diff --git a/db/db.go b/db/db.go
index d32ca23..a1d43a0 100644
--- a/db/db.go
+++ b/db/db.go
@@ -8,7 +8,7 @@ import (
)
func NewDB() (*sqlx.DB, error) {
- l := gologger.Get(config.GetConfig().LogLevel).With().Str("context", "db").Logger()
+ l := gologger.Get(config.GetConfig().LogLevel).With().Caller().Logger()
db, err := sqlx.Open("postgres", config.GetConfig().DbUrl)
if err != nil {
diff --git a/go.mod b/go.mod
index 262488c..3904a81 100644
--- a/go.mod
+++ b/go.mod
@@ -1,41 +1,41 @@
module git.devvul.com/asara/well-goknown
-go 1.23.0
+go 1.23.1
require (
git.devvul.com/asara/gologger v0.8.0
- github.com/fiatjaf/eventstore v0.8.1
- github.com/fiatjaf/khatru v0.8.0
+ github.com/fiatjaf/eventstore v0.9.0
+ github.com/fiatjaf/khatru v0.8.1
github.com/jmoiron/sqlx v1.4.0
github.com/lib/pq v1.10.9
- github.com/nbd-wtf/go-nostr v0.34.13
+ github.com/nbd-wtf/go-nostr v0.36.1
)
require (
- github.com/andybalholm/brotli v1.1.0 // indirect
+ github.com/andybalholm/brotli v1.0.5 // indirect
github.com/btcsuite/btcd/btcec/v2 v2.3.4 // indirect
github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0 // indirect
- github.com/decred/dcrd/crypto/blake256 v1.0.1 // indirect
+ github.com/decred/dcrd/crypto/blake256 v1.1.0 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect
- github.com/fasthttp/websocket v1.5.10 // indirect
+ github.com/fasthttp/websocket v1.5.7 // indirect
github.com/gobwas/httphead v0.1.0 // indirect
github.com/gobwas/pool v0.2.1 // indirect
github.com/gobwas/ws v1.4.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
- github.com/klauspost/compress v1.17.9 // indirect
+ github.com/klauspost/compress v1.17.8 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
- github.com/mattn/go-isatty v0.0.20 // indirect
+ github.com/mattn/go-isatty v0.0.19 // indirect
github.com/puzpuzpuz/xsync/v3 v3.4.0 // indirect
- github.com/rs/cors v1.11.1 // indirect
+ github.com/rs/cors v1.7.0 // indirect
github.com/rs/zerolog v1.33.0 // indirect
- github.com/savsgio/gotils v0.0.0-20240704082632-aef3928b8a38 // indirect
+ github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee // indirect
github.com/tidwall/gjson v1.17.3 // indirect
github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.1 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
- github.com/valyala/fasthttp v1.55.0 // indirect
- golang.org/x/exp v0.0.0-20240823005443-9b4947da3948 // indirect
- golang.org/x/net v0.28.0 // indirect
- golang.org/x/sys v0.24.0 // indirect
+ github.com/valyala/fasthttp v1.51.0 // indirect
+ golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 // indirect
+ golang.org/x/net v0.18.0 // indirect
+ golang.org/x/sys v0.25.0 // indirect
)
diff --git a/go.sum b/go.sum
index d5d0510..5ab4889 100644
--- a/go.sum
+++ b/go.sum
@@ -2,8 +2,8 @@ filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
git.devvul.com/asara/gologger v0.8.0 h1:UsBgNr1ZNpDVqVMTNy3KzSV1afqP0vmTiZvKXZ4YoGk=
git.devvul.com/asara/gologger v0.8.0/go.mod h1:APr1DdVYByFfPUGHqHtRMhxphQbj92/vT/t0iM40H/0=
-github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M=
-github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY=
+github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs=
+github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
github.com/btcsuite/btcd/btcec/v2 v2.3.4 h1:3EJjcN70HCu/mwqlUsGK8GcNVyLVxFDlWurTXGPFfiQ=
github.com/btcsuite/btcd/btcec/v2 v2.3.4/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04=
github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0 h1:59Kx4K6lzOW5w6nFlA0v5+lk/6sjybR934QNHSJZPTQ=
@@ -11,16 +11,16 @@ github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0/go.mod h1:7SFka0XMvUgj3hfZtyd
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y=
-github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo=
+github.com/decred/dcrd/crypto/blake256 v1.1.0 h1:zPMNGQCm0g4QTY27fOCorQW7EryeQ/U0x++OzVrdms8=
+github.com/decred/dcrd/crypto/blake256 v1.1.0/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 h1:rpfIENRNNilwHwZeG5+P150SMrnNEcHYvcCuK6dPZSg=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0=
-github.com/fasthttp/websocket v1.5.10 h1:bc7NIGyrg1L6sd5pRzCIbXpro54SZLEluZCu0rOpcN4=
-github.com/fasthttp/websocket v1.5.10/go.mod h1:BwHeuXGWzCW1/BIKUKD3+qfCl+cTdsHu/f243NcAI/Q=
-github.com/fiatjaf/eventstore v0.8.1 h1:51LchQNy0Hpb0YQHwqYR5pKBpfDs/KjySlWCbbz2pkc=
-github.com/fiatjaf/eventstore v0.8.1/go.mod h1:bsp0Ibv0CIcVuFcoM2AEerMWmXRhF8uWXMf+dClhuow=
-github.com/fiatjaf/khatru v0.8.0 h1:hofUi4qbSqkJiKD4rC9EyNdi9obzBvp3ykJOBxuu/h8=
-github.com/fiatjaf/khatru v0.8.0/go.mod h1:jRmqbbIbEH+y0unt3wMUBwqY/btVussqx5SmBoGhXtg=
+github.com/fasthttp/websocket v1.5.7 h1:0a6o2OfeATvtGgoMKleURhLT6JqWPg7fYfWnH4KHau4=
+github.com/fasthttp/websocket v1.5.7/go.mod h1:bC4fxSono9czeXHQUVKxsC0sNjbm7lPJR04GDFqClfU=
+github.com/fiatjaf/eventstore v0.9.0 h1:WsGDVAaRaVaV/J8PdrQDGfzChrL13q+lTO4C44rhu3E=
+github.com/fiatjaf/eventstore v0.9.0/go.mod h1:JrAce5h0wi79+Sw4gsEq5kz0NtUxbVkOZ7lAo7ay6R8=
+github.com/fiatjaf/khatru v0.8.1 h1:BWAZqwuT0272ZlyzPkuqAA0eGBOs5G3u0Dn1tlWrm6Q=
+github.com/fiatjaf/khatru v0.8.1/go.mod h1:jRmqbbIbEH+y0unt3wMUBwqY/btVussqx5SmBoGhXtg=
github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU=
@@ -34,8 +34,8 @@ github.com/jmoiron/sqlx v1.4.0 h1:1PLqN7S1UYp5t4SrVVnt4nUVNemrDAtxlulVe+Qgm3o=
github.com/jmoiron/sqlx v1.4.0/go.mod h1:ZrZ7UsYB/weZdl2Bxg6jCRO9c3YHl8r3ahlKmRT4JLY=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
-github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
-github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
+github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU=
+github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
@@ -43,25 +43,24 @@ github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJ
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
+github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
-github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
-github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
-github.com/nbd-wtf/go-nostr v0.34.13 h1:2U9zk+B7Z1BafksqorsIZ4aUtTzsgOOB8EJC0fu6ll0=
-github.com/nbd-wtf/go-nostr v0.34.13/go.mod h1:NZQkxl96ggbO8rvDpVjcsojJqKTPwqhP4i82O7K5DJs=
+github.com/nbd-wtf/go-nostr v0.36.1 h1:FdLjHpgXhLfhIjVFpYlQ2AVDUJkpOpXRs3LrkpUh32c=
+github.com/nbd-wtf/go-nostr v0.36.1/go.mod h1:g21TyEpFBmbP7fb8Mc99R1oD76hsyVcQ1rMYCasgU6A=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/puzpuzpuz/xsync/v3 v3.4.0 h1:DuVBAdXuGFHv8adVXjWWZ63pJq+NRXOWVXlKDBZ+mJ4=
github.com/puzpuzpuz/xsync/v3 v3.4.0/go.mod h1:VjzYrABPabuM4KyBh1Ftq6u8nhwY5tBPKP9jpmh0nnA=
-github.com/rs/cors v1.11.1 h1:eU3gRzXLRK57F5rKMGMZURNdIG4EoAmX8k94r9wXWHA=
-github.com/rs/cors v1.11.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU=
+github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik=
+github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8=
github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=
-github.com/savsgio/gotils v0.0.0-20240704082632-aef3928b8a38 h1:D0vL7YNisV2yqE55+q0lFuGse6U8lxlg7fYTctlT5Gc=
-github.com/savsgio/gotils v0.0.0-20240704082632-aef3928b8a38/go.mod h1:sM7Mt7uEoCeFSCBM+qBrqvEo+/9vdmj19wzp3yzUhmg=
+github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee h1:8Iv5m6xEo1NR1AvpV+7XmhI4r39LGNzwUL4YpMuL5vk=
+github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee/go.mod h1:qwtSXrKuJh/zsFQ12yEE89xfCrGKK63Rr7ctU/uCo4g=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/tidwall/gjson v1.17.3 h1:bwWLZU7icoKRG+C+0PNwIKC6FCJO/Q3p2pZvuP0jN94=
@@ -73,16 +72,16 @@ github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4=
github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
-github.com/valyala/fasthttp v1.55.0 h1:Zkefzgt6a7+bVKHnu/YaYSOPfNYNisSVBo/unVCf8k8=
-github.com/valyala/fasthttp v1.55.0/go.mod h1:NkY9JtkrpPKmgwV3HTaS2HWaJss9RSIsRVfcxxoHiOM=
-golang.org/x/exp v0.0.0-20240823005443-9b4947da3948 h1:kx6Ds3MlpiUHKj7syVnbp57++8WpuKPcR5yjLBjvLEA=
-golang.org/x/exp v0.0.0-20240823005443-9b4947da3948/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ=
-golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE=
-golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg=
+github.com/valyala/fasthttp v1.51.0 h1:8b30A5JlZ6C7AS81RsWjYMQmrZG6feChmgAolCl1SqA=
+github.com/valyala/fasthttp v1.51.0/go.mod h1:oI2XroL+lI7vdXyYoQk03bXBThfFl2cVdIA3Xl7cH8g=
+golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 h1:e66Fs6Z+fZTbFBAxKfP3PALWBtpfqks2bwGcexMxgtk=
+golang.org/x/exp v0.0.0-20240909161429-701f63a606c0/go.mod h1:2TbTHSBQa924w8M6Xs1QcRcFwyucIwBGpK1p2f1YFFY=
+golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg=
+golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg=
-golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
+golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/lightningpub/well-known.go b/lightningpub/well-known.go
new file mode 100644
index 0000000..5c441b7
--- /dev/null
+++ b/lightningpub/well-known.go
@@ -0,0 +1,87 @@
+package lightningpub
+
+import (
+ "encoding/json"
+ "fmt"
+ "io/ioutil"
+ "net"
+ "net/http"
+
+ "git.devvul.com/asara/gologger"
+ "git.devvul.com/asara/well-goknown/config"
+ "github.com/jmoiron/sqlx"
+)
+
+var (
+ DB *sqlx.DB
+)
+
+type lnurlp struct {
+ Tag string `json:"tag"`
+ Callback string `json:"callback"`
+ MaxSendable int64 `json:"maxSendable"`
+ MinSendable int64 `json:"minSendable"`
+ Metadata string `json:"metadata"`
+ AllowsNostr bool `json:"allowsNostr"`
+ NostrPubkey string `json:"nostrPubkey"`
+}
+
+func GetLnurlp(w http.ResponseWriter, r *http.Request) {
+ l := gologger.Get(config.GetConfig().LogLevel).With().Caller().Logger()
+
+ // normalize domain
+ domain, _, err := net.SplitHostPort(r.Host)
+ if err != nil {
+ domain = r.Host
+ }
+
+ name := r.PathValue("name")
+ var lnwallet string
+ err = DB.QueryRow("SELECT wallet FROM lnwallets WHERE name=$1 AND domain=$2", name, domain).Scan(&lnwallet)
+ if err != nil {
+ l.Debug().Msgf("user (%s@%s) doesn't exist: %s", name, domain, err.Error())
+ http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
+ return
+ }
+
+ //upstreamUrl := fmt.Sprintf("https://%s/api/guest/lnurl_pay/info?k1=%s", domain, lnwallet)
+ upstreamUrl := fmt.Sprintf("https://%s/api/guest/lnurl_pay/info?k1=%s", domain, lnwallet)
+ upstreamPayload, err := http.Get(upstreamUrl)
+ if err != nil {
+ l.Debug().Msgf("user (%s@%s) doesn't exist: %s", name, domain, err.Error())
+ http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
+ return
+ }
+
+ defer upstreamPayload.Body.Close()
+ body, err := ioutil.ReadAll(upstreamPayload.Body)
+ if err != nil {
+ l.Debug().Msgf("user (%s@%s) doesn't exist: %s", name, domain, err.Error())
+ http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
+ return
+ }
+
+ lnurlpReturn := lnurlp{}
+ err = json.Unmarshal(body, &lnurlpReturn)
+ if err != nil {
+ l.Debug().Msgf("user (%s@%s) doesn't exist: %s", name, domain, err.Error())
+ http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
+ return
+ }
+
+ m := fmt.Sprintf("[[\"text/plain\", \"ln address payment to a user on the devvul server\"],[\"text/identifier\", \"%s@%s\"]]", name, domain)
+ lnurlpReturn.Metadata = m
+
+ ret, err := json.Marshal(lnurlpReturn)
+ if err != nil {
+ l.Debug().Msgf("user (%s@%s) doesn't exist: %s", name, domain, err.Error())
+ http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
+ return
+ }
+
+ l.Debug().Msgf("returning lnwallet for %s@%s", name, domain)
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(http.StatusOK)
+ w.Write(ret)
+ return
+}
diff --git a/main.go b/main.go
index 159f4ab..b0674d0 100644
--- a/main.go
+++ b/main.go
@@ -6,6 +6,7 @@ import (
"git.devvul.com/asara/gologger"
"git.devvul.com/asara/well-goknown/config"
"git.devvul.com/asara/well-goknown/db"
+ "git.devvul.com/asara/well-goknown/lightningpub"
"git.devvul.com/asara/well-goknown/matrix"
"git.devvul.com/asara/well-goknown/nostr"
"github.com/fiatjaf/eventstore/postgresql"
@@ -16,16 +17,16 @@ var (
)
func main() {
- l := gologger.Get(config.GetConfig().LogLevel).With().Str("context", "main").Logger()
+ l := gologger.Get(config.GetConfig().LogLevel).With().Caller().Logger()
db, _ := db.NewDB()
defer db.Close()
+ lightningpub.DB = db
nostr.DB = db
nostr.RelayDb = postgresql.PostgresBackend{DatabaseURL: config.GetConfig().DbUrl}
if err := nostr.RelayDb.Init(); err != nil {
l.Panic().Msgf("unable to connect to relay db: %s", err.Error())
}
-
relay := nostr.NewRelay(Version)
// matrix endpoints
@@ -38,6 +39,10 @@ func main() {
http.HandleFunc("/.well-known/nostr.json", nostr.GetNostrAddr)
http.Handle("/relay", relay)
+ // lnurlp endpoint
+ l.Debug().Msg("enabling lnurlp well-known endpoint")
+ http.HandleFunc("/.well-known/lnurlp/{name}", lightningpub.GetLnurlp)
+
// start server
port := config.GetConfig().ListenAddr
l.Info().Msgf("starting server on %s", port)
diff --git a/matrix/matrix.go b/matrix/matrix.go
index 987311b..08cbffc 100644
--- a/matrix/matrix.go
+++ b/matrix/matrix.go
@@ -32,7 +32,7 @@ type matrixClientWellKnown struct {
}
func MatrixServer(w http.ResponseWriter, req *http.Request) {
- l := gologger.Get(config.GetConfig().LogLevel).With().Str("context", "matrix-server").Logger()
+ l := gologger.Get(config.GetConfig().LogLevel).With().Caller().Logger()
// uses an environment variable for now
wellKnownAddr := fmt.Sprintf("%s:8448", config.GetConfig().MatrixWellKnownAddress)
if wellKnownAddr == "" {
@@ -50,7 +50,7 @@ func MatrixServer(w http.ResponseWriter, req *http.Request) {
}
func MatrixClient(w http.ResponseWriter, req *http.Request) {
- l := gologger.Get(config.GetConfig().LogLevel).With().Str("context", "matrix-client").Logger()
+ l := gologger.Get(config.GetConfig().LogLevel).With().Caller().Logger()
m := &matrixClientWellKnown{}
wellKnownAddr := config.GetConfig().MatrixWellKnownAddress
diff --git a/migrations/000002_lnurl.down.sql b/migrations/000002_lnurl.down.sql
new file mode 100644
index 0000000..045d041
--- /dev/null
+++ b/migrations/000002_lnurl.down.sql
@@ -0,0 +1,5 @@
+BEGIN;
+DROP TRIGGER IF EXISTS update_lnwallets_update_ts on lnwallets;
+DROP FUNCTION IF EXISTS lnwallets_update_ts();
+DROP TABLE IF EXISTS lnwallets;
+COMMIT;
diff --git a/migrations/000002_lnurl.up.sql b/migrations/000002_lnurl.up.sql
new file mode 100644
index 0000000..2515950
--- /dev/null
+++ b/migrations/000002_lnurl.up.sql
@@ -0,0 +1,29 @@
+BEGIN;
+CREATE TABLE IF NOT EXISTS lnwallets (
+ id SERIAL PRIMARY KEY,
+ owner_id INT NOT NULL,
+ name TEXT UNIQUE NOT NULL,
+ domain TEXT NOT NULL,
+ wallet TEXT NOT NULL,
+ create_ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
+ update_ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
+ CONSTRAINT fk_owner FOREIGN KEY(owner_id) REFERENCES users(id),
+ CONSTRAINT ck_name CHECK (name ~ '^[a-z0-9]*$')
+);
+
+CREATE FUNCTION lnwallets_update_ts()
+RETURNS TRIGGER AS $$
+BEGIN
+ NEW.update_ts = now();
+ RETURN NEW;
+END;
+$$ language 'plpgsql';
+
+CREATE TRIGGER update_lnwallets_update_ts
+ BEFORE UPDATE
+ ON
+ lnwallets
+ FOR EACH ROW
+EXECUTE PROCEDURE lnwallets_update_ts();
+
+COMMIT;
diff --git a/nostr/policies.go b/nostr/policies.go
index a774e7e..4730da1 100644
--- a/nostr/policies.go
+++ b/nostr/policies.go
@@ -12,10 +12,10 @@ import (
func RejectUnregisteredNpubs(ctx context.Context, event *nostr.Event) (reject bool, msg string) {
var err error
- l := gologger.Get(config.GetConfig().LogLevel).With().Str("context", "nostr-reject-unregistered").Logger()
+ l := gologger.Get(config.GetConfig().LogLevel).With().Caller().Logger()
- // always allow seals, lightning ephemeral messages, auth messages
- if event.Kind == 13 || event.Kind == 21000 || event.Kind == 22242 || event.Kind == 30078 {
+ // always allow seals, lightning ephemeral messages, auth messages, addressable events
+ if event.Kind == 13 || event.Kind == 21000 || event.Kind == 22242 || event.Kind == 30078 || event.Kind == 1059 {
return false, ""
}
@@ -27,8 +27,8 @@ func RejectUnregisteredNpubs(ctx context.Context, event *nostr.Event) (reject bo
}
npubs := []string{authenticatedUser}
- // add recipients of dms (nip04)/private dms (nip17)/gift wraps (nip59) to npubs list
- if event.Kind == 4 || event.Kind == 14 || event.Kind == 1059 {
+ // add recipients of dms/private dms/gift wraps/signature requests to npubs list
+ if event.Kind == 4 || event.Kind == 14 || event.Kind == 1059 || event.Kind == 24133 {
for _, npub := range event.Tags.GetAll([]string{"p"}) {
npubs = append(npubs, npub.Value())
}
diff --git a/nostr/well-known.go b/nostr/well-known.go
index a3fa9de..15743a8 100644
--- a/nostr/well-known.go
+++ b/nostr/well-known.go
@@ -11,7 +11,7 @@ import (
)
func GetNostrAddr(w http.ResponseWriter, r *http.Request) {
- l := gologger.Get(config.GetConfig().LogLevel).With().Str("context", "nostr").Logger()
+ l := gologger.Get(config.GetConfig().LogLevel).With().Caller().Logger()
// get query string for username
r.ParseForm()
diff --git a/vendor/git.devvul.com/asara/gologger/LICENSE b/vendor/git.devvul.com/asara/gologger/LICENSE
new file mode 100644
index 0000000..d41c0bd
--- /dev/null
+++ b/vendor/git.devvul.com/asara/gologger/LICENSE
@@ -0,0 +1,232 @@
+GNU GENERAL PUBLIC LICENSE
+Version 3, 29 June 2007
+
+Copyright © 2007 Free Software Foundation, Inc.
+
+Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.
+
+Preamble
+
+The GNU General Public License is a free, copyleft license for software and other kinds of works.
+
+The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too.
+
+When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things.
+
+To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others.
+
+For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights.
+
+Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it.
+
+For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions.
+
+Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users.
+
+Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free.
+
+The precise terms and conditions for copying, distribution and modification follow.
+
+TERMS AND CONDITIONS
+
+0. Definitions.
+
+“This License” refers to version 3 of the GNU General Public License.
+
+“Copyright” also means copyright-like laws that apply to other kinds of works, such as semiconductor masks.
+
+“The Program” refers to any copyrightable work licensed under this License. Each licensee is addressed as “you”. “Licensees” and “recipients” may be individuals or organizations.
+
+To “modify” a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a “modified version” of the earlier work or a work “based on” the earlier work.
+
+A “covered work” means either the unmodified Program or a work based on the Program.
+
+To “propagate” a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well.
+
+To “convey” a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying.
+
+An interactive user interface displays “Appropriate Legal Notices” to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion.
+
+1. Source Code.
+The “source code” for a work means the preferred form of the work for making modifications to it. “Object code” means any non-source form of a work.
+
+A “Standard Interface” means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language.
+
+The “System Libraries” of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A “Major Component”, in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it.
+
+The “Corresponding Source” for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work.
+
+The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source.
+
+The Corresponding Source for a work in source code form is that same work.
+
+2. Basic Permissions.
+All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law.
+
+You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you.
+
+Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary.
+
+3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures.
+
+When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures.
+
+4. Conveying Verbatim Copies.
+You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program.
+
+You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee.
+
+5. Conveying Modified Source Versions.
+You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to “keep intact all notices”.
+
+ c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so.
+
+A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an “aggregate” if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate.
+
+6. Conveying Non-Source Forms.
+You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b.
+
+ d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d.
+
+A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work.
+
+A “User Product” is either (1) a “consumer product”, which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, “normally used” refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product.
+
+“Installation Information” for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made.
+
+If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM).
+
+The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network.
+
+Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying.
+
+7. Additional Terms.
+“Additional permissions” are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions.
+
+When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission.
+
+Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors.
+
+All other non-permissive additional terms are considered “further restrictions” within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying.
+
+If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms.
+
+Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way.
+
+8. Termination.
+You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11).
+
+However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation.
+
+Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice.
+
+Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10.
+
+9. Acceptance Not Required for Having Copies.
+You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so.
+
+10. Automatic Licensing of Downstream Recipients.
+Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License.
+
+An “entity transaction” is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts.
+
+You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it.
+
+11. Patents.
+A “contributor” is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's “contributor version”.
+
+A contributor's “essential patent claims” are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, “control” includes the right to grant patent sublicenses in a manner consistent with the requirements of this License.
+
+Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version.
+
+In the following three paragraphs, a “patent license” is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To “grant” such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party.
+
+If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. “Knowingly relying” means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid.
+
+If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it.
+
+A patent license is “discriminatory” if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007.
+
+Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law.
+
+12. No Surrender of Others' Freedom.
+If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program.
+
+13. Use with the GNU Affero General Public License.
+Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such.
+
+14. Revised Versions of this License.
+The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License “or any later version” applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation.
+
+If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program.
+
+Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version.
+
+15. Disclaimer of Warranty.
+THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM “AS IS” WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+16. Limitation of Liability.
+IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+
+17. Interpretation of Sections 15 and 16.
+If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee.
+
+END OF TERMS AND CONDITIONS
+
+How to Apply These Terms to Your New Programs
+
+If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms.
+
+To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the “copyright” line and a pointer to where the full notice is found.
+
+
+ Copyright (C)
+
+ This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with this program. If not, see .
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode:
+
+ Copyright (C)
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an “about box”.
+
+You should also get your employer (if you work as a programmer) or school, if any, to sign a “copyright disclaimer” for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see .
+
+The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read .
diff --git a/vendor/git.devvul.com/asara/gologger/README.md b/vendor/git.devvul.com/asara/gologger/README.md
new file mode 100644
index 0000000..0bcd74f
--- /dev/null
+++ b/vendor/git.devvul.com/asara/gologger/README.md
@@ -0,0 +1,2 @@
+# go-logger
+
diff --git a/vendor/git.devvul.com/asara/gologger/gologger.go b/vendor/git.devvul.com/asara/gologger/gologger.go
new file mode 100644
index 0000000..b1fee6f
--- /dev/null
+++ b/vendor/git.devvul.com/asara/gologger/gologger.go
@@ -0,0 +1,37 @@
+package gologger
+
+import (
+ "io"
+ "os"
+ "sync"
+ "time"
+
+ "github.com/rs/zerolog"
+)
+
+var once sync.Once
+
+var log zerolog.Logger
+
+func Get(l string) zerolog.Logger {
+ once.Do(func() {
+ zerolog.TimeFieldFormat = time.RFC3339Nano
+
+ var output io.Writer = zerolog.ConsoleWriter{
+ Out: os.Stdout,
+ TimeFormat: time.RFC3339,
+ }
+ level, err := zerolog.ParseLevel(l)
+ if err != nil {
+ panic("unable to get parse level for logger")
+ }
+
+ log = zerolog.New(output).
+ Level(zerolog.Level(level)).
+ With().
+ Timestamp().
+ Logger()
+ })
+
+ return log
+}
diff --git a/vendor/github.com/andybalholm/brotli/LICENSE b/vendor/github.com/andybalholm/brotli/LICENSE
new file mode 100644
index 0000000..33b7cdd
--- /dev/null
+++ b/vendor/github.com/andybalholm/brotli/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors.
+
+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/andybalholm/brotli/README.md b/vendor/github.com/andybalholm/brotli/README.md
new file mode 100644
index 0000000..1ea7fdb
--- /dev/null
+++ b/vendor/github.com/andybalholm/brotli/README.md
@@ -0,0 +1,7 @@
+This package is a brotli compressor and decompressor implemented in Go.
+It was translated from the reference implementation (https://github.com/google/brotli)
+with the `c2go` tool at https://github.com/andybalholm/c2go.
+
+I am using it in production with https://github.com/andybalholm/redwood.
+
+API documentation is found at https://pkg.go.dev/github.com/andybalholm/brotli?tab=doc.
diff --git a/vendor/github.com/andybalholm/brotli/backward_references.go b/vendor/github.com/andybalholm/brotli/backward_references.go
new file mode 100644
index 0000000..008c054
--- /dev/null
+++ b/vendor/github.com/andybalholm/brotli/backward_references.go
@@ -0,0 +1,185 @@
+package brotli
+
+import (
+ "sync"
+)
+
+/* Copyright 2013 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Function to find backward reference copies. */
+
+func computeDistanceCode(distance uint, max_distance uint, dist_cache []int) uint {
+ if distance <= max_distance {
+ var distance_plus_3 uint = distance + 3
+ var offset0 uint = distance_plus_3 - uint(dist_cache[0])
+ var offset1 uint = distance_plus_3 - uint(dist_cache[1])
+ if distance == uint(dist_cache[0]) {
+ return 0
+ } else if distance == uint(dist_cache[1]) {
+ return 1
+ } else if offset0 < 7 {
+ return (0x9750468 >> (4 * offset0)) & 0xF
+ } else if offset1 < 7 {
+ return (0xFDB1ACE >> (4 * offset1)) & 0xF
+ } else if distance == uint(dist_cache[2]) {
+ return 2
+ } else if distance == uint(dist_cache[3]) {
+ return 3
+ }
+ }
+
+ return distance + numDistanceShortCodes - 1
+}
+
+var hasherSearchResultPool sync.Pool
+
+func createBackwardReferences(num_bytes uint, position uint, ringbuffer []byte, ringbuffer_mask uint, params *encoderParams, hasher hasherHandle, dist_cache []int, last_insert_len *uint, commands *[]command, num_literals *uint) {
+ var max_backward_limit uint = maxBackwardLimit(params.lgwin)
+ var insert_length uint = *last_insert_len
+ var pos_end uint = position + num_bytes
+ var store_end uint
+ if num_bytes >= hasher.StoreLookahead() {
+ store_end = position + num_bytes - hasher.StoreLookahead() + 1
+ } else {
+ store_end = position
+ }
+ var random_heuristics_window_size uint = literalSpreeLengthForSparseSearch(params)
+ var apply_random_heuristics uint = position + random_heuristics_window_size
+ var gap uint = 0
+ /* Set maximum distance, see section 9.1. of the spec. */
+
+ const kMinScore uint = scoreBase + 100
+
+ /* For speed up heuristics for random data. */
+
+ /* Minimum score to accept a backward reference. */
+ hasher.PrepareDistanceCache(dist_cache)
+ sr2, _ := hasherSearchResultPool.Get().(*hasherSearchResult)
+ if sr2 == nil {
+ sr2 = &hasherSearchResult{}
+ }
+ sr, _ := hasherSearchResultPool.Get().(*hasherSearchResult)
+ if sr == nil {
+ sr = &hasherSearchResult{}
+ }
+
+ for position+hasher.HashTypeLength() < pos_end {
+ var max_length uint = pos_end - position
+ var max_distance uint = brotli_min_size_t(position, max_backward_limit)
+ sr.len = 0
+ sr.len_code_delta = 0
+ sr.distance = 0
+ sr.score = kMinScore
+ hasher.FindLongestMatch(¶ms.dictionary, ringbuffer, ringbuffer_mask, dist_cache, position, max_length, max_distance, gap, params.dist.max_distance, sr)
+ if sr.score > kMinScore {
+ /* Found a match. Let's look for something even better ahead. */
+ var delayed_backward_references_in_row int = 0
+ max_length--
+ for ; ; max_length-- {
+ var cost_diff_lazy uint = 175
+ if params.quality < minQualityForExtensiveReferenceSearch {
+ sr2.len = brotli_min_size_t(sr.len-1, max_length)
+ } else {
+ sr2.len = 0
+ }
+ sr2.len_code_delta = 0
+ sr2.distance = 0
+ sr2.score = kMinScore
+ max_distance = brotli_min_size_t(position+1, max_backward_limit)
+ hasher.FindLongestMatch(¶ms.dictionary, ringbuffer, ringbuffer_mask, dist_cache, position+1, max_length, max_distance, gap, params.dist.max_distance, sr2)
+ if sr2.score >= sr.score+cost_diff_lazy {
+ /* Ok, let's just write one byte for now and start a match from the
+ next byte. */
+ position++
+
+ insert_length++
+ *sr = *sr2
+ delayed_backward_references_in_row++
+ if delayed_backward_references_in_row < 4 && position+hasher.HashTypeLength() < pos_end {
+ continue
+ }
+ }
+
+ break
+ }
+
+ apply_random_heuristics = position + 2*sr.len + random_heuristics_window_size
+ max_distance = brotli_min_size_t(position, max_backward_limit)
+ {
+ /* The first 16 codes are special short-codes,
+ and the minimum offset is 1. */
+ var distance_code uint = computeDistanceCode(sr.distance, max_distance+gap, dist_cache)
+ if (sr.distance <= (max_distance + gap)) && distance_code > 0 {
+ dist_cache[3] = dist_cache[2]
+ dist_cache[2] = dist_cache[1]
+ dist_cache[1] = dist_cache[0]
+ dist_cache[0] = int(sr.distance)
+ hasher.PrepareDistanceCache(dist_cache)
+ }
+
+ *commands = append(*commands, makeCommand(¶ms.dist, insert_length, sr.len, sr.len_code_delta, distance_code))
+ }
+
+ *num_literals += insert_length
+ insert_length = 0
+ /* Put the hash keys into the table, if there are enough bytes left.
+ Depending on the hasher implementation, it can push all positions
+ in the given range or only a subset of them.
+ Avoid hash poisoning with RLE data. */
+ {
+ var range_start uint = position + 2
+ var range_end uint = brotli_min_size_t(position+sr.len, store_end)
+ if sr.distance < sr.len>>2 {
+ range_start = brotli_min_size_t(range_end, brotli_max_size_t(range_start, position+sr.len-(sr.distance<<2)))
+ }
+
+ hasher.StoreRange(ringbuffer, ringbuffer_mask, range_start, range_end)
+ }
+
+ position += sr.len
+ } else {
+ insert_length++
+ position++
+
+ /* If we have not seen matches for a long time, we can skip some
+ match lookups. Unsuccessful match lookups are very very expensive
+ and this kind of a heuristic speeds up compression quite
+ a lot. */
+ if position > apply_random_heuristics {
+ /* Going through uncompressible data, jump. */
+ if position > apply_random_heuristics+4*random_heuristics_window_size {
+ var kMargin uint = brotli_max_size_t(hasher.StoreLookahead()-1, 4)
+ /* It is quite a long time since we saw a copy, so we assume
+ that this data is not compressible, and store hashes less
+ often. Hashes of non compressible data are less likely to
+ turn out to be useful in the future, too, so we store less of
+ them to not to flood out the hash table of good compressible
+ data. */
+
+ var pos_jump uint = brotli_min_size_t(position+16, pos_end-kMargin)
+ for ; position < pos_jump; position += 4 {
+ hasher.Store(ringbuffer, ringbuffer_mask, position)
+ insert_length += 4
+ }
+ } else {
+ var kMargin uint = brotli_max_size_t(hasher.StoreLookahead()-1, 2)
+ var pos_jump uint = brotli_min_size_t(position+8, pos_end-kMargin)
+ for ; position < pos_jump; position += 2 {
+ hasher.Store(ringbuffer, ringbuffer_mask, position)
+ insert_length += 2
+ }
+ }
+ }
+ }
+ }
+
+ insert_length += pos_end - position
+ *last_insert_len = insert_length
+
+ hasherSearchResultPool.Put(sr)
+ hasherSearchResultPool.Put(sr2)
+}
diff --git a/vendor/github.com/andybalholm/brotli/backward_references_hq.go b/vendor/github.com/andybalholm/brotli/backward_references_hq.go
new file mode 100644
index 0000000..21629c1
--- /dev/null
+++ b/vendor/github.com/andybalholm/brotli/backward_references_hq.go
@@ -0,0 +1,796 @@
+package brotli
+
+import "math"
+
+type zopfliNode struct {
+ length uint32
+ distance uint32
+ dcode_insert_length uint32
+ u struct {
+ cost float32
+ next uint32
+ shortcut uint32
+ }
+}
+
+const maxEffectiveDistanceAlphabetSize = 544
+
+const kInfinity float32 = 1.7e38 /* ~= 2 ^ 127 */
+
+var kDistanceCacheIndex = []uint32{0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1}
+
+var kDistanceCacheOffset = []int{0, 0, 0, 0, -1, 1, -2, 2, -3, 3, -1, 1, -2, 2, -3, 3}
+
+func initZopfliNodes(array []zopfliNode, length uint) {
+ var stub zopfliNode
+ var i uint
+ stub.length = 1
+ stub.distance = 0
+ stub.dcode_insert_length = 0
+ stub.u.cost = kInfinity
+ for i = 0; i < length; i++ {
+ array[i] = stub
+ }
+}
+
+func zopfliNodeCopyLength(self *zopfliNode) uint32 {
+ return self.length & 0x1FFFFFF
+}
+
+func zopfliNodeLengthCode(self *zopfliNode) uint32 {
+ var modifier uint32 = self.length >> 25
+ return zopfliNodeCopyLength(self) + 9 - modifier
+}
+
+func zopfliNodeCopyDistance(self *zopfliNode) uint32 {
+ return self.distance
+}
+
+func zopfliNodeDistanceCode(self *zopfliNode) uint32 {
+ var short_code uint32 = self.dcode_insert_length >> 27
+ if short_code == 0 {
+ return zopfliNodeCopyDistance(self) + numDistanceShortCodes - 1
+ } else {
+ return short_code - 1
+ }
+}
+
+func zopfliNodeCommandLength(self *zopfliNode) uint32 {
+ return zopfliNodeCopyLength(self) + (self.dcode_insert_length & 0x7FFFFFF)
+}
+
+/* Histogram based cost model for zopflification. */
+type zopfliCostModel struct {
+ cost_cmd_ [numCommandSymbols]float32
+ cost_dist_ []float32
+ distance_histogram_size uint32
+ literal_costs_ []float32
+ min_cost_cmd_ float32
+ num_bytes_ uint
+}
+
+func initZopfliCostModel(self *zopfliCostModel, dist *distanceParams, num_bytes uint) {
+ var distance_histogram_size uint32 = dist.alphabet_size
+ if distance_histogram_size > maxEffectiveDistanceAlphabetSize {
+ distance_histogram_size = maxEffectiveDistanceAlphabetSize
+ }
+
+ self.num_bytes_ = num_bytes
+ self.literal_costs_ = make([]float32, (num_bytes + 2))
+ self.cost_dist_ = make([]float32, (dist.alphabet_size))
+ self.distance_histogram_size = distance_histogram_size
+}
+
+func cleanupZopfliCostModel(self *zopfliCostModel) {
+ self.literal_costs_ = nil
+ self.cost_dist_ = nil
+}
+
+func setCost(histogram []uint32, histogram_size uint, literal_histogram bool, cost []float32) {
+ var sum uint = 0
+ var missing_symbol_sum uint
+ var log2sum float32
+ var missing_symbol_cost float32
+ var i uint
+ for i = 0; i < histogram_size; i++ {
+ sum += uint(histogram[i])
+ }
+
+ log2sum = float32(fastLog2(sum))
+ missing_symbol_sum = sum
+ if !literal_histogram {
+ for i = 0; i < histogram_size; i++ {
+ if histogram[i] == 0 {
+ missing_symbol_sum++
+ }
+ }
+ }
+
+ missing_symbol_cost = float32(fastLog2(missing_symbol_sum)) + 2
+ for i = 0; i < histogram_size; i++ {
+ if histogram[i] == 0 {
+ cost[i] = missing_symbol_cost
+ continue
+ }
+
+ /* Shannon bits for this symbol. */
+ cost[i] = log2sum - float32(fastLog2(uint(histogram[i])))
+
+ /* Cannot be coded with less than 1 bit */
+ if cost[i] < 1 {
+ cost[i] = 1
+ }
+ }
+}
+
+func zopfliCostModelSetFromCommands(self *zopfliCostModel, position uint, ringbuffer []byte, ringbuffer_mask uint, commands []command, last_insert_len uint) {
+ var histogram_literal [numLiteralSymbols]uint32
+ var histogram_cmd [numCommandSymbols]uint32
+ var histogram_dist [maxEffectiveDistanceAlphabetSize]uint32
+ var cost_literal [numLiteralSymbols]float32
+ var pos uint = position - last_insert_len
+ var min_cost_cmd float32 = kInfinity
+ var cost_cmd []float32 = self.cost_cmd_[:]
+ var literal_costs []float32
+
+ histogram_literal = [numLiteralSymbols]uint32{}
+ histogram_cmd = [numCommandSymbols]uint32{}
+ histogram_dist = [maxEffectiveDistanceAlphabetSize]uint32{}
+
+ for i := range commands {
+ var inslength uint = uint(commands[i].insert_len_)
+ var copylength uint = uint(commandCopyLen(&commands[i]))
+ var distcode uint = uint(commands[i].dist_prefix_) & 0x3FF
+ var cmdcode uint = uint(commands[i].cmd_prefix_)
+ var j uint
+
+ histogram_cmd[cmdcode]++
+ if cmdcode >= 128 {
+ histogram_dist[distcode]++
+ }
+
+ for j = 0; j < inslength; j++ {
+ histogram_literal[ringbuffer[(pos+j)&ringbuffer_mask]]++
+ }
+
+ pos += inslength + copylength
+ }
+
+ setCost(histogram_literal[:], numLiteralSymbols, true, cost_literal[:])
+ setCost(histogram_cmd[:], numCommandSymbols, false, cost_cmd)
+ setCost(histogram_dist[:], uint(self.distance_histogram_size), false, self.cost_dist_)
+
+ for i := 0; i < numCommandSymbols; i++ {
+ min_cost_cmd = brotli_min_float(min_cost_cmd, cost_cmd[i])
+ }
+
+ self.min_cost_cmd_ = min_cost_cmd
+ {
+ literal_costs = self.literal_costs_
+ var literal_carry float32 = 0.0
+ num_bytes := int(self.num_bytes_)
+ literal_costs[0] = 0.0
+ for i := 0; i < num_bytes; i++ {
+ literal_carry += cost_literal[ringbuffer[(position+uint(i))&ringbuffer_mask]]
+ literal_costs[i+1] = literal_costs[i] + literal_carry
+ literal_carry -= literal_costs[i+1] - literal_costs[i]
+ }
+ }
+}
+
+func zopfliCostModelSetFromLiteralCosts(self *zopfliCostModel, position uint, ringbuffer []byte, ringbuffer_mask uint) {
+ var literal_costs []float32 = self.literal_costs_
+ var literal_carry float32 = 0.0
+ var cost_dist []float32 = self.cost_dist_
+ var cost_cmd []float32 = self.cost_cmd_[:]
+ var num_bytes uint = self.num_bytes_
+ var i uint
+ estimateBitCostsForLiterals(position, num_bytes, ringbuffer_mask, ringbuffer, literal_costs[1:])
+ literal_costs[0] = 0.0
+ for i = 0; i < num_bytes; i++ {
+ literal_carry += literal_costs[i+1]
+ literal_costs[i+1] = literal_costs[i] + literal_carry
+ literal_carry -= literal_costs[i+1] - literal_costs[i]
+ }
+
+ for i = 0; i < numCommandSymbols; i++ {
+ cost_cmd[i] = float32(fastLog2(uint(11 + uint32(i))))
+ }
+
+ for i = 0; uint32(i) < self.distance_histogram_size; i++ {
+ cost_dist[i] = float32(fastLog2(uint(20 + uint32(i))))
+ }
+
+ self.min_cost_cmd_ = float32(fastLog2(11))
+}
+
+func zopfliCostModelGetCommandCost(self *zopfliCostModel, cmdcode uint16) float32 {
+ return self.cost_cmd_[cmdcode]
+}
+
+func zopfliCostModelGetDistanceCost(self *zopfliCostModel, distcode uint) float32 {
+ return self.cost_dist_[distcode]
+}
+
+func zopfliCostModelGetLiteralCosts(self *zopfliCostModel, from uint, to uint) float32 {
+ return self.literal_costs_[to] - self.literal_costs_[from]
+}
+
+func zopfliCostModelGetMinCostCmd(self *zopfliCostModel) float32 {
+ return self.min_cost_cmd_
+}
+
+/* REQUIRES: len >= 2, start_pos <= pos */
+/* REQUIRES: cost < kInfinity, nodes[start_pos].cost < kInfinity */
+/* Maintains the "ZopfliNode array invariant". */
+func updateZopfliNode(nodes []zopfliNode, pos uint, start_pos uint, len uint, len_code uint, dist uint, short_code uint, cost float32) {
+ var next *zopfliNode = &nodes[pos+len]
+ next.length = uint32(len | (len+9-len_code)<<25)
+ next.distance = uint32(dist)
+ next.dcode_insert_length = uint32(short_code<<27 | (pos - start_pos))
+ next.u.cost = cost
+}
+
+type posData struct {
+ pos uint
+ distance_cache [4]int
+ costdiff float32
+ cost float32
+}
+
+/* Maintains the smallest 8 cost difference together with their positions */
+type startPosQueue struct {
+ q_ [8]posData
+ idx_ uint
+}
+
+func initStartPosQueue(self *startPosQueue) {
+ self.idx_ = 0
+}
+
+func startPosQueueSize(self *startPosQueue) uint {
+ return brotli_min_size_t(self.idx_, 8)
+}
+
+func startPosQueuePush(self *startPosQueue, posdata *posData) {
+ var offset uint = ^(self.idx_) & 7
+ self.idx_++
+ var len uint = startPosQueueSize(self)
+ var i uint
+ var q []posData = self.q_[:]
+ q[offset] = *posdata
+
+ /* Restore the sorted order. In the list of |len| items at most |len - 1|
+ adjacent element comparisons / swaps are required. */
+ for i = 1; i < len; i++ {
+ if q[offset&7].costdiff > q[(offset+1)&7].costdiff {
+ var tmp posData = q[offset&7]
+ q[offset&7] = q[(offset+1)&7]
+ q[(offset+1)&7] = tmp
+ }
+
+ offset++
+ }
+}
+
+func startPosQueueAt(self *startPosQueue, k uint) *posData {
+ return &self.q_[(k-self.idx_)&7]
+}
+
+/* Returns the minimum possible copy length that can improve the cost of any */
+/* future position. */
+func computeMinimumCopyLength(start_cost float32, nodes []zopfliNode, num_bytes uint, pos uint) uint {
+ var min_cost float32 = start_cost
+ var len uint = 2
+ var next_len_bucket uint = 4
+ /* Compute the minimum possible cost of reaching any future position. */
+
+ var next_len_offset uint = 10
+ for pos+len <= num_bytes && nodes[pos+len].u.cost <= min_cost {
+ /* We already reached (pos + len) with no more cost than the minimum
+ possible cost of reaching anything from this pos, so there is no point in
+ looking for lengths <= len. */
+ len++
+
+ if len == next_len_offset {
+ /* We reached the next copy length code bucket, so we add one more
+ extra bit to the minimum cost. */
+ min_cost += 1.0
+
+ next_len_offset += next_len_bucket
+ next_len_bucket *= 2
+ }
+ }
+
+ return uint(len)
+}
+
+/* REQUIRES: nodes[pos].cost < kInfinity
+ REQUIRES: nodes[0..pos] satisfies that "ZopfliNode array invariant". */
+func computeDistanceShortcut(block_start uint, pos uint, max_backward_limit uint, gap uint, nodes []zopfliNode) uint32 {
+ var clen uint = uint(zopfliNodeCopyLength(&nodes[pos]))
+ var ilen uint = uint(nodes[pos].dcode_insert_length & 0x7FFFFFF)
+ var dist uint = uint(zopfliNodeCopyDistance(&nodes[pos]))
+
+ /* Since |block_start + pos| is the end position of the command, the copy part
+ starts from |block_start + pos - clen|. Distances that are greater than
+ this or greater than |max_backward_limit| + |gap| are static dictionary
+ references, and do not update the last distances.
+ Also distance code 0 (last distance) does not update the last distances. */
+ if pos == 0 {
+ return 0
+ } else if dist+clen <= block_start+pos+gap && dist <= max_backward_limit+gap && zopfliNodeDistanceCode(&nodes[pos]) > 0 {
+ return uint32(pos)
+ } else {
+ return nodes[pos-clen-ilen].u.shortcut
+ }
+}
+
+/* Fills in dist_cache[0..3] with the last four distances (as defined by
+ Section 4. of the Spec) that would be used at (block_start + pos) if we
+ used the shortest path of commands from block_start, computed from
+ nodes[0..pos]. The last four distances at block_start are in
+ starting_dist_cache[0..3].
+ REQUIRES: nodes[pos].cost < kInfinity
+ REQUIRES: nodes[0..pos] satisfies that "ZopfliNode array invariant". */
+func computeDistanceCache(pos uint, starting_dist_cache []int, nodes []zopfliNode, dist_cache []int) {
+ var idx int = 0
+ var p uint = uint(nodes[pos].u.shortcut)
+ for idx < 4 && p > 0 {
+ var ilen uint = uint(nodes[p].dcode_insert_length & 0x7FFFFFF)
+ var clen uint = uint(zopfliNodeCopyLength(&nodes[p]))
+ var dist uint = uint(zopfliNodeCopyDistance(&nodes[p]))
+ dist_cache[idx] = int(dist)
+ idx++
+
+ /* Because of prerequisite, p >= clen + ilen >= 2. */
+ p = uint(nodes[p-clen-ilen].u.shortcut)
+ }
+
+ for ; idx < 4; idx++ {
+ dist_cache[idx] = starting_dist_cache[0]
+ starting_dist_cache = starting_dist_cache[1:]
+ }
+}
+
+/* Maintains "ZopfliNode array invariant" and pushes node to the queue, if it
+ is eligible. */
+func evaluateNode(block_start uint, pos uint, max_backward_limit uint, gap uint, starting_dist_cache []int, model *zopfliCostModel, queue *startPosQueue, nodes []zopfliNode) {
+ /* Save cost, because ComputeDistanceCache invalidates it. */
+ var node_cost float32 = nodes[pos].u.cost
+ nodes[pos].u.shortcut = computeDistanceShortcut(block_start, pos, max_backward_limit, gap, nodes)
+ if node_cost <= zopfliCostModelGetLiteralCosts(model, 0, pos) {
+ var posdata posData
+ posdata.pos = pos
+ posdata.cost = node_cost
+ posdata.costdiff = node_cost - zopfliCostModelGetLiteralCosts(model, 0, pos)
+ computeDistanceCache(pos, starting_dist_cache, nodes, posdata.distance_cache[:])
+ startPosQueuePush(queue, &posdata)
+ }
+}
+
+/* Returns longest copy length. */
+func updateNodes(num_bytes uint, block_start uint, pos uint, ringbuffer []byte, ringbuffer_mask uint, params *encoderParams, max_backward_limit uint, starting_dist_cache []int, num_matches uint, matches []backwardMatch, model *zopfliCostModel, queue *startPosQueue, nodes []zopfliNode) uint {
+ var cur_ix uint = block_start + pos
+ var cur_ix_masked uint = cur_ix & ringbuffer_mask
+ var max_distance uint = brotli_min_size_t(cur_ix, max_backward_limit)
+ var max_len uint = num_bytes - pos
+ var max_zopfli_len uint = maxZopfliLen(params)
+ var max_iters uint = maxZopfliCandidates(params)
+ var min_len uint
+ var result uint = 0
+ var k uint
+ var gap uint = 0
+
+ evaluateNode(block_start, pos, max_backward_limit, gap, starting_dist_cache, model, queue, nodes)
+ {
+ var posdata *posData = startPosQueueAt(queue, 0)
+ var min_cost float32 = (posdata.cost + zopfliCostModelGetMinCostCmd(model) + zopfliCostModelGetLiteralCosts(model, posdata.pos, pos))
+ min_len = computeMinimumCopyLength(min_cost, nodes, num_bytes, pos)
+ }
+
+ /* Go over the command starting positions in order of increasing cost
+ difference. */
+ for k = 0; k < max_iters && k < startPosQueueSize(queue); k++ {
+ var posdata *posData = startPosQueueAt(queue, k)
+ var start uint = posdata.pos
+ var inscode uint16 = getInsertLengthCode(pos - start)
+ var start_costdiff float32 = posdata.costdiff
+ var base_cost float32 = start_costdiff + float32(getInsertExtra(inscode)) + zopfliCostModelGetLiteralCosts(model, 0, pos)
+ var best_len uint = min_len - 1
+ var j uint = 0
+ /* Look for last distance matches using the distance cache from this
+ starting position. */
+ for ; j < numDistanceShortCodes && best_len < max_len; j++ {
+ var idx uint = uint(kDistanceCacheIndex[j])
+ var backward uint = uint(posdata.distance_cache[idx] + kDistanceCacheOffset[j])
+ var prev_ix uint = cur_ix - backward
+ var len uint = 0
+ var continuation byte = ringbuffer[cur_ix_masked+best_len]
+ if cur_ix_masked+best_len > ringbuffer_mask {
+ break
+ }
+
+ if backward > max_distance+gap {
+ /* Word dictionary -> ignore. */
+ continue
+ }
+
+ if backward <= max_distance {
+ /* Regular backward reference. */
+ if prev_ix >= cur_ix {
+ continue
+ }
+
+ prev_ix &= ringbuffer_mask
+ if prev_ix+best_len > ringbuffer_mask || continuation != ringbuffer[prev_ix+best_len] {
+ continue
+ }
+
+ len = findMatchLengthWithLimit(ringbuffer[prev_ix:], ringbuffer[cur_ix_masked:], max_len)
+ } else {
+ continue
+ }
+ {
+ var dist_cost float32 = base_cost + zopfliCostModelGetDistanceCost(model, j)
+ var l uint
+ for l = best_len + 1; l <= len; l++ {
+ var copycode uint16 = getCopyLengthCode(l)
+ var cmdcode uint16 = combineLengthCodes(inscode, copycode, j == 0)
+ var tmp float32
+ if cmdcode < 128 {
+ tmp = base_cost
+ } else {
+ tmp = dist_cost
+ }
+ var cost float32 = tmp + float32(getCopyExtra(copycode)) + zopfliCostModelGetCommandCost(model, cmdcode)
+ if cost < nodes[pos+l].u.cost {
+ updateZopfliNode(nodes, pos, start, l, l, backward, j+1, cost)
+ result = brotli_max_size_t(result, l)
+ }
+
+ best_len = l
+ }
+ }
+ }
+
+ /* At higher iterations look only for new last distance matches, since
+ looking only for new command start positions with the same distances
+ does not help much. */
+ if k >= 2 {
+ continue
+ }
+ {
+ /* Loop through all possible copy lengths at this position. */
+ var len uint = min_len
+ for j = 0; j < num_matches; j++ {
+ var match backwardMatch = matches[j]
+ var dist uint = uint(match.distance)
+ var is_dictionary_match bool = (dist > max_distance+gap)
+ var dist_code uint = dist + numDistanceShortCodes - 1
+ var dist_symbol uint16
+ var distextra uint32
+ var distnumextra uint32
+ var dist_cost float32
+ var max_match_len uint
+ /* We already tried all possible last distance matches, so we can use
+ normal distance code here. */
+ prefixEncodeCopyDistance(dist_code, uint(params.dist.num_direct_distance_codes), uint(params.dist.distance_postfix_bits), &dist_symbol, &distextra)
+
+ distnumextra = uint32(dist_symbol) >> 10
+ dist_cost = base_cost + float32(distnumextra) + zopfliCostModelGetDistanceCost(model, uint(dist_symbol)&0x3FF)
+
+ /* Try all copy lengths up until the maximum copy length corresponding
+ to this distance. If the distance refers to the static dictionary, or
+ the maximum length is long enough, try only one maximum length. */
+ max_match_len = backwardMatchLength(&match)
+
+ if len < max_match_len && (is_dictionary_match || max_match_len > max_zopfli_len) {
+ len = max_match_len
+ }
+
+ for ; len <= max_match_len; len++ {
+ var len_code uint
+ if is_dictionary_match {
+ len_code = backwardMatchLengthCode(&match)
+ } else {
+ len_code = len
+ }
+ var copycode uint16 = getCopyLengthCode(len_code)
+ var cmdcode uint16 = combineLengthCodes(inscode, copycode, false)
+ var cost float32 = dist_cost + float32(getCopyExtra(copycode)) + zopfliCostModelGetCommandCost(model, cmdcode)
+ if cost < nodes[pos+len].u.cost {
+ updateZopfliNode(nodes, pos, start, uint(len), len_code, dist, 0, cost)
+ if len > result {
+ result = len
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return result
+}
+
+func computeShortestPathFromNodes(num_bytes uint, nodes []zopfliNode) uint {
+ var index uint = num_bytes
+ var num_commands uint = 0
+ for nodes[index].dcode_insert_length&0x7FFFFFF == 0 && nodes[index].length == 1 {
+ index--
+ }
+ nodes[index].u.next = math.MaxUint32
+ for index != 0 {
+ var len uint = uint(zopfliNodeCommandLength(&nodes[index]))
+ index -= uint(len)
+ nodes[index].u.next = uint32(len)
+ num_commands++
+ }
+
+ return num_commands
+}
+
+/* REQUIRES: nodes != NULL and len(nodes) >= num_bytes + 1 */
+func zopfliCreateCommands(num_bytes uint, block_start uint, nodes []zopfliNode, dist_cache []int, last_insert_len *uint, params *encoderParams, commands *[]command, num_literals *uint) {
+ var max_backward_limit uint = maxBackwardLimit(params.lgwin)
+ var pos uint = 0
+ var offset uint32 = nodes[0].u.next
+ var i uint
+ var gap uint = 0
+ for i = 0; offset != math.MaxUint32; i++ {
+ var next *zopfliNode = &nodes[uint32(pos)+offset]
+ var copy_length uint = uint(zopfliNodeCopyLength(next))
+ var insert_length uint = uint(next.dcode_insert_length & 0x7FFFFFF)
+ pos += insert_length
+ offset = next.u.next
+ if i == 0 {
+ insert_length += *last_insert_len
+ *last_insert_len = 0
+ }
+ {
+ var distance uint = uint(zopfliNodeCopyDistance(next))
+ var len_code uint = uint(zopfliNodeLengthCode(next))
+ var max_distance uint = brotli_min_size_t(block_start+pos, max_backward_limit)
+ var is_dictionary bool = (distance > max_distance+gap)
+ var dist_code uint = uint(zopfliNodeDistanceCode(next))
+ *commands = append(*commands, makeCommand(¶ms.dist, insert_length, copy_length, int(len_code)-int(copy_length), dist_code))
+
+ if !is_dictionary && dist_code > 0 {
+ dist_cache[3] = dist_cache[2]
+ dist_cache[2] = dist_cache[1]
+ dist_cache[1] = dist_cache[0]
+ dist_cache[0] = int(distance)
+ }
+ }
+
+ *num_literals += insert_length
+ pos += copy_length
+ }
+
+ *last_insert_len += num_bytes - pos
+}
+
+func zopfliIterate(num_bytes uint, position uint, ringbuffer []byte, ringbuffer_mask uint, params *encoderParams, gap uint, dist_cache []int, model *zopfliCostModel, num_matches []uint32, matches []backwardMatch, nodes []zopfliNode) uint {
+ var max_backward_limit uint = maxBackwardLimit(params.lgwin)
+ var max_zopfli_len uint = maxZopfliLen(params)
+ var queue startPosQueue
+ var cur_match_pos uint = 0
+ var i uint
+ nodes[0].length = 0
+ nodes[0].u.cost = 0
+ initStartPosQueue(&queue)
+ for i = 0; i+3 < num_bytes; i++ {
+ var skip uint = updateNodes(num_bytes, position, i, ringbuffer, ringbuffer_mask, params, max_backward_limit, dist_cache, uint(num_matches[i]), matches[cur_match_pos:], model, &queue, nodes)
+ if skip < longCopyQuickStep {
+ skip = 0
+ }
+ cur_match_pos += uint(num_matches[i])
+ if num_matches[i] == 1 && backwardMatchLength(&matches[cur_match_pos-1]) > max_zopfli_len {
+ skip = brotli_max_size_t(backwardMatchLength(&matches[cur_match_pos-1]), skip)
+ }
+
+ if skip > 1 {
+ skip--
+ for skip != 0 {
+ i++
+ if i+3 >= num_bytes {
+ break
+ }
+ evaluateNode(position, i, max_backward_limit, gap, dist_cache, model, &queue, nodes)
+ cur_match_pos += uint(num_matches[i])
+ skip--
+ }
+ }
+ }
+
+ return computeShortestPathFromNodes(num_bytes, nodes)
+}
+
+/* Computes the shortest path of commands from position to at most
+ position + num_bytes.
+
+ On return, path->size() is the number of commands found and path[i] is the
+ length of the i-th command (copy length plus insert length).
+ Note that the sum of the lengths of all commands can be less than num_bytes.
+
+ On return, the nodes[0..num_bytes] array will have the following
+ "ZopfliNode array invariant":
+ For each i in [1..num_bytes], if nodes[i].cost < kInfinity, then
+ (1) nodes[i].copy_length() >= 2
+ (2) nodes[i].command_length() <= i and
+ (3) nodes[i - nodes[i].command_length()].cost < kInfinity
+
+ REQUIRES: nodes != nil and len(nodes) >= num_bytes + 1 */
+func zopfliComputeShortestPath(num_bytes uint, position uint, ringbuffer []byte, ringbuffer_mask uint, params *encoderParams, dist_cache []int, hasher *h10, nodes []zopfliNode) uint {
+ var max_backward_limit uint = maxBackwardLimit(params.lgwin)
+ var max_zopfli_len uint = maxZopfliLen(params)
+ var model zopfliCostModel
+ var queue startPosQueue
+ var matches [2 * (maxNumMatchesH10 + 64)]backwardMatch
+ var store_end uint
+ if num_bytes >= hasher.StoreLookahead() {
+ store_end = position + num_bytes - hasher.StoreLookahead() + 1
+ } else {
+ store_end = position
+ }
+ var i uint
+ var gap uint = 0
+ var lz_matches_offset uint = 0
+ nodes[0].length = 0
+ nodes[0].u.cost = 0
+ initZopfliCostModel(&model, ¶ms.dist, num_bytes)
+ zopfliCostModelSetFromLiteralCosts(&model, position, ringbuffer, ringbuffer_mask)
+ initStartPosQueue(&queue)
+ for i = 0; i+hasher.HashTypeLength()-1 < num_bytes; i++ {
+ var pos uint = position + i
+ var max_distance uint = brotli_min_size_t(pos, max_backward_limit)
+ var skip uint
+ var num_matches uint
+ num_matches = findAllMatchesH10(hasher, ¶ms.dictionary, ringbuffer, ringbuffer_mask, pos, num_bytes-i, max_distance, gap, params, matches[lz_matches_offset:])
+ if num_matches > 0 && backwardMatchLength(&matches[num_matches-1]) > max_zopfli_len {
+ matches[0] = matches[num_matches-1]
+ num_matches = 1
+ }
+
+ skip = updateNodes(num_bytes, position, i, ringbuffer, ringbuffer_mask, params, max_backward_limit, dist_cache, num_matches, matches[:], &model, &queue, nodes)
+ if skip < longCopyQuickStep {
+ skip = 0
+ }
+ if num_matches == 1 && backwardMatchLength(&matches[0]) > max_zopfli_len {
+ skip = brotli_max_size_t(backwardMatchLength(&matches[0]), skip)
+ }
+
+ if skip > 1 {
+ /* Add the tail of the copy to the hasher. */
+ hasher.StoreRange(ringbuffer, ringbuffer_mask, pos+1, brotli_min_size_t(pos+skip, store_end))
+
+ skip--
+ for skip != 0 {
+ i++
+ if i+hasher.HashTypeLength()-1 >= num_bytes {
+ break
+ }
+ evaluateNode(position, i, max_backward_limit, gap, dist_cache, &model, &queue, nodes)
+ skip--
+ }
+ }
+ }
+
+ cleanupZopfliCostModel(&model)
+ return computeShortestPathFromNodes(num_bytes, nodes)
+}
+
+func createZopfliBackwardReferences(num_bytes uint, position uint, ringbuffer []byte, ringbuffer_mask uint, params *encoderParams, hasher *h10, dist_cache []int, last_insert_len *uint, commands *[]command, num_literals *uint) {
+ var nodes []zopfliNode
+ nodes = make([]zopfliNode, (num_bytes + 1))
+ initZopfliNodes(nodes, num_bytes+1)
+ zopfliComputeShortestPath(num_bytes, position, ringbuffer, ringbuffer_mask, params, dist_cache, hasher, nodes)
+ zopfliCreateCommands(num_bytes, position, nodes, dist_cache, last_insert_len, params, commands, num_literals)
+ nodes = nil
+}
+
+func createHqZopfliBackwardReferences(num_bytes uint, position uint, ringbuffer []byte, ringbuffer_mask uint, params *encoderParams, hasher hasherHandle, dist_cache []int, last_insert_len *uint, commands *[]command, num_literals *uint) {
+ var max_backward_limit uint = maxBackwardLimit(params.lgwin)
+ var num_matches []uint32 = make([]uint32, num_bytes)
+ var matches_size uint = 4 * num_bytes
+ var store_end uint
+ if num_bytes >= hasher.StoreLookahead() {
+ store_end = position + num_bytes - hasher.StoreLookahead() + 1
+ } else {
+ store_end = position
+ }
+ var cur_match_pos uint = 0
+ var i uint
+ var orig_num_literals uint
+ var orig_last_insert_len uint
+ var orig_dist_cache [4]int
+ var orig_num_commands int
+ var model zopfliCostModel
+ var nodes []zopfliNode
+ var matches []backwardMatch = make([]backwardMatch, matches_size)
+ var gap uint = 0
+ var shadow_matches uint = 0
+ var new_array []backwardMatch
+ for i = 0; i+hasher.HashTypeLength()-1 < num_bytes; i++ {
+ var pos uint = position + i
+ var max_distance uint = brotli_min_size_t(pos, max_backward_limit)
+ var max_length uint = num_bytes - i
+ var num_found_matches uint
+ var cur_match_end uint
+ var j uint
+
+ /* Ensure that we have enough free slots. */
+ if matches_size < cur_match_pos+maxNumMatchesH10+shadow_matches {
+ var new_size uint = matches_size
+ if new_size == 0 {
+ new_size = cur_match_pos + maxNumMatchesH10 + shadow_matches
+ }
+
+ for new_size < cur_match_pos+maxNumMatchesH10+shadow_matches {
+ new_size *= 2
+ }
+
+ new_array = make([]backwardMatch, new_size)
+ if matches_size != 0 {
+ copy(new_array, matches[:matches_size])
+ }
+
+ matches = new_array
+ matches_size = new_size
+ }
+
+ num_found_matches = findAllMatchesH10(hasher.(*h10), ¶ms.dictionary, ringbuffer, ringbuffer_mask, pos, max_length, max_distance, gap, params, matches[cur_match_pos+shadow_matches:])
+ cur_match_end = cur_match_pos + num_found_matches
+ for j = cur_match_pos; j+1 < cur_match_end; j++ {
+ assert(backwardMatchLength(&matches[j]) <= backwardMatchLength(&matches[j+1]))
+ }
+
+ num_matches[i] = uint32(num_found_matches)
+ if num_found_matches > 0 {
+ var match_len uint = backwardMatchLength(&matches[cur_match_end-1])
+ if match_len > maxZopfliLenQuality11 {
+ var skip uint = match_len - 1
+ matches[cur_match_pos] = matches[cur_match_end-1]
+ cur_match_pos++
+ num_matches[i] = 1
+
+ /* Add the tail of the copy to the hasher. */
+ hasher.StoreRange(ringbuffer, ringbuffer_mask, pos+1, brotli_min_size_t(pos+match_len, store_end))
+ var pos uint = i
+ for i := 0; i < int(skip); i++ {
+ num_matches[pos+1:][i] = 0
+ }
+ i += skip
+ } else {
+ cur_match_pos = cur_match_end
+ }
+ }
+ }
+
+ orig_num_literals = *num_literals
+ orig_last_insert_len = *last_insert_len
+ copy(orig_dist_cache[:], dist_cache[:4])
+ orig_num_commands = len(*commands)
+ nodes = make([]zopfliNode, (num_bytes + 1))
+ initZopfliCostModel(&model, ¶ms.dist, num_bytes)
+ for i = 0; i < 2; i++ {
+ initZopfliNodes(nodes, num_bytes+1)
+ if i == 0 {
+ zopfliCostModelSetFromLiteralCosts(&model, position, ringbuffer, ringbuffer_mask)
+ } else {
+ zopfliCostModelSetFromCommands(&model, position, ringbuffer, ringbuffer_mask, (*commands)[orig_num_commands:], orig_last_insert_len)
+ }
+
+ *commands = (*commands)[:orig_num_commands]
+ *num_literals = orig_num_literals
+ *last_insert_len = orig_last_insert_len
+ copy(dist_cache, orig_dist_cache[:4])
+ zopfliIterate(num_bytes, position, ringbuffer, ringbuffer_mask, params, gap, dist_cache, &model, num_matches, matches, nodes)
+ zopfliCreateCommands(num_bytes, position, nodes, dist_cache, last_insert_len, params, commands, num_literals)
+ }
+
+ cleanupZopfliCostModel(&model)
+ nodes = nil
+ matches = nil
+ num_matches = nil
+}
diff --git a/vendor/github.com/andybalholm/brotli/bit_cost.go b/vendor/github.com/andybalholm/brotli/bit_cost.go
new file mode 100644
index 0000000..0005fc1
--- /dev/null
+++ b/vendor/github.com/andybalholm/brotli/bit_cost.go
@@ -0,0 +1,436 @@
+package brotli
+
+/* Copyright 2013 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Functions to estimate the bit cost of Huffman trees. */
+func shannonEntropy(population []uint32, size uint, total *uint) float64 {
+ var sum uint = 0
+ var retval float64 = 0
+ var population_end []uint32 = population[size:]
+ var p uint
+ for -cap(population) < -cap(population_end) {
+ p = uint(population[0])
+ population = population[1:]
+ sum += p
+ retval -= float64(p) * fastLog2(p)
+ }
+
+ if sum != 0 {
+ retval += float64(sum) * fastLog2(sum)
+ }
+ *total = sum
+ return retval
+}
+
+func bitsEntropy(population []uint32, size uint) float64 {
+ var sum uint
+ var retval float64 = shannonEntropy(population, size, &sum)
+ if retval < float64(sum) {
+ /* At least one bit per literal is needed. */
+ retval = float64(sum)
+ }
+
+ return retval
+}
+
+const kOneSymbolHistogramCost float64 = 12
+const kTwoSymbolHistogramCost float64 = 20
+const kThreeSymbolHistogramCost float64 = 28
+const kFourSymbolHistogramCost float64 = 37
+
+func populationCostLiteral(histogram *histogramLiteral) float64 {
+ var data_size uint = histogramDataSizeLiteral()
+ var count int = 0
+ var s [5]uint
+ var bits float64 = 0.0
+ var i uint
+ if histogram.total_count_ == 0 {
+ return kOneSymbolHistogramCost
+ }
+
+ for i = 0; i < data_size; i++ {
+ if histogram.data_[i] > 0 {
+ s[count] = i
+ count++
+ if count > 4 {
+ break
+ }
+ }
+ }
+
+ if count == 1 {
+ return kOneSymbolHistogramCost
+ }
+
+ if count == 2 {
+ return kTwoSymbolHistogramCost + float64(histogram.total_count_)
+ }
+
+ if count == 3 {
+ var histo0 uint32 = histogram.data_[s[0]]
+ var histo1 uint32 = histogram.data_[s[1]]
+ var histo2 uint32 = histogram.data_[s[2]]
+ var histomax uint32 = brotli_max_uint32_t(histo0, brotli_max_uint32_t(histo1, histo2))
+ return kThreeSymbolHistogramCost + 2*(float64(histo0)+float64(histo1)+float64(histo2)) - float64(histomax)
+ }
+
+ if count == 4 {
+ var histo [4]uint32
+ var h23 uint32
+ var histomax uint32
+ for i = 0; i < 4; i++ {
+ histo[i] = histogram.data_[s[i]]
+ }
+
+ /* Sort */
+ for i = 0; i < 4; i++ {
+ var j uint
+ for j = i + 1; j < 4; j++ {
+ if histo[j] > histo[i] {
+ var tmp uint32 = histo[j]
+ histo[j] = histo[i]
+ histo[i] = tmp
+ }
+ }
+ }
+
+ h23 = histo[2] + histo[3]
+ histomax = brotli_max_uint32_t(h23, histo[0])
+ return kFourSymbolHistogramCost + 3*float64(h23) + 2*(float64(histo[0])+float64(histo[1])) - float64(histomax)
+ }
+ {
+ var max_depth uint = 1
+ var depth_histo = [codeLengthCodes]uint32{0}
+ /* In this loop we compute the entropy of the histogram and simultaneously
+ build a simplified histogram of the code length codes where we use the
+ zero repeat code 17, but we don't use the non-zero repeat code 16. */
+
+ var log2total float64 = fastLog2(histogram.total_count_)
+ for i = 0; i < data_size; {
+ if histogram.data_[i] > 0 {
+ var log2p float64 = log2total - fastLog2(uint(histogram.data_[i]))
+ /* Compute -log2(P(symbol)) = -log2(count(symbol)/total_count) =
+ = log2(total_count) - log2(count(symbol)) */
+
+ var depth uint = uint(log2p + 0.5)
+ /* Approximate the bit depth by round(-log2(P(symbol))) */
+ bits += float64(histogram.data_[i]) * log2p
+
+ if depth > 15 {
+ depth = 15
+ }
+
+ if depth > max_depth {
+ max_depth = depth
+ }
+
+ depth_histo[depth]++
+ i++
+ } else {
+ var reps uint32 = 1
+ /* Compute the run length of zeros and add the appropriate number of 0
+ and 17 code length codes to the code length code histogram. */
+
+ var k uint
+ for k = i + 1; k < data_size && histogram.data_[k] == 0; k++ {
+ reps++
+ }
+
+ i += uint(reps)
+ if i == data_size {
+ /* Don't add any cost for the last zero run, since these are encoded
+ only implicitly. */
+ break
+ }
+
+ if reps < 3 {
+ depth_histo[0] += reps
+ } else {
+ reps -= 2
+ for reps > 0 {
+ depth_histo[repeatZeroCodeLength]++
+
+ /* Add the 3 extra bits for the 17 code length code. */
+ bits += 3
+
+ reps >>= 3
+ }
+ }
+ }
+ }
+
+ /* Add the estimated encoding cost of the code length code histogram. */
+ bits += float64(18 + 2*max_depth)
+
+ /* Add the entropy of the code length code histogram. */
+ bits += bitsEntropy(depth_histo[:], codeLengthCodes)
+ }
+
+ return bits
+}
+
+func populationCostCommand(histogram *histogramCommand) float64 {
+ var data_size uint = histogramDataSizeCommand()
+ var count int = 0
+ var s [5]uint
+ var bits float64 = 0.0
+ var i uint
+ if histogram.total_count_ == 0 {
+ return kOneSymbolHistogramCost
+ }
+
+ for i = 0; i < data_size; i++ {
+ if histogram.data_[i] > 0 {
+ s[count] = i
+ count++
+ if count > 4 {
+ break
+ }
+ }
+ }
+
+ if count == 1 {
+ return kOneSymbolHistogramCost
+ }
+
+ if count == 2 {
+ return kTwoSymbolHistogramCost + float64(histogram.total_count_)
+ }
+
+ if count == 3 {
+ var histo0 uint32 = histogram.data_[s[0]]
+ var histo1 uint32 = histogram.data_[s[1]]
+ var histo2 uint32 = histogram.data_[s[2]]
+ var histomax uint32 = brotli_max_uint32_t(histo0, brotli_max_uint32_t(histo1, histo2))
+ return kThreeSymbolHistogramCost + 2*(float64(histo0)+float64(histo1)+float64(histo2)) - float64(histomax)
+ }
+
+ if count == 4 {
+ var histo [4]uint32
+ var h23 uint32
+ var histomax uint32
+ for i = 0; i < 4; i++ {
+ histo[i] = histogram.data_[s[i]]
+ }
+
+ /* Sort */
+ for i = 0; i < 4; i++ {
+ var j uint
+ for j = i + 1; j < 4; j++ {
+ if histo[j] > histo[i] {
+ var tmp uint32 = histo[j]
+ histo[j] = histo[i]
+ histo[i] = tmp
+ }
+ }
+ }
+
+ h23 = histo[2] + histo[3]
+ histomax = brotli_max_uint32_t(h23, histo[0])
+ return kFourSymbolHistogramCost + 3*float64(h23) + 2*(float64(histo[0])+float64(histo[1])) - float64(histomax)
+ }
+ {
+ var max_depth uint = 1
+ var depth_histo = [codeLengthCodes]uint32{0}
+ /* In this loop we compute the entropy of the histogram and simultaneously
+ build a simplified histogram of the code length codes where we use the
+ zero repeat code 17, but we don't use the non-zero repeat code 16. */
+
+ var log2total float64 = fastLog2(histogram.total_count_)
+ for i = 0; i < data_size; {
+ if histogram.data_[i] > 0 {
+ var log2p float64 = log2total - fastLog2(uint(histogram.data_[i]))
+ /* Compute -log2(P(symbol)) = -log2(count(symbol)/total_count) =
+ = log2(total_count) - log2(count(symbol)) */
+
+ var depth uint = uint(log2p + 0.5)
+ /* Approximate the bit depth by round(-log2(P(symbol))) */
+ bits += float64(histogram.data_[i]) * log2p
+
+ if depth > 15 {
+ depth = 15
+ }
+
+ if depth > max_depth {
+ max_depth = depth
+ }
+
+ depth_histo[depth]++
+ i++
+ } else {
+ var reps uint32 = 1
+ /* Compute the run length of zeros and add the appropriate number of 0
+ and 17 code length codes to the code length code histogram. */
+
+ var k uint
+ for k = i + 1; k < data_size && histogram.data_[k] == 0; k++ {
+ reps++
+ }
+
+ i += uint(reps)
+ if i == data_size {
+ /* Don't add any cost for the last zero run, since these are encoded
+ only implicitly. */
+ break
+ }
+
+ if reps < 3 {
+ depth_histo[0] += reps
+ } else {
+ reps -= 2
+ for reps > 0 {
+ depth_histo[repeatZeroCodeLength]++
+
+ /* Add the 3 extra bits for the 17 code length code. */
+ bits += 3
+
+ reps >>= 3
+ }
+ }
+ }
+ }
+
+ /* Add the estimated encoding cost of the code length code histogram. */
+ bits += float64(18 + 2*max_depth)
+
+ /* Add the entropy of the code length code histogram. */
+ bits += bitsEntropy(depth_histo[:], codeLengthCodes)
+ }
+
+ return bits
+}
+
+func populationCostDistance(histogram *histogramDistance) float64 {
+ var data_size uint = histogramDataSizeDistance()
+ var count int = 0
+ var s [5]uint
+ var bits float64 = 0.0
+ var i uint
+ if histogram.total_count_ == 0 {
+ return kOneSymbolHistogramCost
+ }
+
+ for i = 0; i < data_size; i++ {
+ if histogram.data_[i] > 0 {
+ s[count] = i
+ count++
+ if count > 4 {
+ break
+ }
+ }
+ }
+
+ if count == 1 {
+ return kOneSymbolHistogramCost
+ }
+
+ if count == 2 {
+ return kTwoSymbolHistogramCost + float64(histogram.total_count_)
+ }
+
+ if count == 3 {
+ var histo0 uint32 = histogram.data_[s[0]]
+ var histo1 uint32 = histogram.data_[s[1]]
+ var histo2 uint32 = histogram.data_[s[2]]
+ var histomax uint32 = brotli_max_uint32_t(histo0, brotli_max_uint32_t(histo1, histo2))
+ return kThreeSymbolHistogramCost + 2*(float64(histo0)+float64(histo1)+float64(histo2)) - float64(histomax)
+ }
+
+ if count == 4 {
+ var histo [4]uint32
+ var h23 uint32
+ var histomax uint32
+ for i = 0; i < 4; i++ {
+ histo[i] = histogram.data_[s[i]]
+ }
+
+ /* Sort */
+ for i = 0; i < 4; i++ {
+ var j uint
+ for j = i + 1; j < 4; j++ {
+ if histo[j] > histo[i] {
+ var tmp uint32 = histo[j]
+ histo[j] = histo[i]
+ histo[i] = tmp
+ }
+ }
+ }
+
+ h23 = histo[2] + histo[3]
+ histomax = brotli_max_uint32_t(h23, histo[0])
+ return kFourSymbolHistogramCost + 3*float64(h23) + 2*(float64(histo[0])+float64(histo[1])) - float64(histomax)
+ }
+ {
+ var max_depth uint = 1
+ var depth_histo = [codeLengthCodes]uint32{0}
+ /* In this loop we compute the entropy of the histogram and simultaneously
+ build a simplified histogram of the code length codes where we use the
+ zero repeat code 17, but we don't use the non-zero repeat code 16. */
+
+ var log2total float64 = fastLog2(histogram.total_count_)
+ for i = 0; i < data_size; {
+ if histogram.data_[i] > 0 {
+ var log2p float64 = log2total - fastLog2(uint(histogram.data_[i]))
+ /* Compute -log2(P(symbol)) = -log2(count(symbol)/total_count) =
+ = log2(total_count) - log2(count(symbol)) */
+
+ var depth uint = uint(log2p + 0.5)
+ /* Approximate the bit depth by round(-log2(P(symbol))) */
+ bits += float64(histogram.data_[i]) * log2p
+
+ if depth > 15 {
+ depth = 15
+ }
+
+ if depth > max_depth {
+ max_depth = depth
+ }
+
+ depth_histo[depth]++
+ i++
+ } else {
+ var reps uint32 = 1
+ /* Compute the run length of zeros and add the appropriate number of 0
+ and 17 code length codes to the code length code histogram. */
+
+ var k uint
+ for k = i + 1; k < data_size && histogram.data_[k] == 0; k++ {
+ reps++
+ }
+
+ i += uint(reps)
+ if i == data_size {
+ /* Don't add any cost for the last zero run, since these are encoded
+ only implicitly. */
+ break
+ }
+
+ if reps < 3 {
+ depth_histo[0] += reps
+ } else {
+ reps -= 2
+ for reps > 0 {
+ depth_histo[repeatZeroCodeLength]++
+
+ /* Add the 3 extra bits for the 17 code length code. */
+ bits += 3
+
+ reps >>= 3
+ }
+ }
+ }
+ }
+
+ /* Add the estimated encoding cost of the code length code histogram. */
+ bits += float64(18 + 2*max_depth)
+
+ /* Add the entropy of the code length code histogram. */
+ bits += bitsEntropy(depth_histo[:], codeLengthCodes)
+ }
+
+ return bits
+}
diff --git a/vendor/github.com/andybalholm/brotli/bit_reader.go b/vendor/github.com/andybalholm/brotli/bit_reader.go
new file mode 100644
index 0000000..fba8687
--- /dev/null
+++ b/vendor/github.com/andybalholm/brotli/bit_reader.go
@@ -0,0 +1,266 @@
+package brotli
+
+import "encoding/binary"
+
+/* Copyright 2013 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Bit reading helpers */
+
+const shortFillBitWindowRead = (8 >> 1)
+
+var kBitMask = [33]uint32{
+ 0x00000000,
+ 0x00000001,
+ 0x00000003,
+ 0x00000007,
+ 0x0000000F,
+ 0x0000001F,
+ 0x0000003F,
+ 0x0000007F,
+ 0x000000FF,
+ 0x000001FF,
+ 0x000003FF,
+ 0x000007FF,
+ 0x00000FFF,
+ 0x00001FFF,
+ 0x00003FFF,
+ 0x00007FFF,
+ 0x0000FFFF,
+ 0x0001FFFF,
+ 0x0003FFFF,
+ 0x0007FFFF,
+ 0x000FFFFF,
+ 0x001FFFFF,
+ 0x003FFFFF,
+ 0x007FFFFF,
+ 0x00FFFFFF,
+ 0x01FFFFFF,
+ 0x03FFFFFF,
+ 0x07FFFFFF,
+ 0x0FFFFFFF,
+ 0x1FFFFFFF,
+ 0x3FFFFFFF,
+ 0x7FFFFFFF,
+ 0xFFFFFFFF,
+}
+
+func bitMask(n uint32) uint32 {
+ return kBitMask[n]
+}
+
+type bitReader struct {
+ val_ uint64
+ bit_pos_ uint32
+ input []byte
+ input_len uint
+ byte_pos uint
+}
+
+type bitReaderState struct {
+ val_ uint64
+ bit_pos_ uint32
+ input []byte
+ input_len uint
+ byte_pos uint
+}
+
+/* Initializes the BrotliBitReader fields. */
+
+/* Ensures that accumulator is not empty.
+ May consume up to sizeof(brotli_reg_t) - 1 bytes of input.
+ Returns false if data is required but there is no input available.
+ For BROTLI_ALIGNED_READ this function also prepares bit reader for aligned
+ reading. */
+func bitReaderSaveState(from *bitReader, to *bitReaderState) {
+ to.val_ = from.val_
+ to.bit_pos_ = from.bit_pos_
+ to.input = from.input
+ to.input_len = from.input_len
+ to.byte_pos = from.byte_pos
+}
+
+func bitReaderRestoreState(to *bitReader, from *bitReaderState) {
+ to.val_ = from.val_
+ to.bit_pos_ = from.bit_pos_
+ to.input = from.input
+ to.input_len = from.input_len
+ to.byte_pos = from.byte_pos
+}
+
+func getAvailableBits(br *bitReader) uint32 {
+ return 64 - br.bit_pos_
+}
+
+/* Returns amount of unread bytes the bit reader still has buffered from the
+ BrotliInput, including whole bytes in br->val_. */
+func getRemainingBytes(br *bitReader) uint {
+ return uint(uint32(br.input_len-br.byte_pos) + (getAvailableBits(br) >> 3))
+}
+
+/* Checks if there is at least |num| bytes left in the input ring-buffer
+ (excluding the bits remaining in br->val_). */
+func checkInputAmount(br *bitReader, num uint) bool {
+ return br.input_len-br.byte_pos >= num
+}
+
+/* Guarantees that there are at least |n_bits| + 1 bits in accumulator.
+ Precondition: accumulator contains at least 1 bit.
+ |n_bits| should be in the range [1..24] for regular build. For portable
+ non-64-bit little-endian build only 16 bits are safe to request. */
+func fillBitWindow(br *bitReader, n_bits uint32) {
+ if br.bit_pos_ >= 32 {
+ br.val_ >>= 32
+ br.bit_pos_ ^= 32 /* here same as -= 32 because of the if condition */
+ br.val_ |= (uint64(binary.LittleEndian.Uint32(br.input[br.byte_pos:]))) << 32
+ br.byte_pos += 4
+ }
+}
+
+/* Mostly like BrotliFillBitWindow, but guarantees only 16 bits and reads no
+ more than BROTLI_SHORT_FILL_BIT_WINDOW_READ bytes of input. */
+func fillBitWindow16(br *bitReader) {
+ fillBitWindow(br, 17)
+}
+
+/* Tries to pull one byte of input to accumulator.
+ Returns false if there is no input available. */
+func pullByte(br *bitReader) bool {
+ if br.byte_pos == br.input_len {
+ return false
+ }
+
+ br.val_ >>= 8
+ br.val_ |= (uint64(br.input[br.byte_pos])) << 56
+ br.bit_pos_ -= 8
+ br.byte_pos++
+ return true
+}
+
+/* Returns currently available bits.
+ The number of valid bits could be calculated by BrotliGetAvailableBits. */
+func getBitsUnmasked(br *bitReader) uint64 {
+ return br.val_ >> br.bit_pos_
+}
+
+/* Like BrotliGetBits, but does not mask the result.
+ The result contains at least 16 valid bits. */
+func get16BitsUnmasked(br *bitReader) uint32 {
+ fillBitWindow(br, 16)
+ return uint32(getBitsUnmasked(br))
+}
+
+/* Returns the specified number of bits from |br| without advancing bit
+ position. */
+func getBits(br *bitReader, n_bits uint32) uint32 {
+ fillBitWindow(br, n_bits)
+ return uint32(getBitsUnmasked(br)) & bitMask(n_bits)
+}
+
+/* Tries to peek the specified amount of bits. Returns false, if there
+ is not enough input. */
+func safeGetBits(br *bitReader, n_bits uint32, val *uint32) bool {
+ for getAvailableBits(br) < n_bits {
+ if !pullByte(br) {
+ return false
+ }
+ }
+
+ *val = uint32(getBitsUnmasked(br)) & bitMask(n_bits)
+ return true
+}
+
+/* Advances the bit pos by |n_bits|. */
+func dropBits(br *bitReader, n_bits uint32) {
+ br.bit_pos_ += n_bits
+}
+
+func bitReaderUnload(br *bitReader) {
+ var unused_bytes uint32 = getAvailableBits(br) >> 3
+ var unused_bits uint32 = unused_bytes << 3
+ br.byte_pos -= uint(unused_bytes)
+ if unused_bits == 64 {
+ br.val_ = 0
+ } else {
+ br.val_ <<= unused_bits
+ }
+
+ br.bit_pos_ += unused_bits
+}
+
+/* Reads the specified number of bits from |br| and advances the bit pos.
+ Precondition: accumulator MUST contain at least |n_bits|. */
+func takeBits(br *bitReader, n_bits uint32, val *uint32) {
+ *val = uint32(getBitsUnmasked(br)) & bitMask(n_bits)
+ dropBits(br, n_bits)
+}
+
+/* Reads the specified number of bits from |br| and advances the bit pos.
+ Assumes that there is enough input to perform BrotliFillBitWindow. */
+func readBits(br *bitReader, n_bits uint32) uint32 {
+ var val uint32
+ fillBitWindow(br, n_bits)
+ takeBits(br, n_bits, &val)
+ return val
+}
+
+/* Tries to read the specified amount of bits. Returns false, if there
+ is not enough input. |n_bits| MUST be positive. */
+func safeReadBits(br *bitReader, n_bits uint32, val *uint32) bool {
+ for getAvailableBits(br) < n_bits {
+ if !pullByte(br) {
+ return false
+ }
+ }
+
+ takeBits(br, n_bits, val)
+ return true
+}
+
+/* Advances the bit reader position to the next byte boundary and verifies
+ that any skipped bits are set to zero. */
+func bitReaderJumpToByteBoundary(br *bitReader) bool {
+ var pad_bits_count uint32 = getAvailableBits(br) & 0x7
+ var pad_bits uint32 = 0
+ if pad_bits_count != 0 {
+ takeBits(br, pad_bits_count, &pad_bits)
+ }
+
+ return pad_bits == 0
+}
+
+/* Copies remaining input bytes stored in the bit reader to the output. Value
+ |num| may not be larger than BrotliGetRemainingBytes. The bit reader must be
+ warmed up again after this. */
+func copyBytes(dest []byte, br *bitReader, num uint) {
+ for getAvailableBits(br) >= 8 && num > 0 {
+ dest[0] = byte(getBitsUnmasked(br))
+ dropBits(br, 8)
+ dest = dest[1:]
+ num--
+ }
+
+ copy(dest, br.input[br.byte_pos:][:num])
+ br.byte_pos += num
+}
+
+func initBitReader(br *bitReader) {
+ br.val_ = 0
+ br.bit_pos_ = 64
+}
+
+func warmupBitReader(br *bitReader) bool {
+ /* Fixing alignment after unaligned BrotliFillWindow would result accumulator
+ overflow. If unalignment is caused by BrotliSafeReadBits, then there is
+ enough space in accumulator to fix alignment. */
+ if getAvailableBits(br) == 0 {
+ if !pullByte(br) {
+ return false
+ }
+ }
+
+ return true
+}
diff --git a/vendor/github.com/andybalholm/brotli/block_splitter.go b/vendor/github.com/andybalholm/brotli/block_splitter.go
new file mode 100644
index 0000000..978a131
--- /dev/null
+++ b/vendor/github.com/andybalholm/brotli/block_splitter.go
@@ -0,0 +1,144 @@
+package brotli
+
+/* Copyright 2013 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Block split point selection utilities. */
+
+type blockSplit struct {
+ num_types uint
+ num_blocks uint
+ types []byte
+ lengths []uint32
+ types_alloc_size uint
+ lengths_alloc_size uint
+}
+
+const (
+ kMaxLiteralHistograms uint = 100
+ kMaxCommandHistograms uint = 50
+ kLiteralBlockSwitchCost float64 = 28.1
+ kCommandBlockSwitchCost float64 = 13.5
+ kDistanceBlockSwitchCost float64 = 14.6
+ kLiteralStrideLength uint = 70
+ kCommandStrideLength uint = 40
+ kSymbolsPerLiteralHistogram uint = 544
+ kSymbolsPerCommandHistogram uint = 530
+ kSymbolsPerDistanceHistogram uint = 544
+ kMinLengthForBlockSplitting uint = 128
+ kIterMulForRefining uint = 2
+ kMinItersForRefining uint = 100
+)
+
+func countLiterals(cmds []command) uint {
+ var total_length uint = 0
+ /* Count how many we have. */
+
+ for i := range cmds {
+ total_length += uint(cmds[i].insert_len_)
+ }
+
+ return total_length
+}
+
+func copyLiteralsToByteArray(cmds []command, data []byte, offset uint, mask uint, literals []byte) {
+ var pos uint = 0
+ var from_pos uint = offset & mask
+ for i := range cmds {
+ var insert_len uint = uint(cmds[i].insert_len_)
+ if from_pos+insert_len > mask {
+ var head_size uint = mask + 1 - from_pos
+ copy(literals[pos:], data[from_pos:][:head_size])
+ from_pos = 0
+ pos += head_size
+ insert_len -= head_size
+ }
+
+ if insert_len > 0 {
+ copy(literals[pos:], data[from_pos:][:insert_len])
+ pos += insert_len
+ }
+
+ from_pos = uint((uint32(from_pos+insert_len) + commandCopyLen(&cmds[i])) & uint32(mask))
+ }
+}
+
+func myRand(seed *uint32) uint32 {
+ /* Initial seed should be 7. In this case, loop length is (1 << 29). */
+ *seed *= 16807
+
+ return *seed
+}
+
+func bitCost(count uint) float64 {
+ if count == 0 {
+ return -2.0
+ } else {
+ return fastLog2(count)
+ }
+}
+
+const histogramsPerBatch = 64
+
+const clustersPerBatch = 16
+
+func initBlockSplit(self *blockSplit) {
+ self.num_types = 0
+ self.num_blocks = 0
+ self.types = self.types[:0]
+ self.lengths = self.lengths[:0]
+ self.types_alloc_size = 0
+ self.lengths_alloc_size = 0
+}
+
+func splitBlock(cmds []command, data []byte, pos uint, mask uint, params *encoderParams, literal_split *blockSplit, insert_and_copy_split *blockSplit, dist_split *blockSplit) {
+ {
+ var literals_count uint = countLiterals(cmds)
+ var literals []byte = make([]byte, literals_count)
+
+ /* Create a continuous array of literals. */
+ copyLiteralsToByteArray(cmds, data, pos, mask, literals)
+
+ /* Create the block split on the array of literals.
+ Literal histograms have alphabet size 256. */
+ splitByteVectorLiteral(literals, literals_count, kSymbolsPerLiteralHistogram, kMaxLiteralHistograms, kLiteralStrideLength, kLiteralBlockSwitchCost, params, literal_split)
+
+ literals = nil
+ }
+ {
+ var insert_and_copy_codes []uint16 = make([]uint16, len(cmds))
+ /* Compute prefix codes for commands. */
+
+ for i := range cmds {
+ insert_and_copy_codes[i] = cmds[i].cmd_prefix_
+ }
+
+ /* Create the block split on the array of command prefixes. */
+ splitByteVectorCommand(insert_and_copy_codes, kSymbolsPerCommandHistogram, kMaxCommandHistograms, kCommandStrideLength, kCommandBlockSwitchCost, params, insert_and_copy_split)
+
+ /* TODO: reuse for distances? */
+
+ insert_and_copy_codes = nil
+ }
+ {
+ var distance_prefixes []uint16 = make([]uint16, len(cmds))
+ var j uint = 0
+ /* Create a continuous array of distance prefixes. */
+
+ for i := range cmds {
+ var cmd *command = &cmds[i]
+ if commandCopyLen(cmd) != 0 && cmd.cmd_prefix_ >= 128 {
+ distance_prefixes[j] = cmd.dist_prefix_ & 0x3FF
+ j++
+ }
+ }
+
+ /* Create the block split on the array of distance prefixes. */
+ splitByteVectorDistance(distance_prefixes, j, kSymbolsPerDistanceHistogram, kMaxCommandHistograms, kCommandStrideLength, kDistanceBlockSwitchCost, params, dist_split)
+
+ distance_prefixes = nil
+ }
+}
diff --git a/vendor/github.com/andybalholm/brotli/block_splitter_command.go b/vendor/github.com/andybalholm/brotli/block_splitter_command.go
new file mode 100644
index 0000000..9dec13e
--- /dev/null
+++ b/vendor/github.com/andybalholm/brotli/block_splitter_command.go
@@ -0,0 +1,434 @@
+package brotli
+
+import "math"
+
+/* Copyright 2013 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+func initialEntropyCodesCommand(data []uint16, length uint, stride uint, num_histograms uint, histograms []histogramCommand) {
+ var seed uint32 = 7
+ var block_length uint = length / num_histograms
+ var i uint
+ clearHistogramsCommand(histograms, num_histograms)
+ for i = 0; i < num_histograms; i++ {
+ var pos uint = length * i / num_histograms
+ if i != 0 {
+ pos += uint(myRand(&seed) % uint32(block_length))
+ }
+
+ if pos+stride >= length {
+ pos = length - stride - 1
+ }
+
+ histogramAddVectorCommand(&histograms[i], data[pos:], stride)
+ }
+}
+
+func randomSampleCommand(seed *uint32, data []uint16, length uint, stride uint, sample *histogramCommand) {
+ var pos uint = 0
+ if stride >= length {
+ stride = length
+ } else {
+ pos = uint(myRand(seed) % uint32(length-stride+1))
+ }
+
+ histogramAddVectorCommand(sample, data[pos:], stride)
+}
+
+func refineEntropyCodesCommand(data []uint16, length uint, stride uint, num_histograms uint, histograms []histogramCommand) {
+ var iters uint = kIterMulForRefining*length/stride + kMinItersForRefining
+ var seed uint32 = 7
+ var iter uint
+ iters = ((iters + num_histograms - 1) / num_histograms) * num_histograms
+ for iter = 0; iter < iters; iter++ {
+ var sample histogramCommand
+ histogramClearCommand(&sample)
+ randomSampleCommand(&seed, data, length, stride, &sample)
+ histogramAddHistogramCommand(&histograms[iter%num_histograms], &sample)
+ }
+}
+
+/* Assigns a block id from the range [0, num_histograms) to each data element
+ in data[0..length) and fills in block_id[0..length) with the assigned values.
+ Returns the number of blocks, i.e. one plus the number of block switches. */
+func findBlocksCommand(data []uint16, length uint, block_switch_bitcost float64, num_histograms uint, histograms []histogramCommand, insert_cost []float64, cost []float64, switch_signal []byte, block_id []byte) uint {
+ var data_size uint = histogramDataSizeCommand()
+ var bitmaplen uint = (num_histograms + 7) >> 3
+ var num_blocks uint = 1
+ var i uint
+ var j uint
+ assert(num_histograms <= 256)
+ if num_histograms <= 1 {
+ for i = 0; i < length; i++ {
+ block_id[i] = 0
+ }
+
+ return 1
+ }
+
+ for i := 0; i < int(data_size*num_histograms); i++ {
+ insert_cost[i] = 0
+ }
+ for i = 0; i < num_histograms; i++ {
+ insert_cost[i] = fastLog2(uint(uint32(histograms[i].total_count_)))
+ }
+
+ for i = data_size; i != 0; {
+ i--
+ for j = 0; j < num_histograms; j++ {
+ insert_cost[i*num_histograms+j] = insert_cost[j] - bitCost(uint(histograms[j].data_[i]))
+ }
+ }
+
+ for i := 0; i < int(num_histograms); i++ {
+ cost[i] = 0
+ }
+ for i := 0; i < int(length*bitmaplen); i++ {
+ switch_signal[i] = 0
+ }
+
+ /* After each iteration of this loop, cost[k] will contain the difference
+ between the minimum cost of arriving at the current byte position using
+ entropy code k, and the minimum cost of arriving at the current byte
+ position. This difference is capped at the block switch cost, and if it
+ reaches block switch cost, it means that when we trace back from the last
+ position, we need to switch here. */
+ for i = 0; i < length; i++ {
+ var byte_ix uint = i
+ var ix uint = byte_ix * bitmaplen
+ var insert_cost_ix uint = uint(data[byte_ix]) * num_histograms
+ var min_cost float64 = 1e99
+ var block_switch_cost float64 = block_switch_bitcost
+ var k uint
+ for k = 0; k < num_histograms; k++ {
+ /* We are coding the symbol in data[byte_ix] with entropy code k. */
+ cost[k] += insert_cost[insert_cost_ix+k]
+
+ if cost[k] < min_cost {
+ min_cost = cost[k]
+ block_id[byte_ix] = byte(k)
+ }
+ }
+
+ /* More blocks for the beginning. */
+ if byte_ix < 2000 {
+ block_switch_cost *= 0.77 + 0.07*float64(byte_ix)/2000
+ }
+
+ for k = 0; k < num_histograms; k++ {
+ cost[k] -= min_cost
+ if cost[k] >= block_switch_cost {
+ var mask byte = byte(1 << (k & 7))
+ cost[k] = block_switch_cost
+ assert(k>>3 < bitmaplen)
+ switch_signal[ix+(k>>3)] |= mask
+ /* Trace back from the last position and switch at the marked places. */
+ }
+ }
+ }
+ {
+ var byte_ix uint = length - 1
+ var ix uint = byte_ix * bitmaplen
+ var cur_id byte = block_id[byte_ix]
+ for byte_ix > 0 {
+ var mask byte = byte(1 << (cur_id & 7))
+ assert(uint(cur_id)>>3 < bitmaplen)
+ byte_ix--
+ ix -= bitmaplen
+ if switch_signal[ix+uint(cur_id>>3)]&mask != 0 {
+ if cur_id != block_id[byte_ix] {
+ cur_id = block_id[byte_ix]
+ num_blocks++
+ }
+ }
+
+ block_id[byte_ix] = cur_id
+ }
+ }
+
+ return num_blocks
+}
+
+var remapBlockIdsCommand_kInvalidId uint16 = 256
+
+func remapBlockIdsCommand(block_ids []byte, length uint, new_id []uint16, num_histograms uint) uint {
+ var next_id uint16 = 0
+ var i uint
+ for i = 0; i < num_histograms; i++ {
+ new_id[i] = remapBlockIdsCommand_kInvalidId
+ }
+
+ for i = 0; i < length; i++ {
+ assert(uint(block_ids[i]) < num_histograms)
+ if new_id[block_ids[i]] == remapBlockIdsCommand_kInvalidId {
+ new_id[block_ids[i]] = next_id
+ next_id++
+ }
+ }
+
+ for i = 0; i < length; i++ {
+ block_ids[i] = byte(new_id[block_ids[i]])
+ assert(uint(block_ids[i]) < num_histograms)
+ }
+
+ assert(uint(next_id) <= num_histograms)
+ return uint(next_id)
+}
+
+func buildBlockHistogramsCommand(data []uint16, length uint, block_ids []byte, num_histograms uint, histograms []histogramCommand) {
+ var i uint
+ clearHistogramsCommand(histograms, num_histograms)
+ for i = 0; i < length; i++ {
+ histogramAddCommand(&histograms[block_ids[i]], uint(data[i]))
+ }
+}
+
+var clusterBlocksCommand_kInvalidIndex uint32 = math.MaxUint32
+
+func clusterBlocksCommand(data []uint16, length uint, num_blocks uint, block_ids []byte, split *blockSplit) {
+ var histogram_symbols []uint32 = make([]uint32, num_blocks)
+ var block_lengths []uint32 = make([]uint32, num_blocks)
+ var expected_num_clusters uint = clustersPerBatch * (num_blocks + histogramsPerBatch - 1) / histogramsPerBatch
+ var all_histograms_size uint = 0
+ var all_histograms_capacity uint = expected_num_clusters
+ var all_histograms []histogramCommand = make([]histogramCommand, all_histograms_capacity)
+ var cluster_size_size uint = 0
+ var cluster_size_capacity uint = expected_num_clusters
+ var cluster_size []uint32 = make([]uint32, cluster_size_capacity)
+ var num_clusters uint = 0
+ var histograms []histogramCommand = make([]histogramCommand, brotli_min_size_t(num_blocks, histogramsPerBatch))
+ var max_num_pairs uint = histogramsPerBatch * histogramsPerBatch / 2
+ var pairs_capacity uint = max_num_pairs + 1
+ var pairs []histogramPair = make([]histogramPair, pairs_capacity)
+ var pos uint = 0
+ var clusters []uint32
+ var num_final_clusters uint
+ var new_index []uint32
+ var i uint
+ var sizes = [histogramsPerBatch]uint32{0}
+ var new_clusters = [histogramsPerBatch]uint32{0}
+ var symbols = [histogramsPerBatch]uint32{0}
+ var remap = [histogramsPerBatch]uint32{0}
+
+ for i := 0; i < int(num_blocks); i++ {
+ block_lengths[i] = 0
+ }
+ {
+ var block_idx uint = 0
+ for i = 0; i < length; i++ {
+ assert(block_idx < num_blocks)
+ block_lengths[block_idx]++
+ if i+1 == length || block_ids[i] != block_ids[i+1] {
+ block_idx++
+ }
+ }
+
+ assert(block_idx == num_blocks)
+ }
+
+ for i = 0; i < num_blocks; i += histogramsPerBatch {
+ var num_to_combine uint = brotli_min_size_t(num_blocks-i, histogramsPerBatch)
+ var num_new_clusters uint
+ var j uint
+ for j = 0; j < num_to_combine; j++ {
+ var k uint
+ histogramClearCommand(&histograms[j])
+ for k = 0; uint32(k) < block_lengths[i+j]; k++ {
+ histogramAddCommand(&histograms[j], uint(data[pos]))
+ pos++
+ }
+
+ histograms[j].bit_cost_ = populationCostCommand(&histograms[j])
+ new_clusters[j] = uint32(j)
+ symbols[j] = uint32(j)
+ sizes[j] = 1
+ }
+
+ num_new_clusters = histogramCombineCommand(histograms, sizes[:], symbols[:], new_clusters[:], []histogramPair(pairs), num_to_combine, num_to_combine, histogramsPerBatch, max_num_pairs)
+ if all_histograms_capacity < (all_histograms_size + num_new_clusters) {
+ var _new_size uint
+ if all_histograms_capacity == 0 {
+ _new_size = all_histograms_size + num_new_clusters
+ } else {
+ _new_size = all_histograms_capacity
+ }
+ var new_array []histogramCommand
+ for _new_size < (all_histograms_size + num_new_clusters) {
+ _new_size *= 2
+ }
+ new_array = make([]histogramCommand, _new_size)
+ if all_histograms_capacity != 0 {
+ copy(new_array, all_histograms[:all_histograms_capacity])
+ }
+
+ all_histograms = new_array
+ all_histograms_capacity = _new_size
+ }
+
+ brotli_ensure_capacity_uint32_t(&cluster_size, &cluster_size_capacity, cluster_size_size+num_new_clusters)
+ for j = 0; j < num_new_clusters; j++ {
+ all_histograms[all_histograms_size] = histograms[new_clusters[j]]
+ all_histograms_size++
+ cluster_size[cluster_size_size] = sizes[new_clusters[j]]
+ cluster_size_size++
+ remap[new_clusters[j]] = uint32(j)
+ }
+
+ for j = 0; j < num_to_combine; j++ {
+ histogram_symbols[i+j] = uint32(num_clusters) + remap[symbols[j]]
+ }
+
+ num_clusters += num_new_clusters
+ assert(num_clusters == cluster_size_size)
+ assert(num_clusters == all_histograms_size)
+ }
+
+ histograms = nil
+
+ max_num_pairs = brotli_min_size_t(64*num_clusters, (num_clusters/2)*num_clusters)
+ if pairs_capacity < max_num_pairs+1 {
+ pairs = nil
+ pairs = make([]histogramPair, (max_num_pairs + 1))
+ }
+
+ clusters = make([]uint32, num_clusters)
+ for i = 0; i < num_clusters; i++ {
+ clusters[i] = uint32(i)
+ }
+
+ num_final_clusters = histogramCombineCommand(all_histograms, cluster_size, histogram_symbols, clusters, pairs, num_clusters, num_blocks, maxNumberOfBlockTypes, max_num_pairs)
+ pairs = nil
+ cluster_size = nil
+
+ new_index = make([]uint32, num_clusters)
+ for i = 0; i < num_clusters; i++ {
+ new_index[i] = clusterBlocksCommand_kInvalidIndex
+ }
+ pos = 0
+ {
+ var next_index uint32 = 0
+ for i = 0; i < num_blocks; i++ {
+ var histo histogramCommand
+ var j uint
+ var best_out uint32
+ var best_bits float64
+ histogramClearCommand(&histo)
+ for j = 0; uint32(j) < block_lengths[i]; j++ {
+ histogramAddCommand(&histo, uint(data[pos]))
+ pos++
+ }
+
+ if i == 0 {
+ best_out = histogram_symbols[0]
+ } else {
+ best_out = histogram_symbols[i-1]
+ }
+ best_bits = histogramBitCostDistanceCommand(&histo, &all_histograms[best_out])
+ for j = 0; j < num_final_clusters; j++ {
+ var cur_bits float64 = histogramBitCostDistanceCommand(&histo, &all_histograms[clusters[j]])
+ if cur_bits < best_bits {
+ best_bits = cur_bits
+ best_out = clusters[j]
+ }
+ }
+
+ histogram_symbols[i] = best_out
+ if new_index[best_out] == clusterBlocksCommand_kInvalidIndex {
+ new_index[best_out] = next_index
+ next_index++
+ }
+ }
+ }
+
+ clusters = nil
+ all_histograms = nil
+ brotli_ensure_capacity_uint8_t(&split.types, &split.types_alloc_size, num_blocks)
+ brotli_ensure_capacity_uint32_t(&split.lengths, &split.lengths_alloc_size, num_blocks)
+ {
+ var cur_length uint32 = 0
+ var block_idx uint = 0
+ var max_type byte = 0
+ for i = 0; i < num_blocks; i++ {
+ cur_length += block_lengths[i]
+ if i+1 == num_blocks || histogram_symbols[i] != histogram_symbols[i+1] {
+ var id byte = byte(new_index[histogram_symbols[i]])
+ split.types[block_idx] = id
+ split.lengths[block_idx] = cur_length
+ max_type = brotli_max_uint8_t(max_type, id)
+ cur_length = 0
+ block_idx++
+ }
+ }
+
+ split.num_blocks = block_idx
+ split.num_types = uint(max_type) + 1
+ }
+
+ new_index = nil
+ block_lengths = nil
+ histogram_symbols = nil
+}
+
+func splitByteVectorCommand(data []uint16, literals_per_histogram uint, max_histograms uint, sampling_stride_length uint, block_switch_cost float64, params *encoderParams, split *blockSplit) {
+ length := uint(len(data))
+ var data_size uint = histogramDataSizeCommand()
+ var num_histograms uint = length/literals_per_histogram + 1
+ var histograms []histogramCommand
+ if num_histograms > max_histograms {
+ num_histograms = max_histograms
+ }
+
+ if length == 0 {
+ split.num_types = 1
+ return
+ } else if length < kMinLengthForBlockSplitting {
+ brotli_ensure_capacity_uint8_t(&split.types, &split.types_alloc_size, split.num_blocks+1)
+ brotli_ensure_capacity_uint32_t(&split.lengths, &split.lengths_alloc_size, split.num_blocks+1)
+ split.num_types = 1
+ split.types[split.num_blocks] = 0
+ split.lengths[split.num_blocks] = uint32(length)
+ split.num_blocks++
+ return
+ }
+
+ histograms = make([]histogramCommand, num_histograms)
+
+ /* Find good entropy codes. */
+ initialEntropyCodesCommand(data, length, sampling_stride_length, num_histograms, histograms)
+
+ refineEntropyCodesCommand(data, length, sampling_stride_length, num_histograms, histograms)
+ {
+ var block_ids []byte = make([]byte, length)
+ var num_blocks uint = 0
+ var bitmaplen uint = (num_histograms + 7) >> 3
+ var insert_cost []float64 = make([]float64, (data_size * num_histograms))
+ var cost []float64 = make([]float64, num_histograms)
+ var switch_signal []byte = make([]byte, (length * bitmaplen))
+ var new_id []uint16 = make([]uint16, num_histograms)
+ var iters uint
+ if params.quality < hqZopflificationQuality {
+ iters = 3
+ } else {
+ iters = 10
+ }
+ /* Find a good path through literals with the good entropy codes. */
+
+ var i uint
+ for i = 0; i < iters; i++ {
+ num_blocks = findBlocksCommand(data, length, block_switch_cost, num_histograms, histograms, insert_cost, cost, switch_signal, block_ids)
+ num_histograms = remapBlockIdsCommand(block_ids, length, new_id, num_histograms)
+ buildBlockHistogramsCommand(data, length, block_ids, num_histograms, histograms)
+ }
+
+ insert_cost = nil
+ cost = nil
+ switch_signal = nil
+ new_id = nil
+ histograms = nil
+ clusterBlocksCommand(data, length, num_blocks, block_ids, split)
+ block_ids = nil
+ }
+}
diff --git a/vendor/github.com/andybalholm/brotli/block_splitter_distance.go b/vendor/github.com/andybalholm/brotli/block_splitter_distance.go
new file mode 100644
index 0000000..953530d
--- /dev/null
+++ b/vendor/github.com/andybalholm/brotli/block_splitter_distance.go
@@ -0,0 +1,433 @@
+package brotli
+
+import "math"
+
+/* Copyright 2013 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+func initialEntropyCodesDistance(data []uint16, length uint, stride uint, num_histograms uint, histograms []histogramDistance) {
+ var seed uint32 = 7
+ var block_length uint = length / num_histograms
+ var i uint
+ clearHistogramsDistance(histograms, num_histograms)
+ for i = 0; i < num_histograms; i++ {
+ var pos uint = length * i / num_histograms
+ if i != 0 {
+ pos += uint(myRand(&seed) % uint32(block_length))
+ }
+
+ if pos+stride >= length {
+ pos = length - stride - 1
+ }
+
+ histogramAddVectorDistance(&histograms[i], data[pos:], stride)
+ }
+}
+
+func randomSampleDistance(seed *uint32, data []uint16, length uint, stride uint, sample *histogramDistance) {
+ var pos uint = 0
+ if stride >= length {
+ stride = length
+ } else {
+ pos = uint(myRand(seed) % uint32(length-stride+1))
+ }
+
+ histogramAddVectorDistance(sample, data[pos:], stride)
+}
+
+func refineEntropyCodesDistance(data []uint16, length uint, stride uint, num_histograms uint, histograms []histogramDistance) {
+ var iters uint = kIterMulForRefining*length/stride + kMinItersForRefining
+ var seed uint32 = 7
+ var iter uint
+ iters = ((iters + num_histograms - 1) / num_histograms) * num_histograms
+ for iter = 0; iter < iters; iter++ {
+ var sample histogramDistance
+ histogramClearDistance(&sample)
+ randomSampleDistance(&seed, data, length, stride, &sample)
+ histogramAddHistogramDistance(&histograms[iter%num_histograms], &sample)
+ }
+}
+
+/* Assigns a block id from the range [0, num_histograms) to each data element
+ in data[0..length) and fills in block_id[0..length) with the assigned values.
+ Returns the number of blocks, i.e. one plus the number of block switches. */
+func findBlocksDistance(data []uint16, length uint, block_switch_bitcost float64, num_histograms uint, histograms []histogramDistance, insert_cost []float64, cost []float64, switch_signal []byte, block_id []byte) uint {
+ var data_size uint = histogramDataSizeDistance()
+ var bitmaplen uint = (num_histograms + 7) >> 3
+ var num_blocks uint = 1
+ var i uint
+ var j uint
+ assert(num_histograms <= 256)
+ if num_histograms <= 1 {
+ for i = 0; i < length; i++ {
+ block_id[i] = 0
+ }
+
+ return 1
+ }
+
+ for i := 0; i < int(data_size*num_histograms); i++ {
+ insert_cost[i] = 0
+ }
+ for i = 0; i < num_histograms; i++ {
+ insert_cost[i] = fastLog2(uint(uint32(histograms[i].total_count_)))
+ }
+
+ for i = data_size; i != 0; {
+ i--
+ for j = 0; j < num_histograms; j++ {
+ insert_cost[i*num_histograms+j] = insert_cost[j] - bitCost(uint(histograms[j].data_[i]))
+ }
+ }
+
+ for i := 0; i < int(num_histograms); i++ {
+ cost[i] = 0
+ }
+ for i := 0; i < int(length*bitmaplen); i++ {
+ switch_signal[i] = 0
+ }
+
+ /* After each iteration of this loop, cost[k] will contain the difference
+ between the minimum cost of arriving at the current byte position using
+ entropy code k, and the minimum cost of arriving at the current byte
+ position. This difference is capped at the block switch cost, and if it
+ reaches block switch cost, it means that when we trace back from the last
+ position, we need to switch here. */
+ for i = 0; i < length; i++ {
+ var byte_ix uint = i
+ var ix uint = byte_ix * bitmaplen
+ var insert_cost_ix uint = uint(data[byte_ix]) * num_histograms
+ var min_cost float64 = 1e99
+ var block_switch_cost float64 = block_switch_bitcost
+ var k uint
+ for k = 0; k < num_histograms; k++ {
+ /* We are coding the symbol in data[byte_ix] with entropy code k. */
+ cost[k] += insert_cost[insert_cost_ix+k]
+
+ if cost[k] < min_cost {
+ min_cost = cost[k]
+ block_id[byte_ix] = byte(k)
+ }
+ }
+
+ /* More blocks for the beginning. */
+ if byte_ix < 2000 {
+ block_switch_cost *= 0.77 + 0.07*float64(byte_ix)/2000
+ }
+
+ for k = 0; k < num_histograms; k++ {
+ cost[k] -= min_cost
+ if cost[k] >= block_switch_cost {
+ var mask byte = byte(1 << (k & 7))
+ cost[k] = block_switch_cost
+ assert(k>>3 < bitmaplen)
+ switch_signal[ix+(k>>3)] |= mask
+ /* Trace back from the last position and switch at the marked places. */
+ }
+ }
+ }
+ {
+ var byte_ix uint = length - 1
+ var ix uint = byte_ix * bitmaplen
+ var cur_id byte = block_id[byte_ix]
+ for byte_ix > 0 {
+ var mask byte = byte(1 << (cur_id & 7))
+ assert(uint(cur_id)>>3 < bitmaplen)
+ byte_ix--
+ ix -= bitmaplen
+ if switch_signal[ix+uint(cur_id>>3)]&mask != 0 {
+ if cur_id != block_id[byte_ix] {
+ cur_id = block_id[byte_ix]
+ num_blocks++
+ }
+ }
+
+ block_id[byte_ix] = cur_id
+ }
+ }
+
+ return num_blocks
+}
+
+var remapBlockIdsDistance_kInvalidId uint16 = 256
+
+func remapBlockIdsDistance(block_ids []byte, length uint, new_id []uint16, num_histograms uint) uint {
+ var next_id uint16 = 0
+ var i uint
+ for i = 0; i < num_histograms; i++ {
+ new_id[i] = remapBlockIdsDistance_kInvalidId
+ }
+
+ for i = 0; i < length; i++ {
+ assert(uint(block_ids[i]) < num_histograms)
+ if new_id[block_ids[i]] == remapBlockIdsDistance_kInvalidId {
+ new_id[block_ids[i]] = next_id
+ next_id++
+ }
+ }
+
+ for i = 0; i < length; i++ {
+ block_ids[i] = byte(new_id[block_ids[i]])
+ assert(uint(block_ids[i]) < num_histograms)
+ }
+
+ assert(uint(next_id) <= num_histograms)
+ return uint(next_id)
+}
+
+func buildBlockHistogramsDistance(data []uint16, length uint, block_ids []byte, num_histograms uint, histograms []histogramDistance) {
+ var i uint
+ clearHistogramsDistance(histograms, num_histograms)
+ for i = 0; i < length; i++ {
+ histogramAddDistance(&histograms[block_ids[i]], uint(data[i]))
+ }
+}
+
+var clusterBlocksDistance_kInvalidIndex uint32 = math.MaxUint32
+
+func clusterBlocksDistance(data []uint16, length uint, num_blocks uint, block_ids []byte, split *blockSplit) {
+ var histogram_symbols []uint32 = make([]uint32, num_blocks)
+ var block_lengths []uint32 = make([]uint32, num_blocks)
+ var expected_num_clusters uint = clustersPerBatch * (num_blocks + histogramsPerBatch - 1) / histogramsPerBatch
+ var all_histograms_size uint = 0
+ var all_histograms_capacity uint = expected_num_clusters
+ var all_histograms []histogramDistance = make([]histogramDistance, all_histograms_capacity)
+ var cluster_size_size uint = 0
+ var cluster_size_capacity uint = expected_num_clusters
+ var cluster_size []uint32 = make([]uint32, cluster_size_capacity)
+ var num_clusters uint = 0
+ var histograms []histogramDistance = make([]histogramDistance, brotli_min_size_t(num_blocks, histogramsPerBatch))
+ var max_num_pairs uint = histogramsPerBatch * histogramsPerBatch / 2
+ var pairs_capacity uint = max_num_pairs + 1
+ var pairs []histogramPair = make([]histogramPair, pairs_capacity)
+ var pos uint = 0
+ var clusters []uint32
+ var num_final_clusters uint
+ var new_index []uint32
+ var i uint
+ var sizes = [histogramsPerBatch]uint32{0}
+ var new_clusters = [histogramsPerBatch]uint32{0}
+ var symbols = [histogramsPerBatch]uint32{0}
+ var remap = [histogramsPerBatch]uint32{0}
+
+ for i := 0; i < int(num_blocks); i++ {
+ block_lengths[i] = 0
+ }
+ {
+ var block_idx uint = 0
+ for i = 0; i < length; i++ {
+ assert(block_idx < num_blocks)
+ block_lengths[block_idx]++
+ if i+1 == length || block_ids[i] != block_ids[i+1] {
+ block_idx++
+ }
+ }
+
+ assert(block_idx == num_blocks)
+ }
+
+ for i = 0; i < num_blocks; i += histogramsPerBatch {
+ var num_to_combine uint = brotli_min_size_t(num_blocks-i, histogramsPerBatch)
+ var num_new_clusters uint
+ var j uint
+ for j = 0; j < num_to_combine; j++ {
+ var k uint
+ histogramClearDistance(&histograms[j])
+ for k = 0; uint32(k) < block_lengths[i+j]; k++ {
+ histogramAddDistance(&histograms[j], uint(data[pos]))
+ pos++
+ }
+
+ histograms[j].bit_cost_ = populationCostDistance(&histograms[j])
+ new_clusters[j] = uint32(j)
+ symbols[j] = uint32(j)
+ sizes[j] = 1
+ }
+
+ num_new_clusters = histogramCombineDistance(histograms, sizes[:], symbols[:], new_clusters[:], []histogramPair(pairs), num_to_combine, num_to_combine, histogramsPerBatch, max_num_pairs)
+ if all_histograms_capacity < (all_histograms_size + num_new_clusters) {
+ var _new_size uint
+ if all_histograms_capacity == 0 {
+ _new_size = all_histograms_size + num_new_clusters
+ } else {
+ _new_size = all_histograms_capacity
+ }
+ var new_array []histogramDistance
+ for _new_size < (all_histograms_size + num_new_clusters) {
+ _new_size *= 2
+ }
+ new_array = make([]histogramDistance, _new_size)
+ if all_histograms_capacity != 0 {
+ copy(new_array, all_histograms[:all_histograms_capacity])
+ }
+
+ all_histograms = new_array
+ all_histograms_capacity = _new_size
+ }
+
+ brotli_ensure_capacity_uint32_t(&cluster_size, &cluster_size_capacity, cluster_size_size+num_new_clusters)
+ for j = 0; j < num_new_clusters; j++ {
+ all_histograms[all_histograms_size] = histograms[new_clusters[j]]
+ all_histograms_size++
+ cluster_size[cluster_size_size] = sizes[new_clusters[j]]
+ cluster_size_size++
+ remap[new_clusters[j]] = uint32(j)
+ }
+
+ for j = 0; j < num_to_combine; j++ {
+ histogram_symbols[i+j] = uint32(num_clusters) + remap[symbols[j]]
+ }
+
+ num_clusters += num_new_clusters
+ assert(num_clusters == cluster_size_size)
+ assert(num_clusters == all_histograms_size)
+ }
+
+ histograms = nil
+
+ max_num_pairs = brotli_min_size_t(64*num_clusters, (num_clusters/2)*num_clusters)
+ if pairs_capacity < max_num_pairs+1 {
+ pairs = nil
+ pairs = make([]histogramPair, (max_num_pairs + 1))
+ }
+
+ clusters = make([]uint32, num_clusters)
+ for i = 0; i < num_clusters; i++ {
+ clusters[i] = uint32(i)
+ }
+
+ num_final_clusters = histogramCombineDistance(all_histograms, cluster_size, histogram_symbols, clusters, pairs, num_clusters, num_blocks, maxNumberOfBlockTypes, max_num_pairs)
+ pairs = nil
+ cluster_size = nil
+
+ new_index = make([]uint32, num_clusters)
+ for i = 0; i < num_clusters; i++ {
+ new_index[i] = clusterBlocksDistance_kInvalidIndex
+ }
+ pos = 0
+ {
+ var next_index uint32 = 0
+ for i = 0; i < num_blocks; i++ {
+ var histo histogramDistance
+ var j uint
+ var best_out uint32
+ var best_bits float64
+ histogramClearDistance(&histo)
+ for j = 0; uint32(j) < block_lengths[i]; j++ {
+ histogramAddDistance(&histo, uint(data[pos]))
+ pos++
+ }
+
+ if i == 0 {
+ best_out = histogram_symbols[0]
+ } else {
+ best_out = histogram_symbols[i-1]
+ }
+ best_bits = histogramBitCostDistanceDistance(&histo, &all_histograms[best_out])
+ for j = 0; j < num_final_clusters; j++ {
+ var cur_bits float64 = histogramBitCostDistanceDistance(&histo, &all_histograms[clusters[j]])
+ if cur_bits < best_bits {
+ best_bits = cur_bits
+ best_out = clusters[j]
+ }
+ }
+
+ histogram_symbols[i] = best_out
+ if new_index[best_out] == clusterBlocksDistance_kInvalidIndex {
+ new_index[best_out] = next_index
+ next_index++
+ }
+ }
+ }
+
+ clusters = nil
+ all_histograms = nil
+ brotli_ensure_capacity_uint8_t(&split.types, &split.types_alloc_size, num_blocks)
+ brotli_ensure_capacity_uint32_t(&split.lengths, &split.lengths_alloc_size, num_blocks)
+ {
+ var cur_length uint32 = 0
+ var block_idx uint = 0
+ var max_type byte = 0
+ for i = 0; i < num_blocks; i++ {
+ cur_length += block_lengths[i]
+ if i+1 == num_blocks || histogram_symbols[i] != histogram_symbols[i+1] {
+ var id byte = byte(new_index[histogram_symbols[i]])
+ split.types[block_idx] = id
+ split.lengths[block_idx] = cur_length
+ max_type = brotli_max_uint8_t(max_type, id)
+ cur_length = 0
+ block_idx++
+ }
+ }
+
+ split.num_blocks = block_idx
+ split.num_types = uint(max_type) + 1
+ }
+
+ new_index = nil
+ block_lengths = nil
+ histogram_symbols = nil
+}
+
+func splitByteVectorDistance(data []uint16, length uint, literals_per_histogram uint, max_histograms uint, sampling_stride_length uint, block_switch_cost float64, params *encoderParams, split *blockSplit) {
+ var data_size uint = histogramDataSizeDistance()
+ var num_histograms uint = length/literals_per_histogram + 1
+ var histograms []histogramDistance
+ if num_histograms > max_histograms {
+ num_histograms = max_histograms
+ }
+
+ if length == 0 {
+ split.num_types = 1
+ return
+ } else if length < kMinLengthForBlockSplitting {
+ brotli_ensure_capacity_uint8_t(&split.types, &split.types_alloc_size, split.num_blocks+1)
+ brotli_ensure_capacity_uint32_t(&split.lengths, &split.lengths_alloc_size, split.num_blocks+1)
+ split.num_types = 1
+ split.types[split.num_blocks] = 0
+ split.lengths[split.num_blocks] = uint32(length)
+ split.num_blocks++
+ return
+ }
+
+ histograms = make([]histogramDistance, num_histograms)
+
+ /* Find good entropy codes. */
+ initialEntropyCodesDistance(data, length, sampling_stride_length, num_histograms, histograms)
+
+ refineEntropyCodesDistance(data, length, sampling_stride_length, num_histograms, histograms)
+ {
+ var block_ids []byte = make([]byte, length)
+ var num_blocks uint = 0
+ var bitmaplen uint = (num_histograms + 7) >> 3
+ var insert_cost []float64 = make([]float64, (data_size * num_histograms))
+ var cost []float64 = make([]float64, num_histograms)
+ var switch_signal []byte = make([]byte, (length * bitmaplen))
+ var new_id []uint16 = make([]uint16, num_histograms)
+ var iters uint
+ if params.quality < hqZopflificationQuality {
+ iters = 3
+ } else {
+ iters = 10
+ }
+ /* Find a good path through literals with the good entropy codes. */
+
+ var i uint
+ for i = 0; i < iters; i++ {
+ num_blocks = findBlocksDistance(data, length, block_switch_cost, num_histograms, histograms, insert_cost, cost, switch_signal, block_ids)
+ num_histograms = remapBlockIdsDistance(block_ids, length, new_id, num_histograms)
+ buildBlockHistogramsDistance(data, length, block_ids, num_histograms, histograms)
+ }
+
+ insert_cost = nil
+ cost = nil
+ switch_signal = nil
+ new_id = nil
+ histograms = nil
+ clusterBlocksDistance(data, length, num_blocks, block_ids, split)
+ block_ids = nil
+ }
+}
diff --git a/vendor/github.com/andybalholm/brotli/block_splitter_literal.go b/vendor/github.com/andybalholm/brotli/block_splitter_literal.go
new file mode 100644
index 0000000..1c895cf
--- /dev/null
+++ b/vendor/github.com/andybalholm/brotli/block_splitter_literal.go
@@ -0,0 +1,433 @@
+package brotli
+
+import "math"
+
+/* Copyright 2013 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+func initialEntropyCodesLiteral(data []byte, length uint, stride uint, num_histograms uint, histograms []histogramLiteral) {
+ var seed uint32 = 7
+ var block_length uint = length / num_histograms
+ var i uint
+ clearHistogramsLiteral(histograms, num_histograms)
+ for i = 0; i < num_histograms; i++ {
+ var pos uint = length * i / num_histograms
+ if i != 0 {
+ pos += uint(myRand(&seed) % uint32(block_length))
+ }
+
+ if pos+stride >= length {
+ pos = length - stride - 1
+ }
+
+ histogramAddVectorLiteral(&histograms[i], data[pos:], stride)
+ }
+}
+
+func randomSampleLiteral(seed *uint32, data []byte, length uint, stride uint, sample *histogramLiteral) {
+ var pos uint = 0
+ if stride >= length {
+ stride = length
+ } else {
+ pos = uint(myRand(seed) % uint32(length-stride+1))
+ }
+
+ histogramAddVectorLiteral(sample, data[pos:], stride)
+}
+
+func refineEntropyCodesLiteral(data []byte, length uint, stride uint, num_histograms uint, histograms []histogramLiteral) {
+ var iters uint = kIterMulForRefining*length/stride + kMinItersForRefining
+ var seed uint32 = 7
+ var iter uint
+ iters = ((iters + num_histograms - 1) / num_histograms) * num_histograms
+ for iter = 0; iter < iters; iter++ {
+ var sample histogramLiteral
+ histogramClearLiteral(&sample)
+ randomSampleLiteral(&seed, data, length, stride, &sample)
+ histogramAddHistogramLiteral(&histograms[iter%num_histograms], &sample)
+ }
+}
+
+/* Assigns a block id from the range [0, num_histograms) to each data element
+ in data[0..length) and fills in block_id[0..length) with the assigned values.
+ Returns the number of blocks, i.e. one plus the number of block switches. */
+func findBlocksLiteral(data []byte, length uint, block_switch_bitcost float64, num_histograms uint, histograms []histogramLiteral, insert_cost []float64, cost []float64, switch_signal []byte, block_id []byte) uint {
+ var data_size uint = histogramDataSizeLiteral()
+ var bitmaplen uint = (num_histograms + 7) >> 3
+ var num_blocks uint = 1
+ var i uint
+ var j uint
+ assert(num_histograms <= 256)
+ if num_histograms <= 1 {
+ for i = 0; i < length; i++ {
+ block_id[i] = 0
+ }
+
+ return 1
+ }
+
+ for i := 0; i < int(data_size*num_histograms); i++ {
+ insert_cost[i] = 0
+ }
+ for i = 0; i < num_histograms; i++ {
+ insert_cost[i] = fastLog2(uint(uint32(histograms[i].total_count_)))
+ }
+
+ for i = data_size; i != 0; {
+ i--
+ for j = 0; j < num_histograms; j++ {
+ insert_cost[i*num_histograms+j] = insert_cost[j] - bitCost(uint(histograms[j].data_[i]))
+ }
+ }
+
+ for i := 0; i < int(num_histograms); i++ {
+ cost[i] = 0
+ }
+ for i := 0; i < int(length*bitmaplen); i++ {
+ switch_signal[i] = 0
+ }
+
+ /* After each iteration of this loop, cost[k] will contain the difference
+ between the minimum cost of arriving at the current byte position using
+ entropy code k, and the minimum cost of arriving at the current byte
+ position. This difference is capped at the block switch cost, and if it
+ reaches block switch cost, it means that when we trace back from the last
+ position, we need to switch here. */
+ for i = 0; i < length; i++ {
+ var byte_ix uint = i
+ var ix uint = byte_ix * bitmaplen
+ var insert_cost_ix uint = uint(data[byte_ix]) * num_histograms
+ var min_cost float64 = 1e99
+ var block_switch_cost float64 = block_switch_bitcost
+ var k uint
+ for k = 0; k < num_histograms; k++ {
+ /* We are coding the symbol in data[byte_ix] with entropy code k. */
+ cost[k] += insert_cost[insert_cost_ix+k]
+
+ if cost[k] < min_cost {
+ min_cost = cost[k]
+ block_id[byte_ix] = byte(k)
+ }
+ }
+
+ /* More blocks for the beginning. */
+ if byte_ix < 2000 {
+ block_switch_cost *= 0.77 + 0.07*float64(byte_ix)/2000
+ }
+
+ for k = 0; k < num_histograms; k++ {
+ cost[k] -= min_cost
+ if cost[k] >= block_switch_cost {
+ var mask byte = byte(1 << (k & 7))
+ cost[k] = block_switch_cost
+ assert(k>>3 < bitmaplen)
+ switch_signal[ix+(k>>3)] |= mask
+ /* Trace back from the last position and switch at the marked places. */
+ }
+ }
+ }
+ {
+ var byte_ix uint = length - 1
+ var ix uint = byte_ix * bitmaplen
+ var cur_id byte = block_id[byte_ix]
+ for byte_ix > 0 {
+ var mask byte = byte(1 << (cur_id & 7))
+ assert(uint(cur_id)>>3 < bitmaplen)
+ byte_ix--
+ ix -= bitmaplen
+ if switch_signal[ix+uint(cur_id>>3)]&mask != 0 {
+ if cur_id != block_id[byte_ix] {
+ cur_id = block_id[byte_ix]
+ num_blocks++
+ }
+ }
+
+ block_id[byte_ix] = cur_id
+ }
+ }
+
+ return num_blocks
+}
+
+var remapBlockIdsLiteral_kInvalidId uint16 = 256
+
+func remapBlockIdsLiteral(block_ids []byte, length uint, new_id []uint16, num_histograms uint) uint {
+ var next_id uint16 = 0
+ var i uint
+ for i = 0; i < num_histograms; i++ {
+ new_id[i] = remapBlockIdsLiteral_kInvalidId
+ }
+
+ for i = 0; i < length; i++ {
+ assert(uint(block_ids[i]) < num_histograms)
+ if new_id[block_ids[i]] == remapBlockIdsLiteral_kInvalidId {
+ new_id[block_ids[i]] = next_id
+ next_id++
+ }
+ }
+
+ for i = 0; i < length; i++ {
+ block_ids[i] = byte(new_id[block_ids[i]])
+ assert(uint(block_ids[i]) < num_histograms)
+ }
+
+ assert(uint(next_id) <= num_histograms)
+ return uint(next_id)
+}
+
+func buildBlockHistogramsLiteral(data []byte, length uint, block_ids []byte, num_histograms uint, histograms []histogramLiteral) {
+ var i uint
+ clearHistogramsLiteral(histograms, num_histograms)
+ for i = 0; i < length; i++ {
+ histogramAddLiteral(&histograms[block_ids[i]], uint(data[i]))
+ }
+}
+
+var clusterBlocksLiteral_kInvalidIndex uint32 = math.MaxUint32
+
+func clusterBlocksLiteral(data []byte, length uint, num_blocks uint, block_ids []byte, split *blockSplit) {
+ var histogram_symbols []uint32 = make([]uint32, num_blocks)
+ var block_lengths []uint32 = make([]uint32, num_blocks)
+ var expected_num_clusters uint = clustersPerBatch * (num_blocks + histogramsPerBatch - 1) / histogramsPerBatch
+ var all_histograms_size uint = 0
+ var all_histograms_capacity uint = expected_num_clusters
+ var all_histograms []histogramLiteral = make([]histogramLiteral, all_histograms_capacity)
+ var cluster_size_size uint = 0
+ var cluster_size_capacity uint = expected_num_clusters
+ var cluster_size []uint32 = make([]uint32, cluster_size_capacity)
+ var num_clusters uint = 0
+ var histograms []histogramLiteral = make([]histogramLiteral, brotli_min_size_t(num_blocks, histogramsPerBatch))
+ var max_num_pairs uint = histogramsPerBatch * histogramsPerBatch / 2
+ var pairs_capacity uint = max_num_pairs + 1
+ var pairs []histogramPair = make([]histogramPair, pairs_capacity)
+ var pos uint = 0
+ var clusters []uint32
+ var num_final_clusters uint
+ var new_index []uint32
+ var i uint
+ var sizes = [histogramsPerBatch]uint32{0}
+ var new_clusters = [histogramsPerBatch]uint32{0}
+ var symbols = [histogramsPerBatch]uint32{0}
+ var remap = [histogramsPerBatch]uint32{0}
+
+ for i := 0; i < int(num_blocks); i++ {
+ block_lengths[i] = 0
+ }
+ {
+ var block_idx uint = 0
+ for i = 0; i < length; i++ {
+ assert(block_idx < num_blocks)
+ block_lengths[block_idx]++
+ if i+1 == length || block_ids[i] != block_ids[i+1] {
+ block_idx++
+ }
+ }
+
+ assert(block_idx == num_blocks)
+ }
+
+ for i = 0; i < num_blocks; i += histogramsPerBatch {
+ var num_to_combine uint = brotli_min_size_t(num_blocks-i, histogramsPerBatch)
+ var num_new_clusters uint
+ var j uint
+ for j = 0; j < num_to_combine; j++ {
+ var k uint
+ histogramClearLiteral(&histograms[j])
+ for k = 0; uint32(k) < block_lengths[i+j]; k++ {
+ histogramAddLiteral(&histograms[j], uint(data[pos]))
+ pos++
+ }
+
+ histograms[j].bit_cost_ = populationCostLiteral(&histograms[j])
+ new_clusters[j] = uint32(j)
+ symbols[j] = uint32(j)
+ sizes[j] = 1
+ }
+
+ num_new_clusters = histogramCombineLiteral(histograms, sizes[:], symbols[:], new_clusters[:], []histogramPair(pairs), num_to_combine, num_to_combine, histogramsPerBatch, max_num_pairs)
+ if all_histograms_capacity < (all_histograms_size + num_new_clusters) {
+ var _new_size uint
+ if all_histograms_capacity == 0 {
+ _new_size = all_histograms_size + num_new_clusters
+ } else {
+ _new_size = all_histograms_capacity
+ }
+ var new_array []histogramLiteral
+ for _new_size < (all_histograms_size + num_new_clusters) {
+ _new_size *= 2
+ }
+ new_array = make([]histogramLiteral, _new_size)
+ if all_histograms_capacity != 0 {
+ copy(new_array, all_histograms[:all_histograms_capacity])
+ }
+
+ all_histograms = new_array
+ all_histograms_capacity = _new_size
+ }
+
+ brotli_ensure_capacity_uint32_t(&cluster_size, &cluster_size_capacity, cluster_size_size+num_new_clusters)
+ for j = 0; j < num_new_clusters; j++ {
+ all_histograms[all_histograms_size] = histograms[new_clusters[j]]
+ all_histograms_size++
+ cluster_size[cluster_size_size] = sizes[new_clusters[j]]
+ cluster_size_size++
+ remap[new_clusters[j]] = uint32(j)
+ }
+
+ for j = 0; j < num_to_combine; j++ {
+ histogram_symbols[i+j] = uint32(num_clusters) + remap[symbols[j]]
+ }
+
+ num_clusters += num_new_clusters
+ assert(num_clusters == cluster_size_size)
+ assert(num_clusters == all_histograms_size)
+ }
+
+ histograms = nil
+
+ max_num_pairs = brotli_min_size_t(64*num_clusters, (num_clusters/2)*num_clusters)
+ if pairs_capacity < max_num_pairs+1 {
+ pairs = nil
+ pairs = make([]histogramPair, (max_num_pairs + 1))
+ }
+
+ clusters = make([]uint32, num_clusters)
+ for i = 0; i < num_clusters; i++ {
+ clusters[i] = uint32(i)
+ }
+
+ num_final_clusters = histogramCombineLiteral(all_histograms, cluster_size, histogram_symbols, clusters, pairs, num_clusters, num_blocks, maxNumberOfBlockTypes, max_num_pairs)
+ pairs = nil
+ cluster_size = nil
+
+ new_index = make([]uint32, num_clusters)
+ for i = 0; i < num_clusters; i++ {
+ new_index[i] = clusterBlocksLiteral_kInvalidIndex
+ }
+ pos = 0
+ {
+ var next_index uint32 = 0
+ for i = 0; i < num_blocks; i++ {
+ var histo histogramLiteral
+ var j uint
+ var best_out uint32
+ var best_bits float64
+ histogramClearLiteral(&histo)
+ for j = 0; uint32(j) < block_lengths[i]; j++ {
+ histogramAddLiteral(&histo, uint(data[pos]))
+ pos++
+ }
+
+ if i == 0 {
+ best_out = histogram_symbols[0]
+ } else {
+ best_out = histogram_symbols[i-1]
+ }
+ best_bits = histogramBitCostDistanceLiteral(&histo, &all_histograms[best_out])
+ for j = 0; j < num_final_clusters; j++ {
+ var cur_bits float64 = histogramBitCostDistanceLiteral(&histo, &all_histograms[clusters[j]])
+ if cur_bits < best_bits {
+ best_bits = cur_bits
+ best_out = clusters[j]
+ }
+ }
+
+ histogram_symbols[i] = best_out
+ if new_index[best_out] == clusterBlocksLiteral_kInvalidIndex {
+ new_index[best_out] = next_index
+ next_index++
+ }
+ }
+ }
+
+ clusters = nil
+ all_histograms = nil
+ brotli_ensure_capacity_uint8_t(&split.types, &split.types_alloc_size, num_blocks)
+ brotli_ensure_capacity_uint32_t(&split.lengths, &split.lengths_alloc_size, num_blocks)
+ {
+ var cur_length uint32 = 0
+ var block_idx uint = 0
+ var max_type byte = 0
+ for i = 0; i < num_blocks; i++ {
+ cur_length += block_lengths[i]
+ if i+1 == num_blocks || histogram_symbols[i] != histogram_symbols[i+1] {
+ var id byte = byte(new_index[histogram_symbols[i]])
+ split.types[block_idx] = id
+ split.lengths[block_idx] = cur_length
+ max_type = brotli_max_uint8_t(max_type, id)
+ cur_length = 0
+ block_idx++
+ }
+ }
+
+ split.num_blocks = block_idx
+ split.num_types = uint(max_type) + 1
+ }
+
+ new_index = nil
+ block_lengths = nil
+ histogram_symbols = nil
+}
+
+func splitByteVectorLiteral(data []byte, length uint, literals_per_histogram uint, max_histograms uint, sampling_stride_length uint, block_switch_cost float64, params *encoderParams, split *blockSplit) {
+ var data_size uint = histogramDataSizeLiteral()
+ var num_histograms uint = length/literals_per_histogram + 1
+ var histograms []histogramLiteral
+ if num_histograms > max_histograms {
+ num_histograms = max_histograms
+ }
+
+ if length == 0 {
+ split.num_types = 1
+ return
+ } else if length < kMinLengthForBlockSplitting {
+ brotli_ensure_capacity_uint8_t(&split.types, &split.types_alloc_size, split.num_blocks+1)
+ brotli_ensure_capacity_uint32_t(&split.lengths, &split.lengths_alloc_size, split.num_blocks+1)
+ split.num_types = 1
+ split.types[split.num_blocks] = 0
+ split.lengths[split.num_blocks] = uint32(length)
+ split.num_blocks++
+ return
+ }
+
+ histograms = make([]histogramLiteral, num_histograms)
+
+ /* Find good entropy codes. */
+ initialEntropyCodesLiteral(data, length, sampling_stride_length, num_histograms, histograms)
+
+ refineEntropyCodesLiteral(data, length, sampling_stride_length, num_histograms, histograms)
+ {
+ var block_ids []byte = make([]byte, length)
+ var num_blocks uint = 0
+ var bitmaplen uint = (num_histograms + 7) >> 3
+ var insert_cost []float64 = make([]float64, (data_size * num_histograms))
+ var cost []float64 = make([]float64, num_histograms)
+ var switch_signal []byte = make([]byte, (length * bitmaplen))
+ var new_id []uint16 = make([]uint16, num_histograms)
+ var iters uint
+ if params.quality < hqZopflificationQuality {
+ iters = 3
+ } else {
+ iters = 10
+ }
+ /* Find a good path through literals with the good entropy codes. */
+
+ var i uint
+ for i = 0; i < iters; i++ {
+ num_blocks = findBlocksLiteral(data, length, block_switch_cost, num_histograms, histograms, insert_cost, cost, switch_signal, block_ids)
+ num_histograms = remapBlockIdsLiteral(block_ids, length, new_id, num_histograms)
+ buildBlockHistogramsLiteral(data, length, block_ids, num_histograms, histograms)
+ }
+
+ insert_cost = nil
+ cost = nil
+ switch_signal = nil
+ new_id = nil
+ histograms = nil
+ clusterBlocksLiteral(data, length, num_blocks, block_ids, split)
+ block_ids = nil
+ }
+}
diff --git a/vendor/github.com/andybalholm/brotli/brotli_bit_stream.go b/vendor/github.com/andybalholm/brotli/brotli_bit_stream.go
new file mode 100644
index 0000000..7acfb18
--- /dev/null
+++ b/vendor/github.com/andybalholm/brotli/brotli_bit_stream.go
@@ -0,0 +1,1300 @@
+package brotli
+
+import (
+ "math"
+ "sync"
+)
+
+const maxHuffmanTreeSize = (2*numCommandSymbols + 1)
+
+/* The maximum size of Huffman dictionary for distances assuming that
+ NPOSTFIX = 0 and NDIRECT = 0. */
+const maxSimpleDistanceAlphabetSize = 140
+
+/* Represents the range of values belonging to a prefix code:
+ [offset, offset + 2^nbits) */
+type prefixCodeRange struct {
+ offset uint32
+ nbits uint32
+}
+
+var kBlockLengthPrefixCode = [numBlockLenSymbols]prefixCodeRange{
+ prefixCodeRange{1, 2},
+ prefixCodeRange{5, 2},
+ prefixCodeRange{9, 2},
+ prefixCodeRange{13, 2},
+ prefixCodeRange{17, 3},
+ prefixCodeRange{25, 3},
+ prefixCodeRange{33, 3},
+ prefixCodeRange{41, 3},
+ prefixCodeRange{49, 4},
+ prefixCodeRange{65, 4},
+ prefixCodeRange{81, 4},
+ prefixCodeRange{97, 4},
+ prefixCodeRange{113, 5},
+ prefixCodeRange{145, 5},
+ prefixCodeRange{177, 5},
+ prefixCodeRange{209, 5},
+ prefixCodeRange{241, 6},
+ prefixCodeRange{305, 6},
+ prefixCodeRange{369, 7},
+ prefixCodeRange{497, 8},
+ prefixCodeRange{753, 9},
+ prefixCodeRange{1265, 10},
+ prefixCodeRange{2289, 11},
+ prefixCodeRange{4337, 12},
+ prefixCodeRange{8433, 13},
+ prefixCodeRange{16625, 24},
+}
+
+func blockLengthPrefixCode(len uint32) uint32 {
+ var code uint32
+ if len >= 177 {
+ if len >= 753 {
+ code = 20
+ } else {
+ code = 14
+ }
+ } else if len >= 41 {
+ code = 7
+ } else {
+ code = 0
+ }
+ for code < (numBlockLenSymbols-1) && len >= kBlockLengthPrefixCode[code+1].offset {
+ code++
+ }
+ return code
+}
+
+func getBlockLengthPrefixCode(len uint32, code *uint, n_extra *uint32, extra *uint32) {
+ *code = uint(blockLengthPrefixCode(uint32(len)))
+ *n_extra = kBlockLengthPrefixCode[*code].nbits
+ *extra = len - kBlockLengthPrefixCode[*code].offset
+}
+
+type blockTypeCodeCalculator struct {
+ last_type uint
+ second_last_type uint
+}
+
+func initBlockTypeCodeCalculator(self *blockTypeCodeCalculator) {
+ self.last_type = 1
+ self.second_last_type = 0
+}
+
+func nextBlockTypeCode(calculator *blockTypeCodeCalculator, type_ byte) uint {
+ var type_code uint
+ if uint(type_) == calculator.last_type+1 {
+ type_code = 1
+ } else if uint(type_) == calculator.second_last_type {
+ type_code = 0
+ } else {
+ type_code = uint(type_) + 2
+ }
+ calculator.second_last_type = calculator.last_type
+ calculator.last_type = uint(type_)
+ return type_code
+}
+
+/* |nibblesbits| represents the 2 bits to encode MNIBBLES (0-3)
+ REQUIRES: length > 0
+ REQUIRES: length <= (1 << 24) */
+func encodeMlen(length uint, bits *uint64, numbits *uint, nibblesbits *uint64) {
+ var lg uint
+ if length == 1 {
+ lg = 1
+ } else {
+ lg = uint(log2FloorNonZero(uint(uint32(length-1)))) + 1
+ }
+ var tmp uint
+ if lg < 16 {
+ tmp = 16
+ } else {
+ tmp = (lg + 3)
+ }
+ var mnibbles uint = tmp / 4
+ assert(length > 0)
+ assert(length <= 1<<24)
+ assert(lg <= 24)
+ *nibblesbits = uint64(mnibbles) - 4
+ *numbits = mnibbles * 4
+ *bits = uint64(length) - 1
+}
+
+func storeCommandExtra(cmd *command, storage_ix *uint, storage []byte) {
+ var copylen_code uint32 = commandCopyLenCode(cmd)
+ var inscode uint16 = getInsertLengthCode(uint(cmd.insert_len_))
+ var copycode uint16 = getCopyLengthCode(uint(copylen_code))
+ var insnumextra uint32 = getInsertExtra(inscode)
+ var insextraval uint64 = uint64(cmd.insert_len_) - uint64(getInsertBase(inscode))
+ var copyextraval uint64 = uint64(copylen_code) - uint64(getCopyBase(copycode))
+ var bits uint64 = copyextraval< 0
+ REQUIRES: length <= (1 << 24) */
+func storeCompressedMetaBlockHeader(is_final_block bool, length uint, storage_ix *uint, storage []byte) {
+ var lenbits uint64
+ var nlenbits uint
+ var nibblesbits uint64
+ var is_final uint64
+ if is_final_block {
+ is_final = 1
+ } else {
+ is_final = 0
+ }
+
+ /* Write ISLAST bit. */
+ writeBits(1, is_final, storage_ix, storage)
+
+ /* Write ISEMPTY bit. */
+ if is_final_block {
+ writeBits(1, 0, storage_ix, storage)
+ }
+
+ encodeMlen(length, &lenbits, &nlenbits, &nibblesbits)
+ writeBits(2, nibblesbits, storage_ix, storage)
+ writeBits(nlenbits, lenbits, storage_ix, storage)
+
+ if !is_final_block {
+ /* Write ISUNCOMPRESSED bit. */
+ writeBits(1, 0, storage_ix, storage)
+ }
+}
+
+/* Stores the uncompressed meta-block header.
+ REQUIRES: length > 0
+ REQUIRES: length <= (1 << 24) */
+func storeUncompressedMetaBlockHeader(length uint, storage_ix *uint, storage []byte) {
+ var lenbits uint64
+ var nlenbits uint
+ var nibblesbits uint64
+
+ /* Write ISLAST bit.
+ Uncompressed block cannot be the last one, so set to 0. */
+ writeBits(1, 0, storage_ix, storage)
+
+ encodeMlen(length, &lenbits, &nlenbits, &nibblesbits)
+ writeBits(2, nibblesbits, storage_ix, storage)
+ writeBits(nlenbits, lenbits, storage_ix, storage)
+
+ /* Write ISUNCOMPRESSED bit. */
+ writeBits(1, 1, storage_ix, storage)
+}
+
+var storeHuffmanTreeOfHuffmanTreeToBitMask_kStorageOrder = [codeLengthCodes]byte{1, 2, 3, 4, 0, 5, 17, 6, 16, 7, 8, 9, 10, 11, 12, 13, 14, 15}
+
+var storeHuffmanTreeOfHuffmanTreeToBitMask_kHuffmanBitLengthHuffmanCodeSymbols = [6]byte{0, 7, 3, 2, 1, 15}
+var storeHuffmanTreeOfHuffmanTreeToBitMask_kHuffmanBitLengthHuffmanCodeBitLengths = [6]byte{2, 4, 3, 2, 2, 4}
+
+func storeHuffmanTreeOfHuffmanTreeToBitMask(num_codes int, code_length_bitdepth []byte, storage_ix *uint, storage []byte) {
+ var skip_some uint = 0
+ var codes_to_store uint = codeLengthCodes
+ /* The bit lengths of the Huffman code over the code length alphabet
+ are compressed with the following static Huffman code:
+ Symbol Code
+ ------ ----
+ 0 00
+ 1 1110
+ 2 110
+ 3 01
+ 4 10
+ 5 1111 */
+
+ /* Throw away trailing zeros: */
+ if num_codes > 1 {
+ for ; codes_to_store > 0; codes_to_store-- {
+ if code_length_bitdepth[storeHuffmanTreeOfHuffmanTreeToBitMask_kStorageOrder[codes_to_store-1]] != 0 {
+ break
+ }
+ }
+ }
+
+ if code_length_bitdepth[storeHuffmanTreeOfHuffmanTreeToBitMask_kStorageOrder[0]] == 0 && code_length_bitdepth[storeHuffmanTreeOfHuffmanTreeToBitMask_kStorageOrder[1]] == 0 {
+ skip_some = 2 /* skips two. */
+ if code_length_bitdepth[storeHuffmanTreeOfHuffmanTreeToBitMask_kStorageOrder[2]] == 0 {
+ skip_some = 3 /* skips three. */
+ }
+ }
+
+ writeBits(2, uint64(skip_some), storage_ix, storage)
+ {
+ var i uint
+ for i = skip_some; i < codes_to_store; i++ {
+ var l uint = uint(code_length_bitdepth[storeHuffmanTreeOfHuffmanTreeToBitMask_kStorageOrder[i]])
+ writeBits(uint(storeHuffmanTreeOfHuffmanTreeToBitMask_kHuffmanBitLengthHuffmanCodeBitLengths[l]), uint64(storeHuffmanTreeOfHuffmanTreeToBitMask_kHuffmanBitLengthHuffmanCodeSymbols[l]), storage_ix, storage)
+ }
+ }
+}
+
+func storeHuffmanTreeToBitMask(huffman_tree_size uint, huffman_tree []byte, huffman_tree_extra_bits []byte, code_length_bitdepth []byte, code_length_bitdepth_symbols []uint16, storage_ix *uint, storage []byte) {
+ var i uint
+ for i = 0; i < huffman_tree_size; i++ {
+ var ix uint = uint(huffman_tree[i])
+ writeBits(uint(code_length_bitdepth[ix]), uint64(code_length_bitdepth_symbols[ix]), storage_ix, storage)
+
+ /* Extra bits */
+ switch ix {
+ case repeatPreviousCodeLength:
+ writeBits(2, uint64(huffman_tree_extra_bits[i]), storage_ix, storage)
+
+ case repeatZeroCodeLength:
+ writeBits(3, uint64(huffman_tree_extra_bits[i]), storage_ix, storage)
+ }
+ }
+}
+
+func storeSimpleHuffmanTree(depths []byte, symbols []uint, num_symbols uint, max_bits uint, storage_ix *uint, storage []byte) {
+ /* value of 1 indicates a simple Huffman code */
+ writeBits(2, 1, storage_ix, storage)
+
+ writeBits(2, uint64(num_symbols)-1, storage_ix, storage) /* NSYM - 1 */
+ {
+ /* Sort */
+ var i uint
+ for i = 0; i < num_symbols; i++ {
+ var j uint
+ for j = i + 1; j < num_symbols; j++ {
+ if depths[symbols[j]] < depths[symbols[i]] {
+ var tmp uint = symbols[j]
+ symbols[j] = symbols[i]
+ symbols[i] = tmp
+ }
+ }
+ }
+ }
+
+ if num_symbols == 2 {
+ writeBits(max_bits, uint64(symbols[0]), storage_ix, storage)
+ writeBits(max_bits, uint64(symbols[1]), storage_ix, storage)
+ } else if num_symbols == 3 {
+ writeBits(max_bits, uint64(symbols[0]), storage_ix, storage)
+ writeBits(max_bits, uint64(symbols[1]), storage_ix, storage)
+ writeBits(max_bits, uint64(symbols[2]), storage_ix, storage)
+ } else {
+ writeBits(max_bits, uint64(symbols[0]), storage_ix, storage)
+ writeBits(max_bits, uint64(symbols[1]), storage_ix, storage)
+ writeBits(max_bits, uint64(symbols[2]), storage_ix, storage)
+ writeBits(max_bits, uint64(symbols[3]), storage_ix, storage)
+
+ /* tree-select */
+ var tmp int
+ if depths[symbols[0]] == 1 {
+ tmp = 1
+ } else {
+ tmp = 0
+ }
+ writeBits(1, uint64(tmp), storage_ix, storage)
+ }
+}
+
+/* num = alphabet size
+ depths = symbol depths */
+func storeHuffmanTree(depths []byte, num uint, tree []huffmanTree, storage_ix *uint, storage []byte) {
+ var huffman_tree [numCommandSymbols]byte
+ var huffman_tree_extra_bits [numCommandSymbols]byte
+ var huffman_tree_size uint = 0
+ var code_length_bitdepth = [codeLengthCodes]byte{0}
+ var code_length_bitdepth_symbols [codeLengthCodes]uint16
+ var huffman_tree_histogram = [codeLengthCodes]uint32{0}
+ var i uint
+ var num_codes int = 0
+ /* Write the Huffman tree into the brotli-representation.
+ The command alphabet is the largest, so this allocation will fit all
+ alphabets. */
+
+ var code uint = 0
+
+ assert(num <= numCommandSymbols)
+
+ writeHuffmanTree(depths, num, &huffman_tree_size, huffman_tree[:], huffman_tree_extra_bits[:])
+
+ /* Calculate the statistics of the Huffman tree in brotli-representation. */
+ for i = 0; i < huffman_tree_size; i++ {
+ huffman_tree_histogram[huffman_tree[i]]++
+ }
+
+ for i = 0; i < codeLengthCodes; i++ {
+ if huffman_tree_histogram[i] != 0 {
+ if num_codes == 0 {
+ code = i
+ num_codes = 1
+ } else if num_codes == 1 {
+ num_codes = 2
+ break
+ }
+ }
+ }
+
+ /* Calculate another Huffman tree to use for compressing both the
+ earlier Huffman tree with. */
+ createHuffmanTree(huffman_tree_histogram[:], codeLengthCodes, 5, tree, code_length_bitdepth[:])
+
+ convertBitDepthsToSymbols(code_length_bitdepth[:], codeLengthCodes, code_length_bitdepth_symbols[:])
+
+ /* Now, we have all the data, let's start storing it */
+ storeHuffmanTreeOfHuffmanTreeToBitMask(num_codes, code_length_bitdepth[:], storage_ix, storage)
+
+ if num_codes == 1 {
+ code_length_bitdepth[code] = 0
+ }
+
+ /* Store the real Huffman tree now. */
+ storeHuffmanTreeToBitMask(huffman_tree_size, huffman_tree[:], huffman_tree_extra_bits[:], code_length_bitdepth[:], code_length_bitdepth_symbols[:], storage_ix, storage)
+}
+
+/* Builds a Huffman tree from histogram[0:length] into depth[0:length] and
+ bits[0:length] and stores the encoded tree to the bit stream. */
+func buildAndStoreHuffmanTree(histogram []uint32, histogram_length uint, alphabet_size uint, tree []huffmanTree, depth []byte, bits []uint16, storage_ix *uint, storage []byte) {
+ var count uint = 0
+ var s4 = [4]uint{0}
+ var i uint
+ var max_bits uint = 0
+ for i = 0; i < histogram_length; i++ {
+ if histogram[i] != 0 {
+ if count < 4 {
+ s4[count] = i
+ } else if count > 4 {
+ break
+ }
+
+ count++
+ }
+ }
+ {
+ var max_bits_counter uint = alphabet_size - 1
+ for max_bits_counter != 0 {
+ max_bits_counter >>= 1
+ max_bits++
+ }
+ }
+
+ if count <= 1 {
+ writeBits(4, 1, storage_ix, storage)
+ writeBits(max_bits, uint64(s4[0]), storage_ix, storage)
+ depth[s4[0]] = 0
+ bits[s4[0]] = 0
+ return
+ }
+
+ for i := 0; i < int(histogram_length); i++ {
+ depth[i] = 0
+ }
+ createHuffmanTree(histogram, histogram_length, 15, tree, depth)
+ convertBitDepthsToSymbols(depth, histogram_length, bits)
+
+ if count <= 4 {
+ storeSimpleHuffmanTree(depth, s4[:], count, max_bits, storage_ix, storage)
+ } else {
+ storeHuffmanTree(depth, histogram_length, tree, storage_ix, storage)
+ }
+}
+
+func sortHuffmanTree1(v0 huffmanTree, v1 huffmanTree) bool {
+ return v0.total_count_ < v1.total_count_
+}
+
+var huffmanTreePool sync.Pool
+
+func buildAndStoreHuffmanTreeFast(histogram []uint32, histogram_total uint, max_bits uint, depth []byte, bits []uint16, storage_ix *uint, storage []byte) {
+ var count uint = 0
+ var symbols = [4]uint{0}
+ var length uint = 0
+ var total uint = histogram_total
+ for total != 0 {
+ if histogram[length] != 0 {
+ if count < 4 {
+ symbols[count] = length
+ }
+
+ count++
+ total -= uint(histogram[length])
+ }
+
+ length++
+ }
+
+ if count <= 1 {
+ writeBits(4, 1, storage_ix, storage)
+ writeBits(max_bits, uint64(symbols[0]), storage_ix, storage)
+ depth[symbols[0]] = 0
+ bits[symbols[0]] = 0
+ return
+ }
+
+ for i := 0; i < int(length); i++ {
+ depth[i] = 0
+ }
+ {
+ var max_tree_size uint = 2*length + 1
+ tree, _ := huffmanTreePool.Get().(*[]huffmanTree)
+ if tree == nil || cap(*tree) < int(max_tree_size) {
+ tmp := make([]huffmanTree, max_tree_size)
+ tree = &tmp
+ } else {
+ *tree = (*tree)[:max_tree_size]
+ }
+ var count_limit uint32
+ for count_limit = 1; ; count_limit *= 2 {
+ var node int = 0
+ var l uint
+ for l = length; l != 0; {
+ l--
+ if histogram[l] != 0 {
+ if histogram[l] >= count_limit {
+ initHuffmanTree(&(*tree)[node:][0], histogram[l], -1, int16(l))
+ } else {
+ initHuffmanTree(&(*tree)[node:][0], count_limit, -1, int16(l))
+ }
+
+ node++
+ }
+ }
+ {
+ var n int = node
+ /* Points to the next leaf node. */ /* Points to the next non-leaf node. */
+ var sentinel huffmanTree
+ var i int = 0
+ var j int = n + 1
+ var k int
+
+ sortHuffmanTreeItems(*tree, uint(n), huffmanTreeComparator(sortHuffmanTree1))
+
+ /* The nodes are:
+ [0, n): the sorted leaf nodes that we start with.
+ [n]: we add a sentinel here.
+ [n + 1, 2n): new parent nodes are added here, starting from
+ (n+1). These are naturally in ascending order.
+ [2n]: we add a sentinel at the end as well.
+ There will be (2n+1) elements at the end. */
+ initHuffmanTree(&sentinel, math.MaxUint32, -1, -1)
+
+ (*tree)[node] = sentinel
+ node++
+ (*tree)[node] = sentinel
+ node++
+
+ for k = n - 1; k > 0; k-- {
+ var left int
+ var right int
+ if (*tree)[i].total_count_ <= (*tree)[j].total_count_ {
+ left = i
+ i++
+ } else {
+ left = j
+ j++
+ }
+
+ if (*tree)[i].total_count_ <= (*tree)[j].total_count_ {
+ right = i
+ i++
+ } else {
+ right = j
+ j++
+ }
+
+ /* The sentinel node becomes the parent node. */
+ (*tree)[node-1].total_count_ = (*tree)[left].total_count_ + (*tree)[right].total_count_
+
+ (*tree)[node-1].index_left_ = int16(left)
+ (*tree)[node-1].index_right_or_value_ = int16(right)
+
+ /* Add back the last sentinel node. */
+ (*tree)[node] = sentinel
+ node++
+ }
+
+ if setDepth(2*n-1, *tree, depth, 14) {
+ /* We need to pack the Huffman tree in 14 bits. If this was not
+ successful, add fake entities to the lowest values and retry. */
+ break
+ }
+ }
+ }
+
+ huffmanTreePool.Put(tree)
+ }
+
+ convertBitDepthsToSymbols(depth, length, bits)
+ if count <= 4 {
+ var i uint
+
+ /* value of 1 indicates a simple Huffman code */
+ writeBits(2, 1, storage_ix, storage)
+
+ writeBits(2, uint64(count)-1, storage_ix, storage) /* NSYM - 1 */
+
+ /* Sort */
+ for i = 0; i < count; i++ {
+ var j uint
+ for j = i + 1; j < count; j++ {
+ if depth[symbols[j]] < depth[symbols[i]] {
+ var tmp uint = symbols[j]
+ symbols[j] = symbols[i]
+ symbols[i] = tmp
+ }
+ }
+ }
+
+ if count == 2 {
+ writeBits(max_bits, uint64(symbols[0]), storage_ix, storage)
+ writeBits(max_bits, uint64(symbols[1]), storage_ix, storage)
+ } else if count == 3 {
+ writeBits(max_bits, uint64(symbols[0]), storage_ix, storage)
+ writeBits(max_bits, uint64(symbols[1]), storage_ix, storage)
+ writeBits(max_bits, uint64(symbols[2]), storage_ix, storage)
+ } else {
+ writeBits(max_bits, uint64(symbols[0]), storage_ix, storage)
+ writeBits(max_bits, uint64(symbols[1]), storage_ix, storage)
+ writeBits(max_bits, uint64(symbols[2]), storage_ix, storage)
+ writeBits(max_bits, uint64(symbols[3]), storage_ix, storage)
+
+ /* tree-select */
+ var tmp int
+ if depth[symbols[0]] == 1 {
+ tmp = 1
+ } else {
+ tmp = 0
+ }
+ writeBits(1, uint64(tmp), storage_ix, storage)
+ }
+ } else {
+ var previous_value byte = 8
+ var i uint
+
+ /* Complex Huffman Tree */
+ storeStaticCodeLengthCode(storage_ix, storage)
+
+ /* Actual RLE coding. */
+ for i = 0; i < length; {
+ var value byte = depth[i]
+ var reps uint = 1
+ var k uint
+ for k = i + 1; k < length && depth[k] == value; k++ {
+ reps++
+ }
+
+ i += reps
+ if value == 0 {
+ writeBits(uint(kZeroRepsDepth[reps]), kZeroRepsBits[reps], storage_ix, storage)
+ } else {
+ if previous_value != value {
+ writeBits(uint(kCodeLengthDepth[value]), uint64(kCodeLengthBits[value]), storage_ix, storage)
+ reps--
+ }
+
+ if reps < 3 {
+ for reps != 0 {
+ reps--
+ writeBits(uint(kCodeLengthDepth[value]), uint64(kCodeLengthBits[value]), storage_ix, storage)
+ }
+ } else {
+ reps -= 3
+ writeBits(uint(kNonZeroRepsDepth[reps]), kNonZeroRepsBits[reps], storage_ix, storage)
+ }
+
+ previous_value = value
+ }
+ }
+ }
+}
+
+func indexOf(v []byte, v_size uint, value byte) uint {
+ var i uint = 0
+ for ; i < v_size; i++ {
+ if v[i] == value {
+ return i
+ }
+ }
+
+ return i
+}
+
+func moveToFront(v []byte, index uint) {
+ var value byte = v[index]
+ var i uint
+ for i = index; i != 0; i-- {
+ v[i] = v[i-1]
+ }
+
+ v[0] = value
+}
+
+func moveToFrontTransform(v_in []uint32, v_size uint, v_out []uint32) {
+ var i uint
+ var mtf [256]byte
+ var max_value uint32
+ if v_size == 0 {
+ return
+ }
+
+ max_value = v_in[0]
+ for i = 1; i < v_size; i++ {
+ if v_in[i] > max_value {
+ max_value = v_in[i]
+ }
+ }
+
+ assert(max_value < 256)
+ for i = 0; uint32(i) <= max_value; i++ {
+ mtf[i] = byte(i)
+ }
+ {
+ var mtf_size uint = uint(max_value + 1)
+ for i = 0; i < v_size; i++ {
+ var index uint = indexOf(mtf[:], mtf_size, byte(v_in[i]))
+ assert(index < mtf_size)
+ v_out[i] = uint32(index)
+ moveToFront(mtf[:], index)
+ }
+ }
+}
+
+/* Finds runs of zeros in v[0..in_size) and replaces them with a prefix code of
+ the run length plus extra bits (lower 9 bits is the prefix code and the rest
+ are the extra bits). Non-zero values in v[] are shifted by
+ *max_length_prefix. Will not create prefix codes bigger than the initial
+ value of *max_run_length_prefix. The prefix code of run length L is simply
+ Log2Floor(L) and the number of extra bits is the same as the prefix code. */
+func runLengthCodeZeros(in_size uint, v []uint32, out_size *uint, max_run_length_prefix *uint32) {
+ var max_reps uint32 = 0
+ var i uint
+ var max_prefix uint32
+ for i = 0; i < in_size; {
+ var reps uint32 = 0
+ for ; i < in_size && v[i] != 0; i++ {
+ }
+ for ; i < in_size && v[i] == 0; i++ {
+ reps++
+ }
+
+ max_reps = brotli_max_uint32_t(reps, max_reps)
+ }
+
+ if max_reps > 0 {
+ max_prefix = log2FloorNonZero(uint(max_reps))
+ } else {
+ max_prefix = 0
+ }
+ max_prefix = brotli_min_uint32_t(max_prefix, *max_run_length_prefix)
+ *max_run_length_prefix = max_prefix
+ *out_size = 0
+ for i = 0; i < in_size; {
+ assert(*out_size <= i)
+ if v[i] != 0 {
+ v[*out_size] = v[i] + *max_run_length_prefix
+ i++
+ (*out_size)++
+ } else {
+ var reps uint32 = 1
+ var k uint
+ for k = i + 1; k < in_size && v[k] == 0; k++ {
+ reps++
+ }
+
+ i += uint(reps)
+ for reps != 0 {
+ if reps < 2< 0)
+ writeSingleBit(use_rle, storage_ix, storage)
+ if use_rle {
+ writeBits(4, uint64(max_run_length_prefix)-1, storage_ix, storage)
+ }
+ }
+
+ buildAndStoreHuffmanTree(histogram[:], uint(uint32(num_clusters)+max_run_length_prefix), uint(uint32(num_clusters)+max_run_length_prefix), tree, depths[:], bits[:], storage_ix, storage)
+ for i = 0; i < num_rle_symbols; i++ {
+ var rle_symbol uint32 = rle_symbols[i] & encodeContextMap_kSymbolMask
+ var extra_bits_val uint32 = rle_symbols[i] >> symbolBits
+ writeBits(uint(depths[rle_symbol]), uint64(bits[rle_symbol]), storage_ix, storage)
+ if rle_symbol > 0 && rle_symbol <= max_run_length_prefix {
+ writeBits(uint(rle_symbol), uint64(extra_bits_val), storage_ix, storage)
+ }
+ }
+
+ writeBits(1, 1, storage_ix, storage) /* use move-to-front */
+ rle_symbols = nil
+}
+
+/* Stores the block switch command with index block_ix to the bit stream. */
+func storeBlockSwitch(code *blockSplitCode, block_len uint32, block_type byte, is_first_block bool, storage_ix *uint, storage []byte) {
+ var typecode uint = nextBlockTypeCode(&code.type_code_calculator, block_type)
+ var lencode uint
+ var len_nextra uint32
+ var len_extra uint32
+ if !is_first_block {
+ writeBits(uint(code.type_depths[typecode]), uint64(code.type_bits[typecode]), storage_ix, storage)
+ }
+
+ getBlockLengthPrefixCode(block_len, &lencode, &len_nextra, &len_extra)
+
+ writeBits(uint(code.length_depths[lencode]), uint64(code.length_bits[lencode]), storage_ix, storage)
+ writeBits(uint(len_nextra), uint64(len_extra), storage_ix, storage)
+}
+
+/* Builds a BlockSplitCode data structure from the block split given by the
+ vector of block types and block lengths and stores it to the bit stream. */
+func buildAndStoreBlockSplitCode(types []byte, lengths []uint32, num_blocks uint, num_types uint, tree []huffmanTree, code *blockSplitCode, storage_ix *uint, storage []byte) {
+ var type_histo [maxBlockTypeSymbols]uint32
+ var length_histo [numBlockLenSymbols]uint32
+ var i uint
+ var type_code_calculator blockTypeCodeCalculator
+ for i := 0; i < int(num_types+2); i++ {
+ type_histo[i] = 0
+ }
+ length_histo = [numBlockLenSymbols]uint32{}
+ initBlockTypeCodeCalculator(&type_code_calculator)
+ for i = 0; i < num_blocks; i++ {
+ var type_code uint = nextBlockTypeCode(&type_code_calculator, types[i])
+ if i != 0 {
+ type_histo[type_code]++
+ }
+ length_histo[blockLengthPrefixCode(lengths[i])]++
+ }
+
+ storeVarLenUint8(num_types-1, storage_ix, storage)
+ if num_types > 1 { /* TODO: else? could StoreBlockSwitch occur? */
+ buildAndStoreHuffmanTree(type_histo[0:], num_types+2, num_types+2, tree, code.type_depths[0:], code.type_bits[0:], storage_ix, storage)
+ buildAndStoreHuffmanTree(length_histo[0:], numBlockLenSymbols, numBlockLenSymbols, tree, code.length_depths[0:], code.length_bits[0:], storage_ix, storage)
+ storeBlockSwitch(code, lengths[0], types[0], true, storage_ix, storage)
+ }
+}
+
+/* Stores a context map where the histogram type is always the block type. */
+func storeTrivialContextMap(num_types uint, context_bits uint, tree []huffmanTree, storage_ix *uint, storage []byte) {
+ storeVarLenUint8(num_types-1, storage_ix, storage)
+ if num_types > 1 {
+ var repeat_code uint = context_bits - 1
+ var repeat_bits uint = (1 << repeat_code) - 1
+ var alphabet_size uint = num_types + repeat_code
+ var histogram [maxContextMapSymbols]uint32
+ var depths [maxContextMapSymbols]byte
+ var bits [maxContextMapSymbols]uint16
+ var i uint
+ for i := 0; i < int(alphabet_size); i++ {
+ histogram[i] = 0
+ }
+
+ /* Write RLEMAX. */
+ writeBits(1, 1, storage_ix, storage)
+
+ writeBits(4, uint64(repeat_code)-1, storage_ix, storage)
+ histogram[repeat_code] = uint32(num_types)
+ histogram[0] = 1
+ for i = context_bits; i < alphabet_size; i++ {
+ histogram[i] = 1
+ }
+
+ buildAndStoreHuffmanTree(histogram[:], alphabet_size, alphabet_size, tree, depths[:], bits[:], storage_ix, storage)
+ for i = 0; i < num_types; i++ {
+ var tmp uint
+ if i == 0 {
+ tmp = 0
+ } else {
+ tmp = i + context_bits - 1
+ }
+ var code uint = tmp
+ writeBits(uint(depths[code]), uint64(bits[code]), storage_ix, storage)
+ writeBits(uint(depths[repeat_code]), uint64(bits[repeat_code]), storage_ix, storage)
+ writeBits(repeat_code, uint64(repeat_bits), storage_ix, storage)
+ }
+
+ /* Write IMTF (inverse-move-to-front) bit. */
+ writeBits(1, 1, storage_ix, storage)
+ }
+}
+
+/* Manages the encoding of one block category (literal, command or distance). */
+type blockEncoder struct {
+ histogram_length_ uint
+ num_block_types_ uint
+ block_types_ []byte
+ block_lengths_ []uint32
+ num_blocks_ uint
+ block_split_code_ blockSplitCode
+ block_ix_ uint
+ block_len_ uint
+ entropy_ix_ uint
+ depths_ []byte
+ bits_ []uint16
+}
+
+var blockEncoderPool sync.Pool
+
+func getBlockEncoder(histogram_length uint, num_block_types uint, block_types []byte, block_lengths []uint32, num_blocks uint) *blockEncoder {
+ self, _ := blockEncoderPool.Get().(*blockEncoder)
+
+ if self != nil {
+ self.block_ix_ = 0
+ self.entropy_ix_ = 0
+ self.depths_ = self.depths_[:0]
+ self.bits_ = self.bits_[:0]
+ } else {
+ self = &blockEncoder{}
+ }
+
+ self.histogram_length_ = histogram_length
+ self.num_block_types_ = num_block_types
+ self.block_types_ = block_types
+ self.block_lengths_ = block_lengths
+ self.num_blocks_ = num_blocks
+ initBlockTypeCodeCalculator(&self.block_split_code_.type_code_calculator)
+ if num_blocks == 0 {
+ self.block_len_ = 0
+ } else {
+ self.block_len_ = uint(block_lengths[0])
+ }
+
+ return self
+}
+
+func cleanupBlockEncoder(self *blockEncoder) {
+ blockEncoderPool.Put(self)
+}
+
+/* Creates entropy codes of block lengths and block types and stores them
+ to the bit stream. */
+func buildAndStoreBlockSwitchEntropyCodes(self *blockEncoder, tree []huffmanTree, storage_ix *uint, storage []byte) {
+ buildAndStoreBlockSplitCode(self.block_types_, self.block_lengths_, self.num_blocks_, self.num_block_types_, tree, &self.block_split_code_, storage_ix, storage)
+}
+
+/* Stores the next symbol with the entropy code of the current block type.
+ Updates the block type and block length at block boundaries. */
+func storeSymbol(self *blockEncoder, symbol uint, storage_ix *uint, storage []byte) {
+ if self.block_len_ == 0 {
+ self.block_ix_++
+ var block_ix uint = self.block_ix_
+ var block_len uint32 = self.block_lengths_[block_ix]
+ var block_type byte = self.block_types_[block_ix]
+ self.block_len_ = uint(block_len)
+ self.entropy_ix_ = uint(block_type) * self.histogram_length_
+ storeBlockSwitch(&self.block_split_code_, block_len, block_type, false, storage_ix, storage)
+ }
+
+ self.block_len_--
+ {
+ var ix uint = self.entropy_ix_ + symbol
+ writeBits(uint(self.depths_[ix]), uint64(self.bits_[ix]), storage_ix, storage)
+ }
+}
+
+/* Stores the next symbol with the entropy code of the current block type and
+ context value.
+ Updates the block type and block length at block boundaries. */
+func storeSymbolWithContext(self *blockEncoder, symbol uint, context uint, context_map []uint32, storage_ix *uint, storage []byte, context_bits uint) {
+ if self.block_len_ == 0 {
+ self.block_ix_++
+ var block_ix uint = self.block_ix_
+ var block_len uint32 = self.block_lengths_[block_ix]
+ var block_type byte = self.block_types_[block_ix]
+ self.block_len_ = uint(block_len)
+ self.entropy_ix_ = uint(block_type) << context_bits
+ storeBlockSwitch(&self.block_split_code_, block_len, block_type, false, storage_ix, storage)
+ }
+
+ self.block_len_--
+ {
+ var histo_ix uint = uint(context_map[self.entropy_ix_+context])
+ var ix uint = histo_ix*self.histogram_length_ + symbol
+ writeBits(uint(self.depths_[ix]), uint64(self.bits_[ix]), storage_ix, storage)
+ }
+}
+
+func buildAndStoreEntropyCodesLiteral(self *blockEncoder, histograms []histogramLiteral, histograms_size uint, alphabet_size uint, tree []huffmanTree, storage_ix *uint, storage []byte) {
+ var table_size uint = histograms_size * self.histogram_length_
+ if cap(self.depths_) < int(table_size) {
+ self.depths_ = make([]byte, table_size)
+ } else {
+ self.depths_ = self.depths_[:table_size]
+ }
+ if cap(self.bits_) < int(table_size) {
+ self.bits_ = make([]uint16, table_size)
+ } else {
+ self.bits_ = self.bits_[:table_size]
+ }
+ {
+ var i uint
+ for i = 0; i < histograms_size; i++ {
+ var ix uint = i * self.histogram_length_
+ buildAndStoreHuffmanTree(histograms[i].data_[0:], self.histogram_length_, alphabet_size, tree, self.depths_[ix:], self.bits_[ix:], storage_ix, storage)
+ }
+ }
+}
+
+func buildAndStoreEntropyCodesCommand(self *blockEncoder, histograms []histogramCommand, histograms_size uint, alphabet_size uint, tree []huffmanTree, storage_ix *uint, storage []byte) {
+ var table_size uint = histograms_size * self.histogram_length_
+ if cap(self.depths_) < int(table_size) {
+ self.depths_ = make([]byte, table_size)
+ } else {
+ self.depths_ = self.depths_[:table_size]
+ }
+ if cap(self.bits_) < int(table_size) {
+ self.bits_ = make([]uint16, table_size)
+ } else {
+ self.bits_ = self.bits_[:table_size]
+ }
+ {
+ var i uint
+ for i = 0; i < histograms_size; i++ {
+ var ix uint = i * self.histogram_length_
+ buildAndStoreHuffmanTree(histograms[i].data_[0:], self.histogram_length_, alphabet_size, tree, self.depths_[ix:], self.bits_[ix:], storage_ix, storage)
+ }
+ }
+}
+
+func buildAndStoreEntropyCodesDistance(self *blockEncoder, histograms []histogramDistance, histograms_size uint, alphabet_size uint, tree []huffmanTree, storage_ix *uint, storage []byte) {
+ var table_size uint = histograms_size * self.histogram_length_
+ if cap(self.depths_) < int(table_size) {
+ self.depths_ = make([]byte, table_size)
+ } else {
+ self.depths_ = self.depths_[:table_size]
+ }
+ if cap(self.bits_) < int(table_size) {
+ self.bits_ = make([]uint16, table_size)
+ } else {
+ self.bits_ = self.bits_[:table_size]
+ }
+ {
+ var i uint
+ for i = 0; i < histograms_size; i++ {
+ var ix uint = i * self.histogram_length_
+ buildAndStoreHuffmanTree(histograms[i].data_[0:], self.histogram_length_, alphabet_size, tree, self.depths_[ix:], self.bits_[ix:], storage_ix, storage)
+ }
+ }
+}
+
+func jumpToByteBoundary(storage_ix *uint, storage []byte) {
+ *storage_ix = (*storage_ix + 7) &^ 7
+ storage[*storage_ix>>3] = 0
+}
+
+func storeMetaBlock(input []byte, start_pos uint, length uint, mask uint, prev_byte byte, prev_byte2 byte, is_last bool, params *encoderParams, literal_context_mode int, commands []command, mb *metaBlockSplit, storage_ix *uint, storage []byte) {
+ var pos uint = start_pos
+ var i uint
+ var num_distance_symbols uint32 = params.dist.alphabet_size
+ var num_effective_distance_symbols uint32 = num_distance_symbols
+ var tree []huffmanTree
+ var literal_context_lut contextLUT = getContextLUT(literal_context_mode)
+ var dist *distanceParams = ¶ms.dist
+ if params.large_window && num_effective_distance_symbols > numHistogramDistanceSymbols {
+ num_effective_distance_symbols = numHistogramDistanceSymbols
+ }
+
+ storeCompressedMetaBlockHeader(is_last, length, storage_ix, storage)
+
+ tree = make([]huffmanTree, maxHuffmanTreeSize)
+ literal_enc := getBlockEncoder(numLiteralSymbols, mb.literal_split.num_types, mb.literal_split.types, mb.literal_split.lengths, mb.literal_split.num_blocks)
+ command_enc := getBlockEncoder(numCommandSymbols, mb.command_split.num_types, mb.command_split.types, mb.command_split.lengths, mb.command_split.num_blocks)
+ distance_enc := getBlockEncoder(uint(num_effective_distance_symbols), mb.distance_split.num_types, mb.distance_split.types, mb.distance_split.lengths, mb.distance_split.num_blocks)
+
+ buildAndStoreBlockSwitchEntropyCodes(literal_enc, tree, storage_ix, storage)
+ buildAndStoreBlockSwitchEntropyCodes(command_enc, tree, storage_ix, storage)
+ buildAndStoreBlockSwitchEntropyCodes(distance_enc, tree, storage_ix, storage)
+
+ writeBits(2, uint64(dist.distance_postfix_bits), storage_ix, storage)
+ writeBits(4, uint64(dist.num_direct_distance_codes)>>dist.distance_postfix_bits, storage_ix, storage)
+ for i = 0; i < mb.literal_split.num_types; i++ {
+ writeBits(2, uint64(literal_context_mode), storage_ix, storage)
+ }
+
+ if mb.literal_context_map_size == 0 {
+ storeTrivialContextMap(mb.literal_histograms_size, literalContextBits, tree, storage_ix, storage)
+ } else {
+ encodeContextMap(mb.literal_context_map, mb.literal_context_map_size, mb.literal_histograms_size, tree, storage_ix, storage)
+ }
+
+ if mb.distance_context_map_size == 0 {
+ storeTrivialContextMap(mb.distance_histograms_size, distanceContextBits, tree, storage_ix, storage)
+ } else {
+ encodeContextMap(mb.distance_context_map, mb.distance_context_map_size, mb.distance_histograms_size, tree, storage_ix, storage)
+ }
+
+ buildAndStoreEntropyCodesLiteral(literal_enc, mb.literal_histograms, mb.literal_histograms_size, numLiteralSymbols, tree, storage_ix, storage)
+ buildAndStoreEntropyCodesCommand(command_enc, mb.command_histograms, mb.command_histograms_size, numCommandSymbols, tree, storage_ix, storage)
+ buildAndStoreEntropyCodesDistance(distance_enc, mb.distance_histograms, mb.distance_histograms_size, uint(num_distance_symbols), tree, storage_ix, storage)
+ tree = nil
+
+ for _, cmd := range commands {
+ var cmd_code uint = uint(cmd.cmd_prefix_)
+ storeSymbol(command_enc, cmd_code, storage_ix, storage)
+ storeCommandExtra(&cmd, storage_ix, storage)
+ if mb.literal_context_map_size == 0 {
+ var j uint
+ for j = uint(cmd.insert_len_); j != 0; j-- {
+ storeSymbol(literal_enc, uint(input[pos&mask]), storage_ix, storage)
+ pos++
+ }
+ } else {
+ var j uint
+ for j = uint(cmd.insert_len_); j != 0; j-- {
+ var context uint = uint(getContext(prev_byte, prev_byte2, literal_context_lut))
+ var literal byte = input[pos&mask]
+ storeSymbolWithContext(literal_enc, uint(literal), context, mb.literal_context_map, storage_ix, storage, literalContextBits)
+ prev_byte2 = prev_byte
+ prev_byte = literal
+ pos++
+ }
+ }
+
+ pos += uint(commandCopyLen(&cmd))
+ if commandCopyLen(&cmd) != 0 {
+ prev_byte2 = input[(pos-2)&mask]
+ prev_byte = input[(pos-1)&mask]
+ if cmd.cmd_prefix_ >= 128 {
+ var dist_code uint = uint(cmd.dist_prefix_) & 0x3FF
+ var distnumextra uint32 = uint32(cmd.dist_prefix_) >> 10
+ var distextra uint64 = uint64(cmd.dist_extra_)
+ if mb.distance_context_map_size == 0 {
+ storeSymbol(distance_enc, dist_code, storage_ix, storage)
+ } else {
+ var context uint = uint(commandDistanceContext(&cmd))
+ storeSymbolWithContext(distance_enc, dist_code, context, mb.distance_context_map, storage_ix, storage, distanceContextBits)
+ }
+
+ writeBits(uint(distnumextra), distextra, storage_ix, storage)
+ }
+ }
+ }
+
+ cleanupBlockEncoder(distance_enc)
+ cleanupBlockEncoder(command_enc)
+ cleanupBlockEncoder(literal_enc)
+ if is_last {
+ jumpToByteBoundary(storage_ix, storage)
+ }
+}
+
+func buildHistograms(input []byte, start_pos uint, mask uint, commands []command, lit_histo *histogramLiteral, cmd_histo *histogramCommand, dist_histo *histogramDistance) {
+ var pos uint = start_pos
+ for _, cmd := range commands {
+ var j uint
+ histogramAddCommand(cmd_histo, uint(cmd.cmd_prefix_))
+ for j = uint(cmd.insert_len_); j != 0; j-- {
+ histogramAddLiteral(lit_histo, uint(input[pos&mask]))
+ pos++
+ }
+
+ pos += uint(commandCopyLen(&cmd))
+ if commandCopyLen(&cmd) != 0 && cmd.cmd_prefix_ >= 128 {
+ histogramAddDistance(dist_histo, uint(cmd.dist_prefix_)&0x3FF)
+ }
+ }
+}
+
+func storeDataWithHuffmanCodes(input []byte, start_pos uint, mask uint, commands []command, lit_depth []byte, lit_bits []uint16, cmd_depth []byte, cmd_bits []uint16, dist_depth []byte, dist_bits []uint16, storage_ix *uint, storage []byte) {
+ var pos uint = start_pos
+ for _, cmd := range commands {
+ var cmd_code uint = uint(cmd.cmd_prefix_)
+ var j uint
+ writeBits(uint(cmd_depth[cmd_code]), uint64(cmd_bits[cmd_code]), storage_ix, storage)
+ storeCommandExtra(&cmd, storage_ix, storage)
+ for j = uint(cmd.insert_len_); j != 0; j-- {
+ var literal byte = input[pos&mask]
+ writeBits(uint(lit_depth[literal]), uint64(lit_bits[literal]), storage_ix, storage)
+ pos++
+ }
+
+ pos += uint(commandCopyLen(&cmd))
+ if commandCopyLen(&cmd) != 0 && cmd.cmd_prefix_ >= 128 {
+ var dist_code uint = uint(cmd.dist_prefix_) & 0x3FF
+ var distnumextra uint32 = uint32(cmd.dist_prefix_) >> 10
+ var distextra uint32 = cmd.dist_extra_
+ writeBits(uint(dist_depth[dist_code]), uint64(dist_bits[dist_code]), storage_ix, storage)
+ writeBits(uint(distnumextra), uint64(distextra), storage_ix, storage)
+ }
+ }
+}
+
+func storeMetaBlockTrivial(input []byte, start_pos uint, length uint, mask uint, is_last bool, params *encoderParams, commands []command, storage_ix *uint, storage []byte) {
+ var lit_histo histogramLiteral
+ var cmd_histo histogramCommand
+ var dist_histo histogramDistance
+ var lit_depth [numLiteralSymbols]byte
+ var lit_bits [numLiteralSymbols]uint16
+ var cmd_depth [numCommandSymbols]byte
+ var cmd_bits [numCommandSymbols]uint16
+ var dist_depth [maxSimpleDistanceAlphabetSize]byte
+ var dist_bits [maxSimpleDistanceAlphabetSize]uint16
+ var tree []huffmanTree
+ var num_distance_symbols uint32 = params.dist.alphabet_size
+
+ storeCompressedMetaBlockHeader(is_last, length, storage_ix, storage)
+
+ histogramClearLiteral(&lit_histo)
+ histogramClearCommand(&cmd_histo)
+ histogramClearDistance(&dist_histo)
+
+ buildHistograms(input, start_pos, mask, commands, &lit_histo, &cmd_histo, &dist_histo)
+
+ writeBits(13, 0, storage_ix, storage)
+
+ tree = make([]huffmanTree, maxHuffmanTreeSize)
+ buildAndStoreHuffmanTree(lit_histo.data_[:], numLiteralSymbols, numLiteralSymbols, tree, lit_depth[:], lit_bits[:], storage_ix, storage)
+ buildAndStoreHuffmanTree(cmd_histo.data_[:], numCommandSymbols, numCommandSymbols, tree, cmd_depth[:], cmd_bits[:], storage_ix, storage)
+ buildAndStoreHuffmanTree(dist_histo.data_[:], maxSimpleDistanceAlphabetSize, uint(num_distance_symbols), tree, dist_depth[:], dist_bits[:], storage_ix, storage)
+ tree = nil
+ storeDataWithHuffmanCodes(input, start_pos, mask, commands, lit_depth[:], lit_bits[:], cmd_depth[:], cmd_bits[:], dist_depth[:], dist_bits[:], storage_ix, storage)
+ if is_last {
+ jumpToByteBoundary(storage_ix, storage)
+ }
+}
+
+func storeMetaBlockFast(input []byte, start_pos uint, length uint, mask uint, is_last bool, params *encoderParams, commands []command, storage_ix *uint, storage []byte) {
+ var num_distance_symbols uint32 = params.dist.alphabet_size
+ var distance_alphabet_bits uint32 = log2FloorNonZero(uint(num_distance_symbols-1)) + 1
+
+ storeCompressedMetaBlockHeader(is_last, length, storage_ix, storage)
+
+ writeBits(13, 0, storage_ix, storage)
+
+ if len(commands) <= 128 {
+ var histogram = [numLiteralSymbols]uint32{0}
+ var pos uint = start_pos
+ var num_literals uint = 0
+ var lit_depth [numLiteralSymbols]byte
+ var lit_bits [numLiteralSymbols]uint16
+ for _, cmd := range commands {
+ var j uint
+ for j = uint(cmd.insert_len_); j != 0; j-- {
+ histogram[input[pos&mask]]++
+ pos++
+ }
+
+ num_literals += uint(cmd.insert_len_)
+ pos += uint(commandCopyLen(&cmd))
+ }
+
+ buildAndStoreHuffmanTreeFast(histogram[:], num_literals, /* max_bits = */
+ 8, lit_depth[:], lit_bits[:], storage_ix, storage)
+
+ storeStaticCommandHuffmanTree(storage_ix, storage)
+ storeStaticDistanceHuffmanTree(storage_ix, storage)
+ storeDataWithHuffmanCodes(input, start_pos, mask, commands, lit_depth[:], lit_bits[:], kStaticCommandCodeDepth[:], kStaticCommandCodeBits[:], kStaticDistanceCodeDepth[:], kStaticDistanceCodeBits[:], storage_ix, storage)
+ } else {
+ var lit_histo histogramLiteral
+ var cmd_histo histogramCommand
+ var dist_histo histogramDistance
+ var lit_depth [numLiteralSymbols]byte
+ var lit_bits [numLiteralSymbols]uint16
+ var cmd_depth [numCommandSymbols]byte
+ var cmd_bits [numCommandSymbols]uint16
+ var dist_depth [maxSimpleDistanceAlphabetSize]byte
+ var dist_bits [maxSimpleDistanceAlphabetSize]uint16
+ histogramClearLiteral(&lit_histo)
+ histogramClearCommand(&cmd_histo)
+ histogramClearDistance(&dist_histo)
+ buildHistograms(input, start_pos, mask, commands, &lit_histo, &cmd_histo, &dist_histo)
+ buildAndStoreHuffmanTreeFast(lit_histo.data_[:], lit_histo.total_count_, /* max_bits = */
+ 8, lit_depth[:], lit_bits[:], storage_ix, storage)
+
+ buildAndStoreHuffmanTreeFast(cmd_histo.data_[:], cmd_histo.total_count_, /* max_bits = */
+ 10, cmd_depth[:], cmd_bits[:], storage_ix, storage)
+
+ buildAndStoreHuffmanTreeFast(dist_histo.data_[:], dist_histo.total_count_, /* max_bits = */
+ uint(distance_alphabet_bits), dist_depth[:], dist_bits[:], storage_ix, storage)
+
+ storeDataWithHuffmanCodes(input, start_pos, mask, commands, lit_depth[:], lit_bits[:], cmd_depth[:], cmd_bits[:], dist_depth[:], dist_bits[:], storage_ix, storage)
+ }
+
+ if is_last {
+ jumpToByteBoundary(storage_ix, storage)
+ }
+}
+
+/* This is for storing uncompressed blocks (simple raw storage of
+ bytes-as-bytes). */
+func storeUncompressedMetaBlock(is_final_block bool, input []byte, position uint, mask uint, len uint, storage_ix *uint, storage []byte) {
+ var masked_pos uint = position & mask
+ storeUncompressedMetaBlockHeader(uint(len), storage_ix, storage)
+ jumpToByteBoundary(storage_ix, storage)
+
+ if masked_pos+len > mask+1 {
+ var len1 uint = mask + 1 - masked_pos
+ copy(storage[*storage_ix>>3:], input[masked_pos:][:len1])
+ *storage_ix += len1 << 3
+ len -= len1
+ masked_pos = 0
+ }
+
+ copy(storage[*storage_ix>>3:], input[masked_pos:][:len])
+ *storage_ix += uint(len << 3)
+
+ /* We need to clear the next 4 bytes to continue to be
+ compatible with BrotliWriteBits. */
+ writeBitsPrepareStorage(*storage_ix, storage)
+
+ /* Since the uncompressed block itself may not be the final block, add an
+ empty one after this. */
+ if is_final_block {
+ writeBits(1, 1, storage_ix, storage) /* islast */
+ writeBits(1, 1, storage_ix, storage) /* isempty */
+ jumpToByteBoundary(storage_ix, storage)
+ }
+}
diff --git a/vendor/github.com/andybalholm/brotli/cluster.go b/vendor/github.com/andybalholm/brotli/cluster.go
new file mode 100644
index 0000000..df8a328
--- /dev/null
+++ b/vendor/github.com/andybalholm/brotli/cluster.go
@@ -0,0 +1,30 @@
+package brotli
+
+/* Copyright 2013 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Functions for clustering similar histograms together. */
+
+type histogramPair struct {
+ idx1 uint32
+ idx2 uint32
+ cost_combo float64
+ cost_diff float64
+}
+
+func histogramPairIsLess(p1 *histogramPair, p2 *histogramPair) bool {
+ if p1.cost_diff != p2.cost_diff {
+ return p1.cost_diff > p2.cost_diff
+ }
+
+ return (p1.idx2 - p1.idx1) > (p2.idx2 - p2.idx1)
+}
+
+/* Returns entropy reduction of the context map when we combine two clusters. */
+func clusterCostDiff(size_a uint, size_b uint) float64 {
+ var size_c uint = size_a + size_b
+ return float64(size_a)*fastLog2(size_a) + float64(size_b)*fastLog2(size_b) - float64(size_c)*fastLog2(size_c)
+}
diff --git a/vendor/github.com/andybalholm/brotli/cluster_command.go b/vendor/github.com/andybalholm/brotli/cluster_command.go
new file mode 100644
index 0000000..45b569b
--- /dev/null
+++ b/vendor/github.com/andybalholm/brotli/cluster_command.go
@@ -0,0 +1,164 @@
+package brotli
+
+/* Copyright 2013 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Computes the bit cost reduction by combining out[idx1] and out[idx2] and if
+ it is below a threshold, stores the pair (idx1, idx2) in the *pairs queue. */
+func compareAndPushToQueueCommand(out []histogramCommand, cluster_size []uint32, idx1 uint32, idx2 uint32, max_num_pairs uint, pairs []histogramPair, num_pairs *uint) {
+ var is_good_pair bool = false
+ var p histogramPair
+ p.idx2 = 0
+ p.idx1 = p.idx2
+ p.cost_combo = 0
+ p.cost_diff = p.cost_combo
+ if idx1 == idx2 {
+ return
+ }
+
+ if idx2 < idx1 {
+ var t uint32 = idx2
+ idx2 = idx1
+ idx1 = t
+ }
+
+ p.idx1 = idx1
+ p.idx2 = idx2
+ p.cost_diff = 0.5 * clusterCostDiff(uint(cluster_size[idx1]), uint(cluster_size[idx2]))
+ p.cost_diff -= out[idx1].bit_cost_
+ p.cost_diff -= out[idx2].bit_cost_
+
+ if out[idx1].total_count_ == 0 {
+ p.cost_combo = out[idx2].bit_cost_
+ is_good_pair = true
+ } else if out[idx2].total_count_ == 0 {
+ p.cost_combo = out[idx1].bit_cost_
+ is_good_pair = true
+ } else {
+ var threshold float64
+ if *num_pairs == 0 {
+ threshold = 1e99
+ } else {
+ threshold = brotli_max_double(0.0, pairs[0].cost_diff)
+ }
+ var combo histogramCommand = out[idx1]
+ var cost_combo float64
+ histogramAddHistogramCommand(&combo, &out[idx2])
+ cost_combo = populationCostCommand(&combo)
+ if cost_combo < threshold-p.cost_diff {
+ p.cost_combo = cost_combo
+ is_good_pair = true
+ }
+ }
+
+ if is_good_pair {
+ p.cost_diff += p.cost_combo
+ if *num_pairs > 0 && histogramPairIsLess(&pairs[0], &p) {
+ /* Replace the top of the queue if needed. */
+ if *num_pairs < max_num_pairs {
+ pairs[*num_pairs] = pairs[0]
+ (*num_pairs)++
+ }
+
+ pairs[0] = p
+ } else if *num_pairs < max_num_pairs {
+ pairs[*num_pairs] = p
+ (*num_pairs)++
+ }
+ }
+}
+
+func histogramCombineCommand(out []histogramCommand, cluster_size []uint32, symbols []uint32, clusters []uint32, pairs []histogramPair, num_clusters uint, symbols_size uint, max_clusters uint, max_num_pairs uint) uint {
+ var cost_diff_threshold float64 = 0.0
+ var min_cluster_size uint = 1
+ var num_pairs uint = 0
+ {
+ /* We maintain a vector of histogram pairs, with the property that the pair
+ with the maximum bit cost reduction is the first. */
+ var idx1 uint
+ for idx1 = 0; idx1 < num_clusters; idx1++ {
+ var idx2 uint
+ for idx2 = idx1 + 1; idx2 < num_clusters; idx2++ {
+ compareAndPushToQueueCommand(out, cluster_size, clusters[idx1], clusters[idx2], max_num_pairs, pairs[0:], &num_pairs)
+ }
+ }
+ }
+
+ for num_clusters > min_cluster_size {
+ var best_idx1 uint32
+ var best_idx2 uint32
+ var i uint
+ if pairs[0].cost_diff >= cost_diff_threshold {
+ cost_diff_threshold = 1e99
+ min_cluster_size = max_clusters
+ continue
+ }
+
+ /* Take the best pair from the top of heap. */
+ best_idx1 = pairs[0].idx1
+
+ best_idx2 = pairs[0].idx2
+ histogramAddHistogramCommand(&out[best_idx1], &out[best_idx2])
+ out[best_idx1].bit_cost_ = pairs[0].cost_combo
+ cluster_size[best_idx1] += cluster_size[best_idx2]
+ for i = 0; i < symbols_size; i++ {
+ if symbols[i] == best_idx2 {
+ symbols[i] = best_idx1
+ }
+ }
+
+ for i = 0; i < num_clusters; i++ {
+ if clusters[i] == best_idx2 {
+ copy(clusters[i:], clusters[i+1:][:num_clusters-i-1])
+ break
+ }
+ }
+
+ num_clusters--
+ {
+ /* Remove pairs intersecting the just combined best pair. */
+ var copy_to_idx uint = 0
+ for i = 0; i < num_pairs; i++ {
+ var p *histogramPair = &pairs[i]
+ if p.idx1 == best_idx1 || p.idx2 == best_idx1 || p.idx1 == best_idx2 || p.idx2 == best_idx2 {
+ /* Remove invalid pair from the queue. */
+ continue
+ }
+
+ if histogramPairIsLess(&pairs[0], p) {
+ /* Replace the top of the queue if needed. */
+ var front histogramPair = pairs[0]
+ pairs[0] = *p
+ pairs[copy_to_idx] = front
+ } else {
+ pairs[copy_to_idx] = *p
+ }
+
+ copy_to_idx++
+ }
+
+ num_pairs = copy_to_idx
+ }
+
+ /* Push new pairs formed with the combined histogram to the heap. */
+ for i = 0; i < num_clusters; i++ {
+ compareAndPushToQueueCommand(out, cluster_size, best_idx1, clusters[i], max_num_pairs, pairs[0:], &num_pairs)
+ }
+ }
+
+ return num_clusters
+}
+
+/* What is the bit cost of moving histogram from cur_symbol to candidate. */
+func histogramBitCostDistanceCommand(histogram *histogramCommand, candidate *histogramCommand) float64 {
+ if histogram.total_count_ == 0 {
+ return 0.0
+ } else {
+ var tmp histogramCommand = *histogram
+ histogramAddHistogramCommand(&tmp, candidate)
+ return populationCostCommand(&tmp) - candidate.bit_cost_
+ }
+}
diff --git a/vendor/github.com/andybalholm/brotli/cluster_distance.go b/vendor/github.com/andybalholm/brotli/cluster_distance.go
new file mode 100644
index 0000000..1aaa86e
--- /dev/null
+++ b/vendor/github.com/andybalholm/brotli/cluster_distance.go
@@ -0,0 +1,326 @@
+package brotli
+
+import "math"
+
+/* Copyright 2013 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Computes the bit cost reduction by combining out[idx1] and out[idx2] and if
+ it is below a threshold, stores the pair (idx1, idx2) in the *pairs queue. */
+func compareAndPushToQueueDistance(out []histogramDistance, cluster_size []uint32, idx1 uint32, idx2 uint32, max_num_pairs uint, pairs []histogramPair, num_pairs *uint) {
+ var is_good_pair bool = false
+ var p histogramPair
+ p.idx2 = 0
+ p.idx1 = p.idx2
+ p.cost_combo = 0
+ p.cost_diff = p.cost_combo
+ if idx1 == idx2 {
+ return
+ }
+
+ if idx2 < idx1 {
+ var t uint32 = idx2
+ idx2 = idx1
+ idx1 = t
+ }
+
+ p.idx1 = idx1
+ p.idx2 = idx2
+ p.cost_diff = 0.5 * clusterCostDiff(uint(cluster_size[idx1]), uint(cluster_size[idx2]))
+ p.cost_diff -= out[idx1].bit_cost_
+ p.cost_diff -= out[idx2].bit_cost_
+
+ if out[idx1].total_count_ == 0 {
+ p.cost_combo = out[idx2].bit_cost_
+ is_good_pair = true
+ } else if out[idx2].total_count_ == 0 {
+ p.cost_combo = out[idx1].bit_cost_
+ is_good_pair = true
+ } else {
+ var threshold float64
+ if *num_pairs == 0 {
+ threshold = 1e99
+ } else {
+ threshold = brotli_max_double(0.0, pairs[0].cost_diff)
+ }
+ var combo histogramDistance = out[idx1]
+ var cost_combo float64
+ histogramAddHistogramDistance(&combo, &out[idx2])
+ cost_combo = populationCostDistance(&combo)
+ if cost_combo < threshold-p.cost_diff {
+ p.cost_combo = cost_combo
+ is_good_pair = true
+ }
+ }
+
+ if is_good_pair {
+ p.cost_diff += p.cost_combo
+ if *num_pairs > 0 && histogramPairIsLess(&pairs[0], &p) {
+ /* Replace the top of the queue if needed. */
+ if *num_pairs < max_num_pairs {
+ pairs[*num_pairs] = pairs[0]
+ (*num_pairs)++
+ }
+
+ pairs[0] = p
+ } else if *num_pairs < max_num_pairs {
+ pairs[*num_pairs] = p
+ (*num_pairs)++
+ }
+ }
+}
+
+func histogramCombineDistance(out []histogramDistance, cluster_size []uint32, symbols []uint32, clusters []uint32, pairs []histogramPair, num_clusters uint, symbols_size uint, max_clusters uint, max_num_pairs uint) uint {
+ var cost_diff_threshold float64 = 0.0
+ var min_cluster_size uint = 1
+ var num_pairs uint = 0
+ {
+ /* We maintain a vector of histogram pairs, with the property that the pair
+ with the maximum bit cost reduction is the first. */
+ var idx1 uint
+ for idx1 = 0; idx1 < num_clusters; idx1++ {
+ var idx2 uint
+ for idx2 = idx1 + 1; idx2 < num_clusters; idx2++ {
+ compareAndPushToQueueDistance(out, cluster_size, clusters[idx1], clusters[idx2], max_num_pairs, pairs[0:], &num_pairs)
+ }
+ }
+ }
+
+ for num_clusters > min_cluster_size {
+ var best_idx1 uint32
+ var best_idx2 uint32
+ var i uint
+ if pairs[0].cost_diff >= cost_diff_threshold {
+ cost_diff_threshold = 1e99
+ min_cluster_size = max_clusters
+ continue
+ }
+
+ /* Take the best pair from the top of heap. */
+ best_idx1 = pairs[0].idx1
+
+ best_idx2 = pairs[0].idx2
+ histogramAddHistogramDistance(&out[best_idx1], &out[best_idx2])
+ out[best_idx1].bit_cost_ = pairs[0].cost_combo
+ cluster_size[best_idx1] += cluster_size[best_idx2]
+ for i = 0; i < symbols_size; i++ {
+ if symbols[i] == best_idx2 {
+ symbols[i] = best_idx1
+ }
+ }
+
+ for i = 0; i < num_clusters; i++ {
+ if clusters[i] == best_idx2 {
+ copy(clusters[i:], clusters[i+1:][:num_clusters-i-1])
+ break
+ }
+ }
+
+ num_clusters--
+ {
+ /* Remove pairs intersecting the just combined best pair. */
+ var copy_to_idx uint = 0
+ for i = 0; i < num_pairs; i++ {
+ var p *histogramPair = &pairs[i]
+ if p.idx1 == best_idx1 || p.idx2 == best_idx1 || p.idx1 == best_idx2 || p.idx2 == best_idx2 {
+ /* Remove invalid pair from the queue. */
+ continue
+ }
+
+ if histogramPairIsLess(&pairs[0], p) {
+ /* Replace the top of the queue if needed. */
+ var front histogramPair = pairs[0]
+ pairs[0] = *p
+ pairs[copy_to_idx] = front
+ } else {
+ pairs[copy_to_idx] = *p
+ }
+
+ copy_to_idx++
+ }
+
+ num_pairs = copy_to_idx
+ }
+
+ /* Push new pairs formed with the combined histogram to the heap. */
+ for i = 0; i < num_clusters; i++ {
+ compareAndPushToQueueDistance(out, cluster_size, best_idx1, clusters[i], max_num_pairs, pairs[0:], &num_pairs)
+ }
+ }
+
+ return num_clusters
+}
+
+/* What is the bit cost of moving histogram from cur_symbol to candidate. */
+func histogramBitCostDistanceDistance(histogram *histogramDistance, candidate *histogramDistance) float64 {
+ if histogram.total_count_ == 0 {
+ return 0.0
+ } else {
+ var tmp histogramDistance = *histogram
+ histogramAddHistogramDistance(&tmp, candidate)
+ return populationCostDistance(&tmp) - candidate.bit_cost_
+ }
+}
+
+/* Find the best 'out' histogram for each of the 'in' histograms.
+ When called, clusters[0..num_clusters) contains the unique values from
+ symbols[0..in_size), but this property is not preserved in this function.
+ Note: we assume that out[]->bit_cost_ is already up-to-date. */
+func histogramRemapDistance(in []histogramDistance, in_size uint, clusters []uint32, num_clusters uint, out []histogramDistance, symbols []uint32) {
+ var i uint
+ for i = 0; i < in_size; i++ {
+ var best_out uint32
+ if i == 0 {
+ best_out = symbols[0]
+ } else {
+ best_out = symbols[i-1]
+ }
+ var best_bits float64 = histogramBitCostDistanceDistance(&in[i], &out[best_out])
+ var j uint
+ for j = 0; j < num_clusters; j++ {
+ var cur_bits float64 = histogramBitCostDistanceDistance(&in[i], &out[clusters[j]])
+ if cur_bits < best_bits {
+ best_bits = cur_bits
+ best_out = clusters[j]
+ }
+ }
+
+ symbols[i] = best_out
+ }
+
+ /* Recompute each out based on raw and symbols. */
+ for i = 0; i < num_clusters; i++ {
+ histogramClearDistance(&out[clusters[i]])
+ }
+
+ for i = 0; i < in_size; i++ {
+ histogramAddHistogramDistance(&out[symbols[i]], &in[i])
+ }
+}
+
+/* Reorders elements of the out[0..length) array and changes values in
+ symbols[0..length) array in the following way:
+ * when called, symbols[] contains indexes into out[], and has N unique
+ values (possibly N < length)
+ * on return, symbols'[i] = f(symbols[i]) and
+ out'[symbols'[i]] = out[symbols[i]], for each 0 <= i < length,
+ where f is a bijection between the range of symbols[] and [0..N), and
+ the first occurrences of values in symbols'[i] come in consecutive
+ increasing order.
+ Returns N, the number of unique values in symbols[]. */
+
+var histogramReindexDistance_kInvalidIndex uint32 = math.MaxUint32
+
+func histogramReindexDistance(out []histogramDistance, symbols []uint32, length uint) uint {
+ var new_index []uint32 = make([]uint32, length)
+ var next_index uint32
+ var tmp []histogramDistance
+ var i uint
+ for i = 0; i < length; i++ {
+ new_index[i] = histogramReindexDistance_kInvalidIndex
+ }
+
+ next_index = 0
+ for i = 0; i < length; i++ {
+ if new_index[symbols[i]] == histogramReindexDistance_kInvalidIndex {
+ new_index[symbols[i]] = next_index
+ next_index++
+ }
+ }
+
+ /* TODO: by using idea of "cycle-sort" we can avoid allocation of
+ tmp and reduce the number of copying by the factor of 2. */
+ tmp = make([]histogramDistance, next_index)
+
+ next_index = 0
+ for i = 0; i < length; i++ {
+ if new_index[symbols[i]] == next_index {
+ tmp[next_index] = out[symbols[i]]
+ next_index++
+ }
+
+ symbols[i] = new_index[symbols[i]]
+ }
+
+ new_index = nil
+ for i = 0; uint32(i) < next_index; i++ {
+ out[i] = tmp[i]
+ }
+
+ tmp = nil
+ return uint(next_index)
+}
+
+func clusterHistogramsDistance(in []histogramDistance, in_size uint, max_histograms uint, out []histogramDistance, out_size *uint, histogram_symbols []uint32) {
+ var cluster_size []uint32 = make([]uint32, in_size)
+ var clusters []uint32 = make([]uint32, in_size)
+ var num_clusters uint = 0
+ var max_input_histograms uint = 64
+ var pairs_capacity uint = max_input_histograms * max_input_histograms / 2
+ var pairs []histogramPair = make([]histogramPair, (pairs_capacity + 1))
+ var i uint
+
+ /* For the first pass of clustering, we allow all pairs. */
+ for i = 0; i < in_size; i++ {
+ cluster_size[i] = 1
+ }
+
+ for i = 0; i < in_size; i++ {
+ out[i] = in[i]
+ out[i].bit_cost_ = populationCostDistance(&in[i])
+ histogram_symbols[i] = uint32(i)
+ }
+
+ for i = 0; i < in_size; i += max_input_histograms {
+ var num_to_combine uint = brotli_min_size_t(in_size-i, max_input_histograms)
+ var num_new_clusters uint
+ var j uint
+ for j = 0; j < num_to_combine; j++ {
+ clusters[num_clusters+j] = uint32(i + j)
+ }
+
+ num_new_clusters = histogramCombineDistance(out, cluster_size, histogram_symbols[i:], clusters[num_clusters:], pairs, num_to_combine, num_to_combine, max_histograms, pairs_capacity)
+ num_clusters += num_new_clusters
+ }
+ {
+ /* For the second pass, we limit the total number of histogram pairs.
+ After this limit is reached, we only keep searching for the best pair. */
+ var max_num_pairs uint = brotli_min_size_t(64*num_clusters, (num_clusters/2)*num_clusters)
+ if pairs_capacity < (max_num_pairs + 1) {
+ var _new_size uint
+ if pairs_capacity == 0 {
+ _new_size = max_num_pairs + 1
+ } else {
+ _new_size = pairs_capacity
+ }
+ var new_array []histogramPair
+ for _new_size < (max_num_pairs + 1) {
+ _new_size *= 2
+ }
+ new_array = make([]histogramPair, _new_size)
+ if pairs_capacity != 0 {
+ copy(new_array, pairs[:pairs_capacity])
+ }
+
+ pairs = new_array
+ pairs_capacity = _new_size
+ }
+
+ /* Collapse similar histograms. */
+ num_clusters = histogramCombineDistance(out, cluster_size, histogram_symbols, clusters, pairs, num_clusters, in_size, max_histograms, max_num_pairs)
+ }
+
+ pairs = nil
+ cluster_size = nil
+
+ /* Find the optimal map from original histograms to the final ones. */
+ histogramRemapDistance(in, in_size, clusters, num_clusters, out, histogram_symbols)
+
+ clusters = nil
+
+ /* Convert the context map to a canonical form. */
+ *out_size = histogramReindexDistance(out, histogram_symbols, in_size)
+}
diff --git a/vendor/github.com/andybalholm/brotli/cluster_literal.go b/vendor/github.com/andybalholm/brotli/cluster_literal.go
new file mode 100644
index 0000000..6ba66f3
--- /dev/null
+++ b/vendor/github.com/andybalholm/brotli/cluster_literal.go
@@ -0,0 +1,326 @@
+package brotli
+
+import "math"
+
+/* Copyright 2013 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Computes the bit cost reduction by combining out[idx1] and out[idx2] and if
+ it is below a threshold, stores the pair (idx1, idx2) in the *pairs queue. */
+func compareAndPushToQueueLiteral(out []histogramLiteral, cluster_size []uint32, idx1 uint32, idx2 uint32, max_num_pairs uint, pairs []histogramPair, num_pairs *uint) {
+ var is_good_pair bool = false
+ var p histogramPair
+ p.idx2 = 0
+ p.idx1 = p.idx2
+ p.cost_combo = 0
+ p.cost_diff = p.cost_combo
+ if idx1 == idx2 {
+ return
+ }
+
+ if idx2 < idx1 {
+ var t uint32 = idx2
+ idx2 = idx1
+ idx1 = t
+ }
+
+ p.idx1 = idx1
+ p.idx2 = idx2
+ p.cost_diff = 0.5 * clusterCostDiff(uint(cluster_size[idx1]), uint(cluster_size[idx2]))
+ p.cost_diff -= out[idx1].bit_cost_
+ p.cost_diff -= out[idx2].bit_cost_
+
+ if out[idx1].total_count_ == 0 {
+ p.cost_combo = out[idx2].bit_cost_
+ is_good_pair = true
+ } else if out[idx2].total_count_ == 0 {
+ p.cost_combo = out[idx1].bit_cost_
+ is_good_pair = true
+ } else {
+ var threshold float64
+ if *num_pairs == 0 {
+ threshold = 1e99
+ } else {
+ threshold = brotli_max_double(0.0, pairs[0].cost_diff)
+ }
+ var combo histogramLiteral = out[idx1]
+ var cost_combo float64
+ histogramAddHistogramLiteral(&combo, &out[idx2])
+ cost_combo = populationCostLiteral(&combo)
+ if cost_combo < threshold-p.cost_diff {
+ p.cost_combo = cost_combo
+ is_good_pair = true
+ }
+ }
+
+ if is_good_pair {
+ p.cost_diff += p.cost_combo
+ if *num_pairs > 0 && histogramPairIsLess(&pairs[0], &p) {
+ /* Replace the top of the queue if needed. */
+ if *num_pairs < max_num_pairs {
+ pairs[*num_pairs] = pairs[0]
+ (*num_pairs)++
+ }
+
+ pairs[0] = p
+ } else if *num_pairs < max_num_pairs {
+ pairs[*num_pairs] = p
+ (*num_pairs)++
+ }
+ }
+}
+
+func histogramCombineLiteral(out []histogramLiteral, cluster_size []uint32, symbols []uint32, clusters []uint32, pairs []histogramPair, num_clusters uint, symbols_size uint, max_clusters uint, max_num_pairs uint) uint {
+ var cost_diff_threshold float64 = 0.0
+ var min_cluster_size uint = 1
+ var num_pairs uint = 0
+ {
+ /* We maintain a vector of histogram pairs, with the property that the pair
+ with the maximum bit cost reduction is the first. */
+ var idx1 uint
+ for idx1 = 0; idx1 < num_clusters; idx1++ {
+ var idx2 uint
+ for idx2 = idx1 + 1; idx2 < num_clusters; idx2++ {
+ compareAndPushToQueueLiteral(out, cluster_size, clusters[idx1], clusters[idx2], max_num_pairs, pairs[0:], &num_pairs)
+ }
+ }
+ }
+
+ for num_clusters > min_cluster_size {
+ var best_idx1 uint32
+ var best_idx2 uint32
+ var i uint
+ if pairs[0].cost_diff >= cost_diff_threshold {
+ cost_diff_threshold = 1e99
+ min_cluster_size = max_clusters
+ continue
+ }
+
+ /* Take the best pair from the top of heap. */
+ best_idx1 = pairs[0].idx1
+
+ best_idx2 = pairs[0].idx2
+ histogramAddHistogramLiteral(&out[best_idx1], &out[best_idx2])
+ out[best_idx1].bit_cost_ = pairs[0].cost_combo
+ cluster_size[best_idx1] += cluster_size[best_idx2]
+ for i = 0; i < symbols_size; i++ {
+ if symbols[i] == best_idx2 {
+ symbols[i] = best_idx1
+ }
+ }
+
+ for i = 0; i < num_clusters; i++ {
+ if clusters[i] == best_idx2 {
+ copy(clusters[i:], clusters[i+1:][:num_clusters-i-1])
+ break
+ }
+ }
+
+ num_clusters--
+ {
+ /* Remove pairs intersecting the just combined best pair. */
+ var copy_to_idx uint = 0
+ for i = 0; i < num_pairs; i++ {
+ var p *histogramPair = &pairs[i]
+ if p.idx1 == best_idx1 || p.idx2 == best_idx1 || p.idx1 == best_idx2 || p.idx2 == best_idx2 {
+ /* Remove invalid pair from the queue. */
+ continue
+ }
+
+ if histogramPairIsLess(&pairs[0], p) {
+ /* Replace the top of the queue if needed. */
+ var front histogramPair = pairs[0]
+ pairs[0] = *p
+ pairs[copy_to_idx] = front
+ } else {
+ pairs[copy_to_idx] = *p
+ }
+
+ copy_to_idx++
+ }
+
+ num_pairs = copy_to_idx
+ }
+
+ /* Push new pairs formed with the combined histogram to the heap. */
+ for i = 0; i < num_clusters; i++ {
+ compareAndPushToQueueLiteral(out, cluster_size, best_idx1, clusters[i], max_num_pairs, pairs[0:], &num_pairs)
+ }
+ }
+
+ return num_clusters
+}
+
+/* What is the bit cost of moving histogram from cur_symbol to candidate. */
+func histogramBitCostDistanceLiteral(histogram *histogramLiteral, candidate *histogramLiteral) float64 {
+ if histogram.total_count_ == 0 {
+ return 0.0
+ } else {
+ var tmp histogramLiteral = *histogram
+ histogramAddHistogramLiteral(&tmp, candidate)
+ return populationCostLiteral(&tmp) - candidate.bit_cost_
+ }
+}
+
+/* Find the best 'out' histogram for each of the 'in' histograms.
+ When called, clusters[0..num_clusters) contains the unique values from
+ symbols[0..in_size), but this property is not preserved in this function.
+ Note: we assume that out[]->bit_cost_ is already up-to-date. */
+func histogramRemapLiteral(in []histogramLiteral, in_size uint, clusters []uint32, num_clusters uint, out []histogramLiteral, symbols []uint32) {
+ var i uint
+ for i = 0; i < in_size; i++ {
+ var best_out uint32
+ if i == 0 {
+ best_out = symbols[0]
+ } else {
+ best_out = symbols[i-1]
+ }
+ var best_bits float64 = histogramBitCostDistanceLiteral(&in[i], &out[best_out])
+ var j uint
+ for j = 0; j < num_clusters; j++ {
+ var cur_bits float64 = histogramBitCostDistanceLiteral(&in[i], &out[clusters[j]])
+ if cur_bits < best_bits {
+ best_bits = cur_bits
+ best_out = clusters[j]
+ }
+ }
+
+ symbols[i] = best_out
+ }
+
+ /* Recompute each out based on raw and symbols. */
+ for i = 0; i < num_clusters; i++ {
+ histogramClearLiteral(&out[clusters[i]])
+ }
+
+ for i = 0; i < in_size; i++ {
+ histogramAddHistogramLiteral(&out[symbols[i]], &in[i])
+ }
+}
+
+/* Reorders elements of the out[0..length) array and changes values in
+ symbols[0..length) array in the following way:
+ * when called, symbols[] contains indexes into out[], and has N unique
+ values (possibly N < length)
+ * on return, symbols'[i] = f(symbols[i]) and
+ out'[symbols'[i]] = out[symbols[i]], for each 0 <= i < length,
+ where f is a bijection between the range of symbols[] and [0..N), and
+ the first occurrences of values in symbols'[i] come in consecutive
+ increasing order.
+ Returns N, the number of unique values in symbols[]. */
+
+var histogramReindexLiteral_kInvalidIndex uint32 = math.MaxUint32
+
+func histogramReindexLiteral(out []histogramLiteral, symbols []uint32, length uint) uint {
+ var new_index []uint32 = make([]uint32, length)
+ var next_index uint32
+ var tmp []histogramLiteral
+ var i uint
+ for i = 0; i < length; i++ {
+ new_index[i] = histogramReindexLiteral_kInvalidIndex
+ }
+
+ next_index = 0
+ for i = 0; i < length; i++ {
+ if new_index[symbols[i]] == histogramReindexLiteral_kInvalidIndex {
+ new_index[symbols[i]] = next_index
+ next_index++
+ }
+ }
+
+ /* TODO: by using idea of "cycle-sort" we can avoid allocation of
+ tmp and reduce the number of copying by the factor of 2. */
+ tmp = make([]histogramLiteral, next_index)
+
+ next_index = 0
+ for i = 0; i < length; i++ {
+ if new_index[symbols[i]] == next_index {
+ tmp[next_index] = out[symbols[i]]
+ next_index++
+ }
+
+ symbols[i] = new_index[symbols[i]]
+ }
+
+ new_index = nil
+ for i = 0; uint32(i) < next_index; i++ {
+ out[i] = tmp[i]
+ }
+
+ tmp = nil
+ return uint(next_index)
+}
+
+func clusterHistogramsLiteral(in []histogramLiteral, in_size uint, max_histograms uint, out []histogramLiteral, out_size *uint, histogram_symbols []uint32) {
+ var cluster_size []uint32 = make([]uint32, in_size)
+ var clusters []uint32 = make([]uint32, in_size)
+ var num_clusters uint = 0
+ var max_input_histograms uint = 64
+ var pairs_capacity uint = max_input_histograms * max_input_histograms / 2
+ var pairs []histogramPair = make([]histogramPair, (pairs_capacity + 1))
+ var i uint
+
+ /* For the first pass of clustering, we allow all pairs. */
+ for i = 0; i < in_size; i++ {
+ cluster_size[i] = 1
+ }
+
+ for i = 0; i < in_size; i++ {
+ out[i] = in[i]
+ out[i].bit_cost_ = populationCostLiteral(&in[i])
+ histogram_symbols[i] = uint32(i)
+ }
+
+ for i = 0; i < in_size; i += max_input_histograms {
+ var num_to_combine uint = brotli_min_size_t(in_size-i, max_input_histograms)
+ var num_new_clusters uint
+ var j uint
+ for j = 0; j < num_to_combine; j++ {
+ clusters[num_clusters+j] = uint32(i + j)
+ }
+
+ num_new_clusters = histogramCombineLiteral(out, cluster_size, histogram_symbols[i:], clusters[num_clusters:], pairs, num_to_combine, num_to_combine, max_histograms, pairs_capacity)
+ num_clusters += num_new_clusters
+ }
+ {
+ /* For the second pass, we limit the total number of histogram pairs.
+ After this limit is reached, we only keep searching for the best pair. */
+ var max_num_pairs uint = brotli_min_size_t(64*num_clusters, (num_clusters/2)*num_clusters)
+ if pairs_capacity < (max_num_pairs + 1) {
+ var _new_size uint
+ if pairs_capacity == 0 {
+ _new_size = max_num_pairs + 1
+ } else {
+ _new_size = pairs_capacity
+ }
+ var new_array []histogramPair
+ for _new_size < (max_num_pairs + 1) {
+ _new_size *= 2
+ }
+ new_array = make([]histogramPair, _new_size)
+ if pairs_capacity != 0 {
+ copy(new_array, pairs[:pairs_capacity])
+ }
+
+ pairs = new_array
+ pairs_capacity = _new_size
+ }
+
+ /* Collapse similar histograms. */
+ num_clusters = histogramCombineLiteral(out, cluster_size, histogram_symbols, clusters, pairs, num_clusters, in_size, max_histograms, max_num_pairs)
+ }
+
+ pairs = nil
+ cluster_size = nil
+
+ /* Find the optimal map from original histograms to the final ones. */
+ histogramRemapLiteral(in, in_size, clusters, num_clusters, out, histogram_symbols)
+
+ clusters = nil
+
+ /* Convert the context map to a canonical form. */
+ *out_size = histogramReindexLiteral(out, histogram_symbols, in_size)
+}
diff --git a/vendor/github.com/andybalholm/brotli/command.go b/vendor/github.com/andybalholm/brotli/command.go
new file mode 100644
index 0000000..b1662a5
--- /dev/null
+++ b/vendor/github.com/andybalholm/brotli/command.go
@@ -0,0 +1,254 @@
+package brotli
+
+var kInsBase = []uint32{
+ 0,
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 8,
+ 10,
+ 14,
+ 18,
+ 26,
+ 34,
+ 50,
+ 66,
+ 98,
+ 130,
+ 194,
+ 322,
+ 578,
+ 1090,
+ 2114,
+ 6210,
+ 22594,
+}
+
+var kInsExtra = []uint32{
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1,
+ 1,
+ 2,
+ 2,
+ 3,
+ 3,
+ 4,
+ 4,
+ 5,
+ 5,
+ 6,
+ 7,
+ 8,
+ 9,
+ 10,
+ 12,
+ 14,
+ 24,
+}
+
+var kCopyBase = []uint32{
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8,
+ 9,
+ 10,
+ 12,
+ 14,
+ 18,
+ 22,
+ 30,
+ 38,
+ 54,
+ 70,
+ 102,
+ 134,
+ 198,
+ 326,
+ 582,
+ 1094,
+ 2118,
+}
+
+var kCopyExtra = []uint32{
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1,
+ 1,
+ 2,
+ 2,
+ 3,
+ 3,
+ 4,
+ 4,
+ 5,
+ 5,
+ 6,
+ 7,
+ 8,
+ 9,
+ 10,
+ 24,
+}
+
+func getInsertLengthCode(insertlen uint) uint16 {
+ if insertlen < 6 {
+ return uint16(insertlen)
+ } else if insertlen < 130 {
+ var nbits uint32 = log2FloorNonZero(insertlen-2) - 1
+ return uint16((nbits << 1) + uint32((insertlen-2)>>nbits) + 2)
+ } else if insertlen < 2114 {
+ return uint16(log2FloorNonZero(insertlen-66) + 10)
+ } else if insertlen < 6210 {
+ return 21
+ } else if insertlen < 22594 {
+ return 22
+ } else {
+ return 23
+ }
+}
+
+func getCopyLengthCode(copylen uint) uint16 {
+ if copylen < 10 {
+ return uint16(copylen - 2)
+ } else if copylen < 134 {
+ var nbits uint32 = log2FloorNonZero(copylen-6) - 1
+ return uint16((nbits << 1) + uint32((copylen-6)>>nbits) + 4)
+ } else if copylen < 2118 {
+ return uint16(log2FloorNonZero(copylen-70) + 12)
+ } else {
+ return 23
+ }
+}
+
+func combineLengthCodes(inscode uint16, copycode uint16, use_last_distance bool) uint16 {
+ var bits64 uint16 = uint16(copycode&0x7 | (inscode&0x7)<<3)
+ if use_last_distance && inscode < 8 && copycode < 16 {
+ if copycode < 8 {
+ return bits64
+ } else {
+ return bits64 | 64
+ }
+ } else {
+ /* Specification: 5 Encoding of ... (last table) */
+ /* offset = 2 * index, where index is in range [0..8] */
+ var offset uint32 = 2 * ((uint32(copycode) >> 3) + 3*(uint32(inscode)>>3))
+
+ /* All values in specification are K * 64,
+ where K = [2, 3, 6, 4, 5, 8, 7, 9, 10],
+ i + 1 = [1, 2, 3, 4, 5, 6, 7, 8, 9],
+ K - i - 1 = [1, 1, 3, 0, 0, 2, 0, 1, 2] = D.
+ All values in D require only 2 bits to encode.
+ Magic constant is shifted 6 bits left, to avoid final multiplication. */
+ offset = (offset << 5) + 0x40 + ((0x520D40 >> offset) & 0xC0)
+
+ return uint16(offset | uint32(bits64))
+ }
+}
+
+func getLengthCode(insertlen uint, copylen uint, use_last_distance bool, code *uint16) {
+ var inscode uint16 = getInsertLengthCode(insertlen)
+ var copycode uint16 = getCopyLengthCode(copylen)
+ *code = combineLengthCodes(inscode, copycode, use_last_distance)
+}
+
+func getInsertBase(inscode uint16) uint32 {
+ return kInsBase[inscode]
+}
+
+func getInsertExtra(inscode uint16) uint32 {
+ return kInsExtra[inscode]
+}
+
+func getCopyBase(copycode uint16) uint32 {
+ return kCopyBase[copycode]
+}
+
+func getCopyExtra(copycode uint16) uint32 {
+ return kCopyExtra[copycode]
+}
+
+type command struct {
+ insert_len_ uint32
+ copy_len_ uint32
+ dist_extra_ uint32
+ cmd_prefix_ uint16
+ dist_prefix_ uint16
+}
+
+/* distance_code is e.g. 0 for same-as-last short code, or 16 for offset 1. */
+func makeCommand(dist *distanceParams, insertlen uint, copylen uint, copylen_code_delta int, distance_code uint) (cmd command) {
+ /* Don't rely on signed int representation, use honest casts. */
+ var delta uint32 = uint32(byte(int8(copylen_code_delta)))
+ cmd.insert_len_ = uint32(insertlen)
+ cmd.copy_len_ = uint32(uint32(copylen) | delta<<25)
+
+ /* The distance prefix and extra bits are stored in this Command as if
+ npostfix and ndirect were 0, they are only recomputed later after the
+ clustering if needed. */
+ prefixEncodeCopyDistance(distance_code, uint(dist.num_direct_distance_codes), uint(dist.distance_postfix_bits), &cmd.dist_prefix_, &cmd.dist_extra_)
+ getLengthCode(insertlen, uint(int(copylen)+copylen_code_delta), (cmd.dist_prefix_&0x3FF == 0), &cmd.cmd_prefix_)
+
+ return cmd
+}
+
+func makeInsertCommand(insertlen uint) (cmd command) {
+ cmd.insert_len_ = uint32(insertlen)
+ cmd.copy_len_ = 4 << 25
+ cmd.dist_extra_ = 0
+ cmd.dist_prefix_ = numDistanceShortCodes
+ getLengthCode(insertlen, 4, false, &cmd.cmd_prefix_)
+ return cmd
+}
+
+func commandRestoreDistanceCode(self *command, dist *distanceParams) uint32 {
+ if uint32(self.dist_prefix_&0x3FF) < numDistanceShortCodes+dist.num_direct_distance_codes {
+ return uint32(self.dist_prefix_) & 0x3FF
+ } else {
+ var dcode uint32 = uint32(self.dist_prefix_) & 0x3FF
+ var nbits uint32 = uint32(self.dist_prefix_) >> 10
+ var extra uint32 = self.dist_extra_
+ var postfix_mask uint32 = (1 << dist.distance_postfix_bits) - 1
+ var hcode uint32 = (dcode - dist.num_direct_distance_codes - numDistanceShortCodes) >> dist.distance_postfix_bits
+ var lcode uint32 = (dcode - dist.num_direct_distance_codes - numDistanceShortCodes) & postfix_mask
+ var offset uint32 = ((2 + (hcode & 1)) << nbits) - 4
+ return ((offset + extra) << dist.distance_postfix_bits) + lcode + dist.num_direct_distance_codes + numDistanceShortCodes
+ }
+}
+
+func commandDistanceContext(self *command) uint32 {
+ var r uint32 = uint32(self.cmd_prefix_) >> 6
+ var c uint32 = uint32(self.cmd_prefix_) & 7
+ if (r == 0 || r == 2 || r == 4 || r == 7) && (c <= 2) {
+ return c
+ }
+
+ return 3
+}
+
+func commandCopyLen(self *command) uint32 {
+ return self.copy_len_ & 0x1FFFFFF
+}
+
+func commandCopyLenCode(self *command) uint32 {
+ var modifier uint32 = self.copy_len_ >> 25
+ var delta int32 = int32(int8(byte(modifier | (modifier&0x40)<<1)))
+ return uint32(int32(self.copy_len_&0x1FFFFFF) + delta)
+}
diff --git a/vendor/github.com/andybalholm/brotli/compress_fragment.go b/vendor/github.com/andybalholm/brotli/compress_fragment.go
new file mode 100644
index 0000000..c9bd057
--- /dev/null
+++ b/vendor/github.com/andybalholm/brotli/compress_fragment.go
@@ -0,0 +1,834 @@
+package brotli
+
+import "encoding/binary"
+
+/* Copyright 2015 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Function for fast encoding of an input fragment, independently from the input
+ history. This function uses one-pass processing: when we find a backward
+ match, we immediately emit the corresponding command and literal codes to
+ the bit stream.
+
+ Adapted from the CompressFragment() function in
+ https://github.com/google/snappy/blob/master/snappy.cc */
+
+const maxDistance_compress_fragment = 262128
+
+func hash5(p []byte, shift uint) uint32 {
+ var h uint64 = (binary.LittleEndian.Uint64(p) << 24) * uint64(kHashMul32)
+ return uint32(h >> shift)
+}
+
+func hashBytesAtOffset5(v uint64, offset int, shift uint) uint32 {
+ assert(offset >= 0)
+ assert(offset <= 3)
+ {
+ var h uint64 = ((v >> uint(8*offset)) << 24) * uint64(kHashMul32)
+ return uint32(h >> shift)
+ }
+}
+
+func isMatch5(p1 []byte, p2 []byte) bool {
+ return binary.LittleEndian.Uint32(p1) == binary.LittleEndian.Uint32(p2) &&
+ p1[4] == p2[4]
+}
+
+/* Builds a literal prefix code into "depths" and "bits" based on the statistics
+ of the "input" string and stores it into the bit stream.
+ Note that the prefix code here is built from the pre-LZ77 input, therefore
+ we can only approximate the statistics of the actual literal stream.
+ Moreover, for long inputs we build a histogram from a sample of the input
+ and thus have to assign a non-zero depth for each literal.
+ Returns estimated compression ratio millibytes/char for encoding given input
+ with generated code. */
+func buildAndStoreLiteralPrefixCode(input []byte, input_size uint, depths []byte, bits []uint16, storage_ix *uint, storage []byte) uint {
+ var histogram = [256]uint32{0}
+ var histogram_total uint
+ var i uint
+ if input_size < 1<<15 {
+ for i = 0; i < input_size; i++ {
+ histogram[input[i]]++
+ }
+
+ histogram_total = input_size
+ for i = 0; i < 256; i++ {
+ /* We weigh the first 11 samples with weight 3 to account for the
+ balancing effect of the LZ77 phase on the histogram. */
+ var adjust uint32 = 2 * brotli_min_uint32_t(histogram[i], 11)
+ histogram[i] += adjust
+ histogram_total += uint(adjust)
+ }
+ } else {
+ const kSampleRate uint = 29
+ for i = 0; i < input_size; i += kSampleRate {
+ histogram[input[i]]++
+ }
+
+ histogram_total = (input_size + kSampleRate - 1) / kSampleRate
+ for i = 0; i < 256; i++ {
+ /* We add 1 to each population count to avoid 0 bit depths (since this is
+ only a sample and we don't know if the symbol appears or not), and we
+ weigh the first 11 samples with weight 3 to account for the balancing
+ effect of the LZ77 phase on the histogram (more frequent symbols are
+ more likely to be in backward references instead as literals). */
+ var adjust uint32 = 1 + 2*brotli_min_uint32_t(histogram[i], 11)
+ histogram[i] += adjust
+ histogram_total += uint(adjust)
+ }
+ }
+
+ buildAndStoreHuffmanTreeFast(histogram[:], histogram_total, /* max_bits = */
+ 8, depths, bits, storage_ix, storage)
+ {
+ var literal_ratio uint = 0
+ for i = 0; i < 256; i++ {
+ if histogram[i] != 0 {
+ literal_ratio += uint(histogram[i] * uint32(depths[i]))
+ }
+ }
+
+ /* Estimated encoding ratio, millibytes per symbol. */
+ return (literal_ratio * 125) / histogram_total
+ }
+}
+
+/* Builds a command and distance prefix code (each 64 symbols) into "depth" and
+ "bits" based on "histogram" and stores it into the bit stream. */
+func buildAndStoreCommandPrefixCode1(histogram []uint32, depth []byte, bits []uint16, storage_ix *uint, storage []byte) {
+ var tree [129]huffmanTree
+ var cmd_depth = [numCommandSymbols]byte{0}
+ /* Tree size for building a tree over 64 symbols is 2 * 64 + 1. */
+
+ var cmd_bits [64]uint16
+
+ createHuffmanTree(histogram, 64, 15, tree[:], depth)
+ createHuffmanTree(histogram[64:], 64, 14, tree[:], depth[64:])
+
+ /* We have to jump through a few hoops here in order to compute
+ the command bits because the symbols are in a different order than in
+ the full alphabet. This looks complicated, but having the symbols
+ in this order in the command bits saves a few branches in the Emit*
+ functions. */
+ copy(cmd_depth[:], depth[:24])
+
+ copy(cmd_depth[24:][:], depth[40:][:8])
+ copy(cmd_depth[32:][:], depth[24:][:8])
+ copy(cmd_depth[40:][:], depth[48:][:8])
+ copy(cmd_depth[48:][:], depth[32:][:8])
+ copy(cmd_depth[56:][:], depth[56:][:8])
+ convertBitDepthsToSymbols(cmd_depth[:], 64, cmd_bits[:])
+ copy(bits, cmd_bits[:24])
+ copy(bits[24:], cmd_bits[32:][:8])
+ copy(bits[32:], cmd_bits[48:][:8])
+ copy(bits[40:], cmd_bits[24:][:8])
+ copy(bits[48:], cmd_bits[40:][:8])
+ copy(bits[56:], cmd_bits[56:][:8])
+ convertBitDepthsToSymbols(depth[64:], 64, bits[64:])
+ {
+ /* Create the bit length array for the full command alphabet. */
+ var i uint
+ for i := 0; i < int(64); i++ {
+ cmd_depth[i] = 0
+ } /* only 64 first values were used */
+ copy(cmd_depth[:], depth[:8])
+ copy(cmd_depth[64:][:], depth[8:][:8])
+ copy(cmd_depth[128:][:], depth[16:][:8])
+ copy(cmd_depth[192:][:], depth[24:][:8])
+ copy(cmd_depth[384:][:], depth[32:][:8])
+ for i = 0; i < 8; i++ {
+ cmd_depth[128+8*i] = depth[40+i]
+ cmd_depth[256+8*i] = depth[48+i]
+ cmd_depth[448+8*i] = depth[56+i]
+ }
+
+ storeHuffmanTree(cmd_depth[:], numCommandSymbols, tree[:], storage_ix, storage)
+ }
+
+ storeHuffmanTree(depth[64:], 64, tree[:], storage_ix, storage)
+}
+
+/* REQUIRES: insertlen < 6210 */
+func emitInsertLen1(insertlen uint, depth []byte, bits []uint16, histo []uint32, storage_ix *uint, storage []byte) {
+ if insertlen < 6 {
+ var code uint = insertlen + 40
+ writeBits(uint(depth[code]), uint64(bits[code]), storage_ix, storage)
+ histo[code]++
+ } else if insertlen < 130 {
+ var tail uint = insertlen - 2
+ var nbits uint32 = log2FloorNonZero(tail) - 1
+ var prefix uint = tail >> nbits
+ var inscode uint = uint((nbits << 1) + uint32(prefix) + 42)
+ writeBits(uint(depth[inscode]), uint64(bits[inscode]), storage_ix, storage)
+ writeBits(uint(nbits), uint64(tail)-(uint64(prefix)<> nbits
+ var code uint = uint((nbits << 1) + uint32(prefix) + 20)
+ writeBits(uint(depth[code]), uint64(bits[code]), storage_ix, storage)
+ writeBits(uint(nbits), uint64(tail)-(uint64(prefix)<> nbits
+ var code uint = uint((nbits << 1) + uint32(prefix) + 4)
+ writeBits(uint(depth[code]), uint64(bits[code]), storage_ix, storage)
+ writeBits(uint(nbits), uint64(tail)-(uint64(prefix)<> 5) + 30
+ writeBits(uint(depth[code]), uint64(bits[code]), storage_ix, storage)
+ writeBits(5, uint64(tail)&31, storage_ix, storage)
+ writeBits(uint(depth[64]), uint64(bits[64]), storage_ix, storage)
+ histo[code]++
+ histo[64]++
+ } else if copylen < 2120 {
+ var tail uint = copylen - 72
+ var nbits uint32 = log2FloorNonZero(tail)
+ var code uint = uint(nbits + 28)
+ writeBits(uint(depth[code]), uint64(bits[code]), storage_ix, storage)
+ writeBits(uint(nbits), uint64(tail)-(uint64(uint(1))<> nbits) & 1
+ var offset uint = (2 + prefix) << nbits
+ var distcode uint = uint(2*(nbits-1) + uint32(prefix) + 80)
+ writeBits(uint(depth[distcode]), uint64(bits[distcode]), storage_ix, storage)
+ writeBits(uint(nbits), uint64(d)-uint64(offset), storage_ix, storage)
+ histo[distcode]++
+}
+
+func emitLiterals(input []byte, len uint, depth []byte, bits []uint16, storage_ix *uint, storage []byte) {
+ var j uint
+ for j = 0; j < len; j++ {
+ var lit byte = input[j]
+ writeBits(uint(depth[lit]), uint64(bits[lit]), storage_ix, storage)
+ }
+}
+
+/* REQUIRES: len <= 1 << 24. */
+func storeMetaBlockHeader1(len uint, is_uncompressed bool, storage_ix *uint, storage []byte) {
+ var nibbles uint = 6
+
+ /* ISLAST */
+ writeBits(1, 0, storage_ix, storage)
+
+ if len <= 1<<16 {
+ nibbles = 4
+ } else if len <= 1<<20 {
+ nibbles = 5
+ }
+
+ writeBits(2, uint64(nibbles)-4, storage_ix, storage)
+ writeBits(nibbles*4, uint64(len)-1, storage_ix, storage)
+
+ /* ISUNCOMPRESSED */
+ writeSingleBit(is_uncompressed, storage_ix, storage)
+}
+
+func updateBits(n_bits uint, bits uint32, pos uint, array []byte) {
+ for n_bits > 0 {
+ var byte_pos uint = pos >> 3
+ var n_unchanged_bits uint = pos & 7
+ var n_changed_bits uint = brotli_min_size_t(n_bits, 8-n_unchanged_bits)
+ var total_bits uint = n_unchanged_bits + n_changed_bits
+ var mask uint32 = (^((1 << total_bits) - 1)) | ((1 << n_unchanged_bits) - 1)
+ var unchanged_bits uint32 = uint32(array[byte_pos]) & mask
+ var changed_bits uint32 = bits & ((1 << n_changed_bits) - 1)
+ array[byte_pos] = byte(changed_bits<>= n_changed_bits
+ pos += n_changed_bits
+ }
+}
+
+func rewindBitPosition1(new_storage_ix uint, storage_ix *uint, storage []byte) {
+ var bitpos uint = new_storage_ix & 7
+ var mask uint = (1 << bitpos) - 1
+ storage[new_storage_ix>>3] &= byte(mask)
+ *storage_ix = new_storage_ix
+}
+
+var shouldMergeBlock_kSampleRate uint = 43
+
+func shouldMergeBlock(data []byte, len uint, depths []byte) bool {
+ var histo = [256]uint{0}
+ var i uint
+ for i = 0; i < len; i += shouldMergeBlock_kSampleRate {
+ histo[data[i]]++
+ }
+ {
+ var total uint = (len + shouldMergeBlock_kSampleRate - 1) / shouldMergeBlock_kSampleRate
+ var r float64 = (fastLog2(total)+0.5)*float64(total) + 200
+ for i = 0; i < 256; i++ {
+ r -= float64(histo[i]) * (float64(depths[i]) + fastLog2(histo[i]))
+ }
+
+ return r >= 0.0
+ }
+}
+
+func shouldUseUncompressedMode(metablock_start []byte, next_emit []byte, insertlen uint, literal_ratio uint) bool {
+ var compressed uint = uint(-cap(next_emit) + cap(metablock_start))
+ if compressed*50 > insertlen {
+ return false
+ } else {
+ return literal_ratio > 980
+ }
+}
+
+func emitUncompressedMetaBlock1(begin []byte, end []byte, storage_ix_start uint, storage_ix *uint, storage []byte) {
+ var len uint = uint(-cap(end) + cap(begin))
+ rewindBitPosition1(storage_ix_start, storage_ix, storage)
+ storeMetaBlockHeader1(uint(len), true, storage_ix, storage)
+ *storage_ix = (*storage_ix + 7) &^ 7
+ copy(storage[*storage_ix>>3:], begin[:len])
+ *storage_ix += uint(len << 3)
+ storage[*storage_ix>>3] = 0
+}
+
+var kCmdHistoSeed = [128]uint32{
+ 0,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 0,
+ 0,
+ 0,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 0,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 0,
+ 0,
+ 0,
+ 0,
+}
+
+var compressFragmentFastImpl_kFirstBlockSize uint = 3 << 15
+var compressFragmentFastImpl_kMergeBlockSize uint = 1 << 16
+
+func compressFragmentFastImpl(in []byte, input_size uint, is_last bool, table []int, table_bits uint, cmd_depth []byte, cmd_bits []uint16, cmd_code_numbits *uint, cmd_code []byte, storage_ix *uint, storage []byte) {
+ var cmd_histo [128]uint32
+ var ip_end int
+ var next_emit int = 0
+ var base_ip int = 0
+ var input int = 0
+ const kInputMarginBytes uint = windowGap
+ const kMinMatchLen uint = 5
+ var metablock_start int = input
+ var block_size uint = brotli_min_size_t(input_size, compressFragmentFastImpl_kFirstBlockSize)
+ var total_block_size uint = block_size
+ var mlen_storage_ix uint = *storage_ix + 3
+ var lit_depth [256]byte
+ var lit_bits [256]uint16
+ var literal_ratio uint
+ var ip int
+ var last_distance int
+ var shift uint = 64 - table_bits
+
+ /* "next_emit" is a pointer to the first byte that is not covered by a
+ previous copy. Bytes between "next_emit" and the start of the next copy or
+ the end of the input will be emitted as literal bytes. */
+
+ /* Save the start of the first block for position and distance computations.
+ */
+
+ /* Save the bit position of the MLEN field of the meta-block header, so that
+ we can update it later if we decide to extend this meta-block. */
+ storeMetaBlockHeader1(block_size, false, storage_ix, storage)
+
+ /* No block splits, no contexts. */
+ writeBits(13, 0, storage_ix, storage)
+
+ literal_ratio = buildAndStoreLiteralPrefixCode(in[input:], block_size, lit_depth[:], lit_bits[:], storage_ix, storage)
+ {
+ /* Store the pre-compressed command and distance prefix codes. */
+ var i uint
+ for i = 0; i+7 < *cmd_code_numbits; i += 8 {
+ writeBits(8, uint64(cmd_code[i>>3]), storage_ix, storage)
+ }
+ }
+
+ writeBits(*cmd_code_numbits&7, uint64(cmd_code[*cmd_code_numbits>>3]), storage_ix, storage)
+
+ /* Initialize the command and distance histograms. We will gather
+ statistics of command and distance codes during the processing
+ of this block and use it to update the command and distance
+ prefix codes for the next block. */
+emit_commands:
+ copy(cmd_histo[:], kCmdHistoSeed[:])
+
+ /* "ip" is the input pointer. */
+ ip = input
+
+ last_distance = -1
+ ip_end = int(uint(input) + block_size)
+
+ if block_size >= kInputMarginBytes {
+ var len_limit uint = brotli_min_size_t(block_size-kMinMatchLen, input_size-kInputMarginBytes)
+ var ip_limit int = int(uint(input) + len_limit)
+ /* For the last block, we need to keep a 16 bytes margin so that we can be
+ sure that all distances are at most window size - 16.
+ For all other blocks, we only need to keep a margin of 5 bytes so that
+ we don't go over the block size with a copy. */
+
+ var next_hash uint32
+ ip++
+ for next_hash = hash5(in[ip:], shift); ; {
+ var skip uint32 = 32
+ var next_ip int = ip
+ /* Step 1: Scan forward in the input looking for a 5-byte-long match.
+ If we get close to exhausting the input then goto emit_remainder.
+
+ Heuristic match skipping: If 32 bytes are scanned with no matches
+ found, start looking only at every other byte. If 32 more bytes are
+ scanned, look at every third byte, etc.. When a match is found,
+ immediately go back to looking at every byte. This is a small loss
+ (~5% performance, ~0.1% density) for compressible data due to more
+ bookkeeping, but for non-compressible data (such as JPEG) it's a huge
+ win since the compressor quickly "realizes" the data is incompressible
+ and doesn't bother looking for matches everywhere.
+
+ The "skip" variable keeps track of how many bytes there are since the
+ last match; dividing it by 32 (i.e. right-shifting by five) gives the
+ number of bytes to move ahead for each iteration. */
+
+ var candidate int
+ assert(next_emit < ip)
+
+ trawl:
+ for {
+ var hash uint32 = next_hash
+ var bytes_between_hash_lookups uint32 = skip >> 5
+ skip++
+ assert(hash == hash5(in[next_ip:], shift))
+ ip = next_ip
+ next_ip = int(uint32(ip) + bytes_between_hash_lookups)
+ if next_ip > ip_limit {
+ goto emit_remainder
+ }
+
+ next_hash = hash5(in[next_ip:], shift)
+ candidate = ip - last_distance
+ if isMatch5(in[ip:], in[candidate:]) {
+ if candidate < ip {
+ table[hash] = int(ip - base_ip)
+ break
+ }
+ }
+
+ candidate = base_ip + table[hash]
+ assert(candidate >= base_ip)
+ assert(candidate < ip)
+
+ table[hash] = int(ip - base_ip)
+ if isMatch5(in[ip:], in[candidate:]) {
+ break
+ }
+ }
+
+ /* Check copy distance. If candidate is not feasible, continue search.
+ Checking is done outside of hot loop to reduce overhead. */
+ if ip-candidate > maxDistance_compress_fragment {
+ goto trawl
+ }
+
+ /* Step 2: Emit the found match together with the literal bytes from
+ "next_emit" to the bit stream, and then see if we can find a next match
+ immediately afterwards. Repeat until we find no match for the input
+ without emitting some literal bytes. */
+ {
+ var base int = ip
+ /* > 0 */
+ var matched uint = 5 + findMatchLengthWithLimit(in[candidate+5:], in[ip+5:], uint(ip_end-ip)-5)
+ var distance int = int(base - candidate)
+ /* We have a 5-byte match at ip, and we need to emit bytes in
+ [next_emit, ip). */
+
+ var insert uint = uint(base - next_emit)
+ ip += int(matched)
+ if insert < 6210 {
+ emitInsertLen1(insert, cmd_depth, cmd_bits, cmd_histo[:], storage_ix, storage)
+ } else if shouldUseUncompressedMode(in[metablock_start:], in[next_emit:], insert, literal_ratio) {
+ emitUncompressedMetaBlock1(in[metablock_start:], in[base:], mlen_storage_ix-3, storage_ix, storage)
+ input_size -= uint(base - input)
+ input = base
+ next_emit = input
+ goto next_block
+ } else {
+ emitLongInsertLen(insert, cmd_depth, cmd_bits, cmd_histo[:], storage_ix, storage)
+ }
+
+ emitLiterals(in[next_emit:], insert, lit_depth[:], lit_bits[:], storage_ix, storage)
+ if distance == last_distance {
+ writeBits(uint(cmd_depth[64]), uint64(cmd_bits[64]), storage_ix, storage)
+ cmd_histo[64]++
+ } else {
+ emitDistance1(uint(distance), cmd_depth, cmd_bits, cmd_histo[:], storage_ix, storage)
+ last_distance = distance
+ }
+
+ emitCopyLenLastDistance1(matched, cmd_depth, cmd_bits, cmd_histo[:], storage_ix, storage)
+
+ next_emit = ip
+ if ip >= ip_limit {
+ goto emit_remainder
+ }
+
+ /* We could immediately start working at ip now, but to improve
+ compression we first update "table" with the hashes of some positions
+ within the last copy. */
+ {
+ var input_bytes uint64 = binary.LittleEndian.Uint64(in[ip-3:])
+ var prev_hash uint32 = hashBytesAtOffset5(input_bytes, 0, shift)
+ var cur_hash uint32 = hashBytesAtOffset5(input_bytes, 3, shift)
+ table[prev_hash] = int(ip - base_ip - 3)
+ prev_hash = hashBytesAtOffset5(input_bytes, 1, shift)
+ table[prev_hash] = int(ip - base_ip - 2)
+ prev_hash = hashBytesAtOffset5(input_bytes, 2, shift)
+ table[prev_hash] = int(ip - base_ip - 1)
+
+ candidate = base_ip + table[cur_hash]
+ table[cur_hash] = int(ip - base_ip)
+ }
+ }
+
+ for isMatch5(in[ip:], in[candidate:]) {
+ var base int = ip
+ /* We have a 5-byte match at ip, and no need to emit any literal bytes
+ prior to ip. */
+
+ var matched uint = 5 + findMatchLengthWithLimit(in[candidate+5:], in[ip+5:], uint(ip_end-ip)-5)
+ if ip-candidate > maxDistance_compress_fragment {
+ break
+ }
+ ip += int(matched)
+ last_distance = int(base - candidate) /* > 0 */
+ emitCopyLen1(matched, cmd_depth, cmd_bits, cmd_histo[:], storage_ix, storage)
+ emitDistance1(uint(last_distance), cmd_depth, cmd_bits, cmd_histo[:], storage_ix, storage)
+
+ next_emit = ip
+ if ip >= ip_limit {
+ goto emit_remainder
+ }
+
+ /* We could immediately start working at ip now, but to improve
+ compression we first update "table" with the hashes of some positions
+ within the last copy. */
+ {
+ var input_bytes uint64 = binary.LittleEndian.Uint64(in[ip-3:])
+ var prev_hash uint32 = hashBytesAtOffset5(input_bytes, 0, shift)
+ var cur_hash uint32 = hashBytesAtOffset5(input_bytes, 3, shift)
+ table[prev_hash] = int(ip - base_ip - 3)
+ prev_hash = hashBytesAtOffset5(input_bytes, 1, shift)
+ table[prev_hash] = int(ip - base_ip - 2)
+ prev_hash = hashBytesAtOffset5(input_bytes, 2, shift)
+ table[prev_hash] = int(ip - base_ip - 1)
+
+ candidate = base_ip + table[cur_hash]
+ table[cur_hash] = int(ip - base_ip)
+ }
+ }
+
+ ip++
+ next_hash = hash5(in[ip:], shift)
+ }
+ }
+
+emit_remainder:
+ assert(next_emit <= ip_end)
+ input += int(block_size)
+ input_size -= block_size
+ block_size = brotli_min_size_t(input_size, compressFragmentFastImpl_kMergeBlockSize)
+
+ /* Decide if we want to continue this meta-block instead of emitting the
+ last insert-only command. */
+ if input_size > 0 && total_block_size+block_size <= 1<<20 && shouldMergeBlock(in[input:], block_size, lit_depth[:]) {
+ assert(total_block_size > 1<<16)
+
+ /* Update the size of the current meta-block and continue emitting commands.
+ We can do this because the current size and the new size both have 5
+ nibbles. */
+ total_block_size += block_size
+
+ updateBits(20, uint32(total_block_size-1), mlen_storage_ix, storage)
+ goto emit_commands
+ }
+
+ /* Emit the remaining bytes as literals. */
+ if next_emit < ip_end {
+ var insert uint = uint(ip_end - next_emit)
+ if insert < 6210 {
+ emitInsertLen1(insert, cmd_depth, cmd_bits, cmd_histo[:], storage_ix, storage)
+ emitLiterals(in[next_emit:], insert, lit_depth[:], lit_bits[:], storage_ix, storage)
+ } else if shouldUseUncompressedMode(in[metablock_start:], in[next_emit:], insert, literal_ratio) {
+ emitUncompressedMetaBlock1(in[metablock_start:], in[ip_end:], mlen_storage_ix-3, storage_ix, storage)
+ } else {
+ emitLongInsertLen(insert, cmd_depth, cmd_bits, cmd_histo[:], storage_ix, storage)
+ emitLiterals(in[next_emit:], insert, lit_depth[:], lit_bits[:], storage_ix, storage)
+ }
+ }
+
+ next_emit = ip_end
+
+ /* If we have more data, write a new meta-block header and prefix codes and
+ then continue emitting commands. */
+next_block:
+ if input_size > 0 {
+ metablock_start = input
+ block_size = brotli_min_size_t(input_size, compressFragmentFastImpl_kFirstBlockSize)
+ total_block_size = block_size
+
+ /* Save the bit position of the MLEN field of the meta-block header, so that
+ we can update it later if we decide to extend this meta-block. */
+ mlen_storage_ix = *storage_ix + 3
+
+ storeMetaBlockHeader1(block_size, false, storage_ix, storage)
+
+ /* No block splits, no contexts. */
+ writeBits(13, 0, storage_ix, storage)
+
+ literal_ratio = buildAndStoreLiteralPrefixCode(in[input:], block_size, lit_depth[:], lit_bits[:], storage_ix, storage)
+ buildAndStoreCommandPrefixCode1(cmd_histo[:], cmd_depth, cmd_bits, storage_ix, storage)
+ goto emit_commands
+ }
+
+ if !is_last {
+ /* If this is not the last block, update the command and distance prefix
+ codes for the next block and store the compressed forms. */
+ cmd_code[0] = 0
+
+ *cmd_code_numbits = 0
+ buildAndStoreCommandPrefixCode1(cmd_histo[:], cmd_depth, cmd_bits, cmd_code_numbits, cmd_code)
+ }
+}
+
+/* Compresses "input" string to the "*storage" buffer as one or more complete
+ meta-blocks, and updates the "*storage_ix" bit position.
+
+ If "is_last" is 1, emits an additional empty last meta-block.
+
+ "cmd_depth" and "cmd_bits" contain the command and distance prefix codes
+ (see comment in encode.h) used for the encoding of this input fragment.
+ If "is_last" is 0, they are updated to reflect the statistics
+ of this input fragment, to be used for the encoding of the next fragment.
+
+ "*cmd_code_numbits" is the number of bits of the compressed representation
+ of the command and distance prefix codes, and "cmd_code" is an array of
+ at least "(*cmd_code_numbits + 7) >> 3" size that contains the compressed
+ command and distance prefix codes. If "is_last" is 0, these are also
+ updated to represent the updated "cmd_depth" and "cmd_bits".
+
+ REQUIRES: "input_size" is greater than zero, or "is_last" is 1.
+ REQUIRES: "input_size" is less or equal to maximal metablock size (1 << 24).
+ REQUIRES: All elements in "table[0..table_size-1]" are initialized to zero.
+ REQUIRES: "table_size" is an odd (9, 11, 13, 15) power of two
+ OUTPUT: maximal copy distance <= |input_size|
+ OUTPUT: maximal copy distance <= BROTLI_MAX_BACKWARD_LIMIT(18) */
+func compressFragmentFast(input []byte, input_size uint, is_last bool, table []int, table_size uint, cmd_depth []byte, cmd_bits []uint16, cmd_code_numbits *uint, cmd_code []byte, storage_ix *uint, storage []byte) {
+ var initial_storage_ix uint = *storage_ix
+ var table_bits uint = uint(log2FloorNonZero(table_size))
+
+ if input_size == 0 {
+ assert(is_last)
+ writeBits(1, 1, storage_ix, storage) /* islast */
+ writeBits(1, 1, storage_ix, storage) /* isempty */
+ *storage_ix = (*storage_ix + 7) &^ 7
+ return
+ }
+
+ compressFragmentFastImpl(input, input_size, is_last, table, table_bits, cmd_depth, cmd_bits, cmd_code_numbits, cmd_code, storage_ix, storage)
+
+ /* If output is larger than single uncompressed block, rewrite it. */
+ if *storage_ix-initial_storage_ix > 31+(input_size<<3) {
+ emitUncompressedMetaBlock1(input, input[input_size:], initial_storage_ix, storage_ix, storage)
+ }
+
+ if is_last {
+ writeBits(1, 1, storage_ix, storage) /* islast */
+ writeBits(1, 1, storage_ix, storage) /* isempty */
+ *storage_ix = (*storage_ix + 7) &^ 7
+ }
+}
diff --git a/vendor/github.com/andybalholm/brotli/compress_fragment_two_pass.go b/vendor/github.com/andybalholm/brotli/compress_fragment_two_pass.go
new file mode 100644
index 0000000..172dc7f
--- /dev/null
+++ b/vendor/github.com/andybalholm/brotli/compress_fragment_two_pass.go
@@ -0,0 +1,748 @@
+package brotli
+
+import "encoding/binary"
+
+/* Copyright 2015 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Function for fast encoding of an input fragment, independently from the input
+ history. This function uses two-pass processing: in the first pass we save
+ the found backward matches and literal bytes into a buffer, and in the
+ second pass we emit them into the bit stream using prefix codes built based
+ on the actual command and literal byte histograms. */
+
+const kCompressFragmentTwoPassBlockSize uint = 1 << 17
+
+func hash1(p []byte, shift uint, length uint) uint32 {
+ var h uint64 = (binary.LittleEndian.Uint64(p) << ((8 - length) * 8)) * uint64(kHashMul32)
+ return uint32(h >> shift)
+}
+
+func hashBytesAtOffset(v uint64, offset uint, shift uint, length uint) uint32 {
+ assert(offset <= 8-length)
+ {
+ var h uint64 = ((v >> (8 * offset)) << ((8 - length) * 8)) * uint64(kHashMul32)
+ return uint32(h >> shift)
+ }
+}
+
+func isMatch1(p1 []byte, p2 []byte, length uint) bool {
+ if binary.LittleEndian.Uint32(p1) != binary.LittleEndian.Uint32(p2) {
+ return false
+ }
+ if length == 4 {
+ return true
+ }
+ return p1[4] == p2[4] && p1[5] == p2[5]
+}
+
+/* Builds a command and distance prefix code (each 64 symbols) into "depth" and
+ "bits" based on "histogram" and stores it into the bit stream. */
+func buildAndStoreCommandPrefixCode(histogram []uint32, depth []byte, bits []uint16, storage_ix *uint, storage []byte) {
+ var tree [129]huffmanTree
+ var cmd_depth = [numCommandSymbols]byte{0}
+ /* Tree size for building a tree over 64 symbols is 2 * 64 + 1. */
+
+ var cmd_bits [64]uint16
+ createHuffmanTree(histogram, 64, 15, tree[:], depth)
+ createHuffmanTree(histogram[64:], 64, 14, tree[:], depth[64:])
+
+ /* We have to jump through a few hoops here in order to compute
+ the command bits because the symbols are in a different order than in
+ the full alphabet. This looks complicated, but having the symbols
+ in this order in the command bits saves a few branches in the Emit*
+ functions. */
+ copy(cmd_depth[:], depth[24:][:24])
+
+ copy(cmd_depth[24:][:], depth[:8])
+ copy(cmd_depth[32:][:], depth[48:][:8])
+ copy(cmd_depth[40:][:], depth[8:][:8])
+ copy(cmd_depth[48:][:], depth[56:][:8])
+ copy(cmd_depth[56:][:], depth[16:][:8])
+ convertBitDepthsToSymbols(cmd_depth[:], 64, cmd_bits[:])
+ copy(bits, cmd_bits[24:][:8])
+ copy(bits[8:], cmd_bits[40:][:8])
+ copy(bits[16:], cmd_bits[56:][:8])
+ copy(bits[24:], cmd_bits[:24])
+ copy(bits[48:], cmd_bits[32:][:8])
+ copy(bits[56:], cmd_bits[48:][:8])
+ convertBitDepthsToSymbols(depth[64:], 64, bits[64:])
+ {
+ /* Create the bit length array for the full command alphabet. */
+ var i uint
+ for i := 0; i < int(64); i++ {
+ cmd_depth[i] = 0
+ } /* only 64 first values were used */
+ copy(cmd_depth[:], depth[24:][:8])
+ copy(cmd_depth[64:][:], depth[32:][:8])
+ copy(cmd_depth[128:][:], depth[40:][:8])
+ copy(cmd_depth[192:][:], depth[48:][:8])
+ copy(cmd_depth[384:][:], depth[56:][:8])
+ for i = 0; i < 8; i++ {
+ cmd_depth[128+8*i] = depth[i]
+ cmd_depth[256+8*i] = depth[8+i]
+ cmd_depth[448+8*i] = depth[16+i]
+ }
+
+ storeHuffmanTree(cmd_depth[:], numCommandSymbols, tree[:], storage_ix, storage)
+ }
+
+ storeHuffmanTree(depth[64:], 64, tree[:], storage_ix, storage)
+}
+
+func emitInsertLen(insertlen uint32, commands *[]uint32) {
+ if insertlen < 6 {
+ (*commands)[0] = insertlen
+ } else if insertlen < 130 {
+ var tail uint32 = insertlen - 2
+ var nbits uint32 = log2FloorNonZero(uint(tail)) - 1
+ var prefix uint32 = tail >> nbits
+ var inscode uint32 = (nbits << 1) + prefix + 2
+ var extra uint32 = tail - (prefix << nbits)
+ (*commands)[0] = inscode | extra<<8
+ } else if insertlen < 2114 {
+ var tail uint32 = insertlen - 66
+ var nbits uint32 = log2FloorNonZero(uint(tail))
+ var code uint32 = nbits + 10
+ var extra uint32 = tail - (1 << nbits)
+ (*commands)[0] = code | extra<<8
+ } else if insertlen < 6210 {
+ var extra uint32 = insertlen - 2114
+ (*commands)[0] = 21 | extra<<8
+ } else if insertlen < 22594 {
+ var extra uint32 = insertlen - 6210
+ (*commands)[0] = 22 | extra<<8
+ } else {
+ var extra uint32 = insertlen - 22594
+ (*commands)[0] = 23 | extra<<8
+ }
+
+ *commands = (*commands)[1:]
+}
+
+func emitCopyLen(copylen uint, commands *[]uint32) {
+ if copylen < 10 {
+ (*commands)[0] = uint32(copylen + 38)
+ } else if copylen < 134 {
+ var tail uint = copylen - 6
+ var nbits uint = uint(log2FloorNonZero(tail) - 1)
+ var prefix uint = tail >> nbits
+ var code uint = (nbits << 1) + prefix + 44
+ var extra uint = tail - (prefix << nbits)
+ (*commands)[0] = uint32(code | extra<<8)
+ } else if copylen < 2118 {
+ var tail uint = copylen - 70
+ var nbits uint = uint(log2FloorNonZero(tail))
+ var code uint = nbits + 52
+ var extra uint = tail - (uint(1) << nbits)
+ (*commands)[0] = uint32(code | extra<<8)
+ } else {
+ var extra uint = copylen - 2118
+ (*commands)[0] = uint32(63 | extra<<8)
+ }
+
+ *commands = (*commands)[1:]
+}
+
+func emitCopyLenLastDistance(copylen uint, commands *[]uint32) {
+ if copylen < 12 {
+ (*commands)[0] = uint32(copylen + 20)
+ *commands = (*commands)[1:]
+ } else if copylen < 72 {
+ var tail uint = copylen - 8
+ var nbits uint = uint(log2FloorNonZero(tail) - 1)
+ var prefix uint = tail >> nbits
+ var code uint = (nbits << 1) + prefix + 28
+ var extra uint = tail - (prefix << nbits)
+ (*commands)[0] = uint32(code | extra<<8)
+ *commands = (*commands)[1:]
+ } else if copylen < 136 {
+ var tail uint = copylen - 8
+ var code uint = (tail >> 5) + 54
+ var extra uint = tail & 31
+ (*commands)[0] = uint32(code | extra<<8)
+ *commands = (*commands)[1:]
+ (*commands)[0] = 64
+ *commands = (*commands)[1:]
+ } else if copylen < 2120 {
+ var tail uint = copylen - 72
+ var nbits uint = uint(log2FloorNonZero(tail))
+ var code uint = nbits + 52
+ var extra uint = tail - (uint(1) << nbits)
+ (*commands)[0] = uint32(code | extra<<8)
+ *commands = (*commands)[1:]
+ (*commands)[0] = 64
+ *commands = (*commands)[1:]
+ } else {
+ var extra uint = copylen - 2120
+ (*commands)[0] = uint32(63 | extra<<8)
+ *commands = (*commands)[1:]
+ (*commands)[0] = 64
+ *commands = (*commands)[1:]
+ }
+}
+
+func emitDistance(distance uint32, commands *[]uint32) {
+ var d uint32 = distance + 3
+ var nbits uint32 = log2FloorNonZero(uint(d)) - 1
+ var prefix uint32 = (d >> nbits) & 1
+ var offset uint32 = (2 + prefix) << nbits
+ var distcode uint32 = 2*(nbits-1) + prefix + 80
+ var extra uint32 = d - offset
+ (*commands)[0] = distcode | extra<<8
+ *commands = (*commands)[1:]
+}
+
+/* REQUIRES: len <= 1 << 24. */
+func storeMetaBlockHeader(len uint, is_uncompressed bool, storage_ix *uint, storage []byte) {
+ var nibbles uint = 6
+
+ /* ISLAST */
+ writeBits(1, 0, storage_ix, storage)
+
+ if len <= 1<<16 {
+ nibbles = 4
+ } else if len <= 1<<20 {
+ nibbles = 5
+ }
+
+ writeBits(2, uint64(nibbles)-4, storage_ix, storage)
+ writeBits(nibbles*4, uint64(len)-1, storage_ix, storage)
+
+ /* ISUNCOMPRESSED */
+ writeSingleBit(is_uncompressed, storage_ix, storage)
+}
+
+func createCommands(input []byte, block_size uint, input_size uint, base_ip_ptr []byte, table []int, table_bits uint, min_match uint, literals *[]byte, commands *[]uint32) {
+ var ip int = 0
+ var shift uint = 64 - table_bits
+ var ip_end int = int(block_size)
+ var base_ip int = -cap(base_ip_ptr) + cap(input)
+ var next_emit int = 0
+ var last_distance int = -1
+ /* "ip" is the input pointer. */
+
+ const kInputMarginBytes uint = windowGap
+
+ /* "next_emit" is a pointer to the first byte that is not covered by a
+ previous copy. Bytes between "next_emit" and the start of the next copy or
+ the end of the input will be emitted as literal bytes. */
+ if block_size >= kInputMarginBytes {
+ var len_limit uint = brotli_min_size_t(block_size-min_match, input_size-kInputMarginBytes)
+ var ip_limit int = int(len_limit)
+ /* For the last block, we need to keep a 16 bytes margin so that we can be
+ sure that all distances are at most window size - 16.
+ For all other blocks, we only need to keep a margin of 5 bytes so that
+ we don't go over the block size with a copy. */
+
+ var next_hash uint32
+ ip++
+ for next_hash = hash1(input[ip:], shift, min_match); ; {
+ var skip uint32 = 32
+ var next_ip int = ip
+ /* Step 1: Scan forward in the input looking for a 6-byte-long match.
+ If we get close to exhausting the input then goto emit_remainder.
+
+ Heuristic match skipping: If 32 bytes are scanned with no matches
+ found, start looking only at every other byte. If 32 more bytes are
+ scanned, look at every third byte, etc.. When a match is found,
+ immediately go back to looking at every byte. This is a small loss
+ (~5% performance, ~0.1% density) for compressible data due to more
+ bookkeeping, but for non-compressible data (such as JPEG) it's a huge
+ win since the compressor quickly "realizes" the data is incompressible
+ and doesn't bother looking for matches everywhere.
+
+ The "skip" variable keeps track of how many bytes there are since the
+ last match; dividing it by 32 (ie. right-shifting by five) gives the
+ number of bytes to move ahead for each iteration. */
+
+ var candidate int
+
+ assert(next_emit < ip)
+
+ trawl:
+ for {
+ var hash uint32 = next_hash
+ var bytes_between_hash_lookups uint32 = skip >> 5
+ skip++
+ ip = next_ip
+ assert(hash == hash1(input[ip:], shift, min_match))
+ next_ip = int(uint32(ip) + bytes_between_hash_lookups)
+ if next_ip > ip_limit {
+ goto emit_remainder
+ }
+
+ next_hash = hash1(input[next_ip:], shift, min_match)
+ candidate = ip - last_distance
+ if isMatch1(input[ip:], base_ip_ptr[candidate-base_ip:], min_match) {
+ if candidate < ip {
+ table[hash] = int(ip - base_ip)
+ break
+ }
+ }
+
+ candidate = base_ip + table[hash]
+ assert(candidate >= base_ip)
+ assert(candidate < ip)
+
+ table[hash] = int(ip - base_ip)
+ if isMatch1(input[ip:], base_ip_ptr[candidate-base_ip:], min_match) {
+ break
+ }
+ }
+
+ /* Check copy distance. If candidate is not feasible, continue search.
+ Checking is done outside of hot loop to reduce overhead. */
+ if ip-candidate > maxDistance_compress_fragment {
+ goto trawl
+ }
+
+ /* Step 2: Emit the found match together with the literal bytes from
+ "next_emit", and then see if we can find a next match immediately
+ afterwards. Repeat until we find no match for the input
+ without emitting some literal bytes. */
+ {
+ var base int = ip
+ /* > 0 */
+ var matched uint = min_match + findMatchLengthWithLimit(base_ip_ptr[uint(candidate-base_ip)+min_match:], input[uint(ip)+min_match:], uint(ip_end-ip)-min_match)
+ var distance int = int(base - candidate)
+ /* We have a 6-byte match at ip, and we need to emit bytes in
+ [next_emit, ip). */
+
+ var insert int = int(base - next_emit)
+ ip += int(matched)
+ emitInsertLen(uint32(insert), commands)
+ copy(*literals, input[next_emit:][:uint(insert)])
+ *literals = (*literals)[insert:]
+ if distance == last_distance {
+ (*commands)[0] = 64
+ *commands = (*commands)[1:]
+ } else {
+ emitDistance(uint32(distance), commands)
+ last_distance = distance
+ }
+
+ emitCopyLenLastDistance(matched, commands)
+
+ next_emit = ip
+ if ip >= ip_limit {
+ goto emit_remainder
+ }
+ {
+ var input_bytes uint64
+ var cur_hash uint32
+ /* We could immediately start working at ip now, but to improve
+ compression we first update "table" with the hashes of some
+ positions within the last copy. */
+
+ var prev_hash uint32
+ if min_match == 4 {
+ input_bytes = binary.LittleEndian.Uint64(input[ip-3:])
+ cur_hash = hashBytesAtOffset(input_bytes, 3, shift, min_match)
+ prev_hash = hashBytesAtOffset(input_bytes, 0, shift, min_match)
+ table[prev_hash] = int(ip - base_ip - 3)
+ prev_hash = hashBytesAtOffset(input_bytes, 1, shift, min_match)
+ table[prev_hash] = int(ip - base_ip - 2)
+ prev_hash = hashBytesAtOffset(input_bytes, 0, shift, min_match)
+ table[prev_hash] = int(ip - base_ip - 1)
+ } else {
+ input_bytes = binary.LittleEndian.Uint64(input[ip-5:])
+ prev_hash = hashBytesAtOffset(input_bytes, 0, shift, min_match)
+ table[prev_hash] = int(ip - base_ip - 5)
+ prev_hash = hashBytesAtOffset(input_bytes, 1, shift, min_match)
+ table[prev_hash] = int(ip - base_ip - 4)
+ prev_hash = hashBytesAtOffset(input_bytes, 2, shift, min_match)
+ table[prev_hash] = int(ip - base_ip - 3)
+ input_bytes = binary.LittleEndian.Uint64(input[ip-2:])
+ cur_hash = hashBytesAtOffset(input_bytes, 2, shift, min_match)
+ prev_hash = hashBytesAtOffset(input_bytes, 0, shift, min_match)
+ table[prev_hash] = int(ip - base_ip - 2)
+ prev_hash = hashBytesAtOffset(input_bytes, 1, shift, min_match)
+ table[prev_hash] = int(ip - base_ip - 1)
+ }
+
+ candidate = base_ip + table[cur_hash]
+ table[cur_hash] = int(ip - base_ip)
+ }
+ }
+
+ for ip-candidate <= maxDistance_compress_fragment && isMatch1(input[ip:], base_ip_ptr[candidate-base_ip:], min_match) {
+ var base int = ip
+ /* We have a 6-byte match at ip, and no need to emit any
+ literal bytes prior to ip. */
+
+ var matched uint = min_match + findMatchLengthWithLimit(base_ip_ptr[uint(candidate-base_ip)+min_match:], input[uint(ip)+min_match:], uint(ip_end-ip)-min_match)
+ ip += int(matched)
+ last_distance = int(base - candidate) /* > 0 */
+ emitCopyLen(matched, commands)
+ emitDistance(uint32(last_distance), commands)
+
+ next_emit = ip
+ if ip >= ip_limit {
+ goto emit_remainder
+ }
+ {
+ var input_bytes uint64
+ var cur_hash uint32
+ /* We could immediately start working at ip now, but to improve
+ compression we first update "table" with the hashes of some
+ positions within the last copy. */
+
+ var prev_hash uint32
+ if min_match == 4 {
+ input_bytes = binary.LittleEndian.Uint64(input[ip-3:])
+ cur_hash = hashBytesAtOffset(input_bytes, 3, shift, min_match)
+ prev_hash = hashBytesAtOffset(input_bytes, 0, shift, min_match)
+ table[prev_hash] = int(ip - base_ip - 3)
+ prev_hash = hashBytesAtOffset(input_bytes, 1, shift, min_match)
+ table[prev_hash] = int(ip - base_ip - 2)
+ prev_hash = hashBytesAtOffset(input_bytes, 2, shift, min_match)
+ table[prev_hash] = int(ip - base_ip - 1)
+ } else {
+ input_bytes = binary.LittleEndian.Uint64(input[ip-5:])
+ prev_hash = hashBytesAtOffset(input_bytes, 0, shift, min_match)
+ table[prev_hash] = int(ip - base_ip - 5)
+ prev_hash = hashBytesAtOffset(input_bytes, 1, shift, min_match)
+ table[prev_hash] = int(ip - base_ip - 4)
+ prev_hash = hashBytesAtOffset(input_bytes, 2, shift, min_match)
+ table[prev_hash] = int(ip - base_ip - 3)
+ input_bytes = binary.LittleEndian.Uint64(input[ip-2:])
+ cur_hash = hashBytesAtOffset(input_bytes, 2, shift, min_match)
+ prev_hash = hashBytesAtOffset(input_bytes, 0, shift, min_match)
+ table[prev_hash] = int(ip - base_ip - 2)
+ prev_hash = hashBytesAtOffset(input_bytes, 1, shift, min_match)
+ table[prev_hash] = int(ip - base_ip - 1)
+ }
+
+ candidate = base_ip + table[cur_hash]
+ table[cur_hash] = int(ip - base_ip)
+ }
+ }
+
+ ip++
+ next_hash = hash1(input[ip:], shift, min_match)
+ }
+ }
+
+emit_remainder:
+ assert(next_emit <= ip_end)
+
+ /* Emit the remaining bytes as literals. */
+ if next_emit < ip_end {
+ var insert uint32 = uint32(ip_end - next_emit)
+ emitInsertLen(insert, commands)
+ copy(*literals, input[next_emit:][:insert])
+ *literals = (*literals)[insert:]
+ }
+}
+
+var storeCommands_kNumExtraBits = [128]uint32{
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1,
+ 1,
+ 2,
+ 2,
+ 3,
+ 3,
+ 4,
+ 4,
+ 5,
+ 5,
+ 6,
+ 7,
+ 8,
+ 9,
+ 10,
+ 12,
+ 14,
+ 24,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1,
+ 1,
+ 2,
+ 2,
+ 3,
+ 3,
+ 4,
+ 4,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1,
+ 1,
+ 2,
+ 2,
+ 3,
+ 3,
+ 4,
+ 4,
+ 5,
+ 5,
+ 6,
+ 7,
+ 8,
+ 9,
+ 10,
+ 24,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1,
+ 1,
+ 2,
+ 2,
+ 3,
+ 3,
+ 4,
+ 4,
+ 5,
+ 5,
+ 6,
+ 6,
+ 7,
+ 7,
+ 8,
+ 8,
+ 9,
+ 9,
+ 10,
+ 10,
+ 11,
+ 11,
+ 12,
+ 12,
+ 13,
+ 13,
+ 14,
+ 14,
+ 15,
+ 15,
+ 16,
+ 16,
+ 17,
+ 17,
+ 18,
+ 18,
+ 19,
+ 19,
+ 20,
+ 20,
+ 21,
+ 21,
+ 22,
+ 22,
+ 23,
+ 23,
+ 24,
+ 24,
+}
+var storeCommands_kInsertOffset = [24]uint32{
+ 0,
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 8,
+ 10,
+ 14,
+ 18,
+ 26,
+ 34,
+ 50,
+ 66,
+ 98,
+ 130,
+ 194,
+ 322,
+ 578,
+ 1090,
+ 2114,
+ 6210,
+ 22594,
+}
+
+func storeCommands(literals []byte, num_literals uint, commands []uint32, num_commands uint, storage_ix *uint, storage []byte) {
+ var lit_depths [256]byte
+ var lit_bits [256]uint16
+ var lit_histo = [256]uint32{0}
+ var cmd_depths = [128]byte{0}
+ var cmd_bits = [128]uint16{0}
+ var cmd_histo = [128]uint32{0}
+ var i uint
+ for i = 0; i < num_literals; i++ {
+ lit_histo[literals[i]]++
+ }
+
+ buildAndStoreHuffmanTreeFast(lit_histo[:], num_literals, /* max_bits = */
+ 8, lit_depths[:], lit_bits[:], storage_ix, storage)
+
+ for i = 0; i < num_commands; i++ {
+ var code uint32 = commands[i] & 0xFF
+ assert(code < 128)
+ cmd_histo[code]++
+ }
+
+ cmd_histo[1] += 1
+ cmd_histo[2] += 1
+ cmd_histo[64] += 1
+ cmd_histo[84] += 1
+ buildAndStoreCommandPrefixCode(cmd_histo[:], cmd_depths[:], cmd_bits[:], storage_ix, storage)
+
+ for i = 0; i < num_commands; i++ {
+ var cmd uint32 = commands[i]
+ var code uint32 = cmd & 0xFF
+ var extra uint32 = cmd >> 8
+ assert(code < 128)
+ writeBits(uint(cmd_depths[code]), uint64(cmd_bits[code]), storage_ix, storage)
+ writeBits(uint(storeCommands_kNumExtraBits[code]), uint64(extra), storage_ix, storage)
+ if code < 24 {
+ var insert uint32 = storeCommands_kInsertOffset[code] + extra
+ var j uint32
+ for j = 0; j < insert; j++ {
+ var lit byte = literals[0]
+ writeBits(uint(lit_depths[lit]), uint64(lit_bits[lit]), storage_ix, storage)
+ literals = literals[1:]
+ }
+ }
+ }
+}
+
+/* Acceptable loss for uncompressible speedup is 2% */
+const minRatio = 0.98
+
+const sampleRate = 43
+
+func shouldCompress(input []byte, input_size uint, num_literals uint) bool {
+ var corpus_size float64 = float64(input_size)
+ if float64(num_literals) < minRatio*corpus_size {
+ return true
+ } else {
+ var literal_histo = [256]uint32{0}
+ var max_total_bit_cost float64 = corpus_size * 8 * minRatio / sampleRate
+ var i uint
+ for i = 0; i < input_size; i += sampleRate {
+ literal_histo[input[i]]++
+ }
+
+ return bitsEntropy(literal_histo[:], 256) < max_total_bit_cost
+ }
+}
+
+func rewindBitPosition(new_storage_ix uint, storage_ix *uint, storage []byte) {
+ var bitpos uint = new_storage_ix & 7
+ var mask uint = (1 << bitpos) - 1
+ storage[new_storage_ix>>3] &= byte(mask)
+ *storage_ix = new_storage_ix
+}
+
+func emitUncompressedMetaBlock(input []byte, input_size uint, storage_ix *uint, storage []byte) {
+ storeMetaBlockHeader(input_size, true, storage_ix, storage)
+ *storage_ix = (*storage_ix + 7) &^ 7
+ copy(storage[*storage_ix>>3:], input[:input_size])
+ *storage_ix += input_size << 3
+ storage[*storage_ix>>3] = 0
+}
+
+func compressFragmentTwoPassImpl(input []byte, input_size uint, is_last bool, command_buf []uint32, literal_buf []byte, table []int, table_bits uint, min_match uint, storage_ix *uint, storage []byte) {
+ /* Save the start of the first block for position and distance computations.
+ */
+ var base_ip []byte = input
+
+ for input_size > 0 {
+ var block_size uint = brotli_min_size_t(input_size, kCompressFragmentTwoPassBlockSize)
+ var commands []uint32 = command_buf
+ var literals []byte = literal_buf
+ var num_literals uint
+ createCommands(input, block_size, input_size, base_ip, table, table_bits, min_match, &literals, &commands)
+ num_literals = uint(-cap(literals) + cap(literal_buf))
+ if shouldCompress(input, block_size, num_literals) {
+ var num_commands uint = uint(-cap(commands) + cap(command_buf))
+ storeMetaBlockHeader(block_size, false, storage_ix, storage)
+
+ /* No block splits, no contexts. */
+ writeBits(13, 0, storage_ix, storage)
+
+ storeCommands(literal_buf, num_literals, command_buf, num_commands, storage_ix, storage)
+ } else {
+ /* Since we did not find many backward references and the entropy of
+ the data is close to 8 bits, we can simply emit an uncompressed block.
+ This makes compression speed of uncompressible data about 3x faster. */
+ emitUncompressedMetaBlock(input, block_size, storage_ix, storage)
+ }
+
+ input = input[block_size:]
+ input_size -= block_size
+ }
+}
+
+/* Compresses "input" string to the "*storage" buffer as one or more complete
+ meta-blocks, and updates the "*storage_ix" bit position.
+
+ If "is_last" is 1, emits an additional empty last meta-block.
+
+ REQUIRES: "input_size" is greater than zero, or "is_last" is 1.
+ REQUIRES: "input_size" is less or equal to maximal metablock size (1 << 24).
+ REQUIRES: "command_buf" and "literal_buf" point to at least
+ kCompressFragmentTwoPassBlockSize long arrays.
+ REQUIRES: All elements in "table[0..table_size-1]" are initialized to zero.
+ REQUIRES: "table_size" is a power of two
+ OUTPUT: maximal copy distance <= |input_size|
+ OUTPUT: maximal copy distance <= BROTLI_MAX_BACKWARD_LIMIT(18) */
+func compressFragmentTwoPass(input []byte, input_size uint, is_last bool, command_buf []uint32, literal_buf []byte, table []int, table_size uint, storage_ix *uint, storage []byte) {
+ var initial_storage_ix uint = *storage_ix
+ var table_bits uint = uint(log2FloorNonZero(table_size))
+ var min_match uint
+ if table_bits <= 15 {
+ min_match = 4
+ } else {
+ min_match = 6
+ }
+ compressFragmentTwoPassImpl(input, input_size, is_last, command_buf, literal_buf, table, table_bits, min_match, storage_ix, storage)
+
+ /* If output is larger than single uncompressed block, rewrite it. */
+ if *storage_ix-initial_storage_ix > 31+(input_size<<3) {
+ rewindBitPosition(initial_storage_ix, storage_ix, storage)
+ emitUncompressedMetaBlock(input, input_size, storage_ix, storage)
+ }
+
+ if is_last {
+ writeBits(1, 1, storage_ix, storage) /* islast */
+ writeBits(1, 1, storage_ix, storage) /* isempty */
+ *storage_ix = (*storage_ix + 7) &^ 7
+ }
+}
diff --git a/vendor/github.com/andybalholm/brotli/constants.go b/vendor/github.com/andybalholm/brotli/constants.go
new file mode 100644
index 0000000..a880dff
--- /dev/null
+++ b/vendor/github.com/andybalholm/brotli/constants.go
@@ -0,0 +1,77 @@
+package brotli
+
+/* Copyright 2016 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Specification: 7.3. Encoding of the context map */
+const contextMapMaxRle = 16
+
+/* Specification: 2. Compressed representation overview */
+const maxNumberOfBlockTypes = 256
+
+/* Specification: 3.3. Alphabet sizes: insert-and-copy length */
+const numLiteralSymbols = 256
+
+const numCommandSymbols = 704
+
+const numBlockLenSymbols = 26
+
+const maxContextMapSymbols = (maxNumberOfBlockTypes + contextMapMaxRle)
+
+const maxBlockTypeSymbols = (maxNumberOfBlockTypes + 2)
+
+/* Specification: 3.5. Complex prefix codes */
+const repeatPreviousCodeLength = 16
+
+const repeatZeroCodeLength = 17
+
+const codeLengthCodes = (repeatZeroCodeLength + 1)
+
+/* "code length of 8 is repeated" */
+const initialRepeatedCodeLength = 8
+
+/* "Large Window Brotli" */
+const largeMaxDistanceBits = 62
+
+const largeMinWbits = 10
+
+const largeMaxWbits = 30
+
+/* Specification: 4. Encoding of distances */
+const numDistanceShortCodes = 16
+
+const maxNpostfix = 3
+
+const maxNdirect = 120
+
+const maxDistanceBits = 24
+
+func distanceAlphabetSize(NPOSTFIX uint, NDIRECT uint, MAXNBITS uint) uint {
+ return numDistanceShortCodes + NDIRECT + uint(MAXNBITS<<(NPOSTFIX+1))
+}
+
+/* numDistanceSymbols == 1128 */
+const numDistanceSymbols = 1128
+
+const maxDistance = 0x3FFFFFC
+
+const maxAllowedDistance = 0x7FFFFFFC
+
+/* 7.1. Context modes and context ID lookup for literals */
+/* "context IDs for literals are in the range of 0..63" */
+const literalContextBits = 6
+
+/* 7.2. Context ID for distances */
+const distanceContextBits = 2
+
+/* 9.1. Format of the Stream Header */
+/* Number of slack bytes for window size. Don't confuse
+ with BROTLI_NUM_DISTANCE_SHORT_CODES. */
+const windowGap = 16
+
+func maxBackwardLimit(W uint) uint {
+ return (uint(1) << W) - windowGap
+}
diff --git a/vendor/github.com/andybalholm/brotli/context.go b/vendor/github.com/andybalholm/brotli/context.go
new file mode 100644
index 0000000..884ff8a
--- /dev/null
+++ b/vendor/github.com/andybalholm/brotli/context.go
@@ -0,0 +1,2176 @@
+package brotli
+
+/* Lookup table to map the previous two bytes to a context id.
+
+There are four different context modeling modes defined here:
+ contextLSB6: context id is the least significant 6 bits of the last byte,
+ contextMSB6: context id is the most significant 6 bits of the last byte,
+ contextUTF8: second-order context model tuned for UTF8-encoded text,
+ contextSigned: second-order context model tuned for signed integers.
+
+If |p1| and |p2| are the previous two bytes, and |mode| is current context
+mode, we calculate the context as:
+
+ context = ContextLut(mode)[p1] | ContextLut(mode)[p2 + 256].
+
+For contextUTF8 mode, if the previous two bytes are ASCII characters
+(i.e. < 128), this will be equivalent to
+
+ context = 4 * context1(p1) + context2(p2),
+
+where context1 is based on the previous byte in the following way:
+
+ 0 : non-ASCII control
+ 1 : \t, \n, \r
+ 2 : space
+ 3 : other punctuation
+ 4 : " '
+ 5 : %
+ 6 : ( < [ {
+ 7 : ) > ] }
+ 8 : , ; :
+ 9 : .
+ 10 : =
+ 11 : number
+ 12 : upper-case vowel
+ 13 : upper-case consonant
+ 14 : lower-case vowel
+ 15 : lower-case consonant
+
+and context2 is based on the second last byte:
+
+ 0 : control, space
+ 1 : punctuation
+ 2 : upper-case letter, number
+ 3 : lower-case letter
+
+If the last byte is ASCII, and the second last byte is not (in a valid UTF8
+stream it will be a continuation byte, value between 128 and 191), the
+context is the same as if the second last byte was an ASCII control or space.
+
+If the last byte is a UTF8 lead byte (value >= 192), then the next byte will
+be a continuation byte and the context id is 2 or 3 depending on the LSB of
+the last byte and to a lesser extent on the second last byte if it is ASCII.
+
+If the last byte is a UTF8 continuation byte, the second last byte can be:
+ - continuation byte: the next byte is probably ASCII or lead byte (assuming
+ 4-byte UTF8 characters are rare) and the context id is 0 or 1.
+ - lead byte (192 - 207): next byte is ASCII or lead byte, context is 0 or 1
+ - lead byte (208 - 255): next byte is continuation byte, context is 2 or 3
+
+The possible value combinations of the previous two bytes, the range of
+context ids and the type of the next byte is summarized in the table below:
+
+|--------\-----------------------------------------------------------------|
+| \ Last byte |
+| Second \---------------------------------------------------------------|
+| last byte \ ASCII | cont. byte | lead byte |
+| \ (0-127) | (128-191) | (192-) |
+|=============|===================|=====================|==================|
+| ASCII | next: ASCII/lead | not valid | next: cont. |
+| (0-127) | context: 4 - 63 | | context: 2 - 3 |
+|-------------|-------------------|---------------------|------------------|
+| cont. byte | next: ASCII/lead | next: ASCII/lead | next: cont. |
+| (128-191) | context: 4 - 63 | context: 0 - 1 | context: 2 - 3 |
+|-------------|-------------------|---------------------|------------------|
+| lead byte | not valid | next: ASCII/lead | not valid |
+| (192-207) | | context: 0 - 1 | |
+|-------------|-------------------|---------------------|------------------|
+| lead byte | not valid | next: cont. | not valid |
+| (208-) | | context: 2 - 3 | |
+|-------------|-------------------|---------------------|------------------|
+*/
+
+const (
+ contextLSB6 = 0
+ contextMSB6 = 1
+ contextUTF8 = 2
+ contextSigned = 3
+)
+
+/* Common context lookup table for all context modes. */
+var kContextLookup = [2048]byte{
+ /* CONTEXT_LSB6, last byte. */
+ 0,
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8,
+ 9,
+ 10,
+ 11,
+ 12,
+ 13,
+ 14,
+ 15,
+ 16,
+ 17,
+ 18,
+ 19,
+ 20,
+ 21,
+ 22,
+ 23,
+ 24,
+ 25,
+ 26,
+ 27,
+ 28,
+ 29,
+ 30,
+ 31,
+ 32,
+ 33,
+ 34,
+ 35,
+ 36,
+ 37,
+ 38,
+ 39,
+ 40,
+ 41,
+ 42,
+ 43,
+ 44,
+ 45,
+ 46,
+ 47,
+ 48,
+ 49,
+ 50,
+ 51,
+ 52,
+ 53,
+ 54,
+ 55,
+ 56,
+ 57,
+ 58,
+ 59,
+ 60,
+ 61,
+ 62,
+ 63,
+ 0,
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8,
+ 9,
+ 10,
+ 11,
+ 12,
+ 13,
+ 14,
+ 15,
+ 16,
+ 17,
+ 18,
+ 19,
+ 20,
+ 21,
+ 22,
+ 23,
+ 24,
+ 25,
+ 26,
+ 27,
+ 28,
+ 29,
+ 30,
+ 31,
+ 32,
+ 33,
+ 34,
+ 35,
+ 36,
+ 37,
+ 38,
+ 39,
+ 40,
+ 41,
+ 42,
+ 43,
+ 44,
+ 45,
+ 46,
+ 47,
+ 48,
+ 49,
+ 50,
+ 51,
+ 52,
+ 53,
+ 54,
+ 55,
+ 56,
+ 57,
+ 58,
+ 59,
+ 60,
+ 61,
+ 62,
+ 63,
+ 0,
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8,
+ 9,
+ 10,
+ 11,
+ 12,
+ 13,
+ 14,
+ 15,
+ 16,
+ 17,
+ 18,
+ 19,
+ 20,
+ 21,
+ 22,
+ 23,
+ 24,
+ 25,
+ 26,
+ 27,
+ 28,
+ 29,
+ 30,
+ 31,
+ 32,
+ 33,
+ 34,
+ 35,
+ 36,
+ 37,
+ 38,
+ 39,
+ 40,
+ 41,
+ 42,
+ 43,
+ 44,
+ 45,
+ 46,
+ 47,
+ 48,
+ 49,
+ 50,
+ 51,
+ 52,
+ 53,
+ 54,
+ 55,
+ 56,
+ 57,
+ 58,
+ 59,
+ 60,
+ 61,
+ 62,
+ 63,
+ 0,
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8,
+ 9,
+ 10,
+ 11,
+ 12,
+ 13,
+ 14,
+ 15,
+ 16,
+ 17,
+ 18,
+ 19,
+ 20,
+ 21,
+ 22,
+ 23,
+ 24,
+ 25,
+ 26,
+ 27,
+ 28,
+ 29,
+ 30,
+ 31,
+ 32,
+ 33,
+ 34,
+ 35,
+ 36,
+ 37,
+ 38,
+ 39,
+ 40,
+ 41,
+ 42,
+ 43,
+ 44,
+ 45,
+ 46,
+ 47,
+ 48,
+ 49,
+ 50,
+ 51,
+ 52,
+ 53,
+ 54,
+ 55,
+ 56,
+ 57,
+ 58,
+ 59,
+ 60,
+ 61,
+ 62,
+ 63,
+
+ /* CONTEXT_LSB6, second last byte, */
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+
+ /* CONTEXT_MSB6, last byte. */
+ 0,
+ 0,
+ 0,
+ 0,
+ 1,
+ 1,
+ 1,
+ 1,
+ 2,
+ 2,
+ 2,
+ 2,
+ 3,
+ 3,
+ 3,
+ 3,
+ 4,
+ 4,
+ 4,
+ 4,
+ 5,
+ 5,
+ 5,
+ 5,
+ 6,
+ 6,
+ 6,
+ 6,
+ 7,
+ 7,
+ 7,
+ 7,
+ 8,
+ 8,
+ 8,
+ 8,
+ 9,
+ 9,
+ 9,
+ 9,
+ 10,
+ 10,
+ 10,
+ 10,
+ 11,
+ 11,
+ 11,
+ 11,
+ 12,
+ 12,
+ 12,
+ 12,
+ 13,
+ 13,
+ 13,
+ 13,
+ 14,
+ 14,
+ 14,
+ 14,
+ 15,
+ 15,
+ 15,
+ 15,
+ 16,
+ 16,
+ 16,
+ 16,
+ 17,
+ 17,
+ 17,
+ 17,
+ 18,
+ 18,
+ 18,
+ 18,
+ 19,
+ 19,
+ 19,
+ 19,
+ 20,
+ 20,
+ 20,
+ 20,
+ 21,
+ 21,
+ 21,
+ 21,
+ 22,
+ 22,
+ 22,
+ 22,
+ 23,
+ 23,
+ 23,
+ 23,
+ 24,
+ 24,
+ 24,
+ 24,
+ 25,
+ 25,
+ 25,
+ 25,
+ 26,
+ 26,
+ 26,
+ 26,
+ 27,
+ 27,
+ 27,
+ 27,
+ 28,
+ 28,
+ 28,
+ 28,
+ 29,
+ 29,
+ 29,
+ 29,
+ 30,
+ 30,
+ 30,
+ 30,
+ 31,
+ 31,
+ 31,
+ 31,
+ 32,
+ 32,
+ 32,
+ 32,
+ 33,
+ 33,
+ 33,
+ 33,
+ 34,
+ 34,
+ 34,
+ 34,
+ 35,
+ 35,
+ 35,
+ 35,
+ 36,
+ 36,
+ 36,
+ 36,
+ 37,
+ 37,
+ 37,
+ 37,
+ 38,
+ 38,
+ 38,
+ 38,
+ 39,
+ 39,
+ 39,
+ 39,
+ 40,
+ 40,
+ 40,
+ 40,
+ 41,
+ 41,
+ 41,
+ 41,
+ 42,
+ 42,
+ 42,
+ 42,
+ 43,
+ 43,
+ 43,
+ 43,
+ 44,
+ 44,
+ 44,
+ 44,
+ 45,
+ 45,
+ 45,
+ 45,
+ 46,
+ 46,
+ 46,
+ 46,
+ 47,
+ 47,
+ 47,
+ 47,
+ 48,
+ 48,
+ 48,
+ 48,
+ 49,
+ 49,
+ 49,
+ 49,
+ 50,
+ 50,
+ 50,
+ 50,
+ 51,
+ 51,
+ 51,
+ 51,
+ 52,
+ 52,
+ 52,
+ 52,
+ 53,
+ 53,
+ 53,
+ 53,
+ 54,
+ 54,
+ 54,
+ 54,
+ 55,
+ 55,
+ 55,
+ 55,
+ 56,
+ 56,
+ 56,
+ 56,
+ 57,
+ 57,
+ 57,
+ 57,
+ 58,
+ 58,
+ 58,
+ 58,
+ 59,
+ 59,
+ 59,
+ 59,
+ 60,
+ 60,
+ 60,
+ 60,
+ 61,
+ 61,
+ 61,
+ 61,
+ 62,
+ 62,
+ 62,
+ 62,
+ 63,
+ 63,
+ 63,
+ 63,
+
+ /* CONTEXT_MSB6, second last byte, */
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+
+ /* CONTEXT_UTF8, last byte. */
+ /* ASCII range. */
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4,
+ 4,
+ 0,
+ 0,
+ 4,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8,
+ 12,
+ 16,
+ 12,
+ 12,
+ 20,
+ 12,
+ 16,
+ 24,
+ 28,
+ 12,
+ 12,
+ 32,
+ 12,
+ 36,
+ 12,
+ 44,
+ 44,
+ 44,
+ 44,
+ 44,
+ 44,
+ 44,
+ 44,
+ 44,
+ 44,
+ 32,
+ 32,
+ 24,
+ 40,
+ 28,
+ 12,
+ 12,
+ 48,
+ 52,
+ 52,
+ 52,
+ 48,
+ 52,
+ 52,
+ 52,
+ 48,
+ 52,
+ 52,
+ 52,
+ 52,
+ 52,
+ 48,
+ 52,
+ 52,
+ 52,
+ 52,
+ 52,
+ 48,
+ 52,
+ 52,
+ 52,
+ 52,
+ 52,
+ 24,
+ 12,
+ 28,
+ 12,
+ 12,
+ 12,
+ 56,
+ 60,
+ 60,
+ 60,
+ 56,
+ 60,
+ 60,
+ 60,
+ 56,
+ 60,
+ 60,
+ 60,
+ 60,
+ 60,
+ 56,
+ 60,
+ 60,
+ 60,
+ 60,
+ 60,
+ 56,
+ 60,
+ 60,
+ 60,
+ 60,
+ 60,
+ 24,
+ 12,
+ 28,
+ 12,
+ 0,
+
+ /* UTF8 continuation byte range. */
+ 0,
+ 1,
+ 0,
+ 1,
+ 0,
+ 1,
+ 0,
+ 1,
+ 0,
+ 1,
+ 0,
+ 1,
+ 0,
+ 1,
+ 0,
+ 1,
+ 0,
+ 1,
+ 0,
+ 1,
+ 0,
+ 1,
+ 0,
+ 1,
+ 0,
+ 1,
+ 0,
+ 1,
+ 0,
+ 1,
+ 0,
+ 1,
+ 0,
+ 1,
+ 0,
+ 1,
+ 0,
+ 1,
+ 0,
+ 1,
+ 0,
+ 1,
+ 0,
+ 1,
+ 0,
+ 1,
+ 0,
+ 1,
+ 0,
+ 1,
+ 0,
+ 1,
+ 0,
+ 1,
+ 0,
+ 1,
+ 0,
+ 1,
+ 0,
+ 1,
+ 0,
+ 1,
+ 0,
+ 1,
+
+ /* UTF8 lead byte range. */
+ 2,
+ 3,
+ 2,
+ 3,
+ 2,
+ 3,
+ 2,
+ 3,
+ 2,
+ 3,
+ 2,
+ 3,
+ 2,
+ 3,
+ 2,
+ 3,
+ 2,
+ 3,
+ 2,
+ 3,
+ 2,
+ 3,
+ 2,
+ 3,
+ 2,
+ 3,
+ 2,
+ 3,
+ 2,
+ 3,
+ 2,
+ 3,
+ 2,
+ 3,
+ 2,
+ 3,
+ 2,
+ 3,
+ 2,
+ 3,
+ 2,
+ 3,
+ 2,
+ 3,
+ 2,
+ 3,
+ 2,
+ 3,
+ 2,
+ 3,
+ 2,
+ 3,
+ 2,
+ 3,
+ 2,
+ 3,
+ 2,
+ 3,
+ 2,
+ 3,
+ 2,
+ 3,
+ 2,
+ 3,
+
+ /* CONTEXT_UTF8 second last byte. */
+ /* ASCII range. */
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 1,
+ 1,
+ 1,
+ 1,
+ 0,
+
+ /* UTF8 continuation byte range. */
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+
+ /* UTF8 lead byte range. */
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+
+ /* CONTEXT_SIGNED, last byte, same as the above values shifted by 3 bits. */
+ 0,
+ 8,
+ 8,
+ 8,
+ 8,
+ 8,
+ 8,
+ 8,
+ 8,
+ 8,
+ 8,
+ 8,
+ 8,
+ 8,
+ 8,
+ 8,
+ 16,
+ 16,
+ 16,
+ 16,
+ 16,
+ 16,
+ 16,
+ 16,
+ 16,
+ 16,
+ 16,
+ 16,
+ 16,
+ 16,
+ 16,
+ 16,
+ 16,
+ 16,
+ 16,
+ 16,
+ 16,
+ 16,
+ 16,
+ 16,
+ 16,
+ 16,
+ 16,
+ 16,
+ 16,
+ 16,
+ 16,
+ 16,
+ 16,
+ 16,
+ 16,
+ 16,
+ 16,
+ 16,
+ 16,
+ 16,
+ 16,
+ 16,
+ 16,
+ 16,
+ 16,
+ 16,
+ 16,
+ 16,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 40,
+ 40,
+ 40,
+ 40,
+ 40,
+ 40,
+ 40,
+ 40,
+ 40,
+ 40,
+ 40,
+ 40,
+ 40,
+ 40,
+ 40,
+ 40,
+ 40,
+ 40,
+ 40,
+ 40,
+ 40,
+ 40,
+ 40,
+ 40,
+ 40,
+ 40,
+ 40,
+ 40,
+ 40,
+ 40,
+ 40,
+ 40,
+ 40,
+ 40,
+ 40,
+ 40,
+ 40,
+ 40,
+ 40,
+ 40,
+ 40,
+ 40,
+ 40,
+ 40,
+ 40,
+ 40,
+ 40,
+ 40,
+ 48,
+ 48,
+ 48,
+ 48,
+ 48,
+ 48,
+ 48,
+ 48,
+ 48,
+ 48,
+ 48,
+ 48,
+ 48,
+ 48,
+ 48,
+ 56,
+
+ /* CONTEXT_SIGNED, second last byte. */
+ 0,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 5,
+ 5,
+ 5,
+ 5,
+ 5,
+ 5,
+ 5,
+ 5,
+ 5,
+ 5,
+ 5,
+ 5,
+ 5,
+ 5,
+ 5,
+ 5,
+ 5,
+ 5,
+ 5,
+ 5,
+ 5,
+ 5,
+ 5,
+ 5,
+ 5,
+ 5,
+ 5,
+ 5,
+ 5,
+ 5,
+ 5,
+ 5,
+ 5,
+ 5,
+ 5,
+ 5,
+ 5,
+ 5,
+ 5,
+ 5,
+ 5,
+ 5,
+ 5,
+ 5,
+ 5,
+ 5,
+ 5,
+ 5,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 7,
+}
+
+type contextLUT []byte
+
+func getContextLUT(mode int) contextLUT {
+ return kContextLookup[mode<<9:]
+}
+
+func getContext(p1 byte, p2 byte, lut contextLUT) byte {
+ return lut[p1] | lut[256+int(p2)]
+}
diff --git a/vendor/github.com/andybalholm/brotli/decode.go b/vendor/github.com/andybalholm/brotli/decode.go
new file mode 100644
index 0000000..9d9513b
--- /dev/null
+++ b/vendor/github.com/andybalholm/brotli/decode.go
@@ -0,0 +1,2581 @@
+package brotli
+
+/* Copyright 2013 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+const (
+ decoderResultError = 0
+ decoderResultSuccess = 1
+ decoderResultNeedsMoreInput = 2
+ decoderResultNeedsMoreOutput = 3
+)
+
+/**
+ * Error code for detailed logging / production debugging.
+ *
+ * See ::BrotliDecoderGetErrorCode and ::BROTLI_LAST_ERROR_CODE.
+ */
+const (
+ decoderNoError = 0
+ decoderSuccess = 1
+ decoderNeedsMoreInput = 2
+ decoderNeedsMoreOutput = 3
+ decoderErrorFormatExuberantNibble = -1
+ decoderErrorFormatReserved = -2
+ decoderErrorFormatExuberantMetaNibble = -3
+ decoderErrorFormatSimpleHuffmanAlphabet = -4
+ decoderErrorFormatSimpleHuffmanSame = -5
+ decoderErrorFormatClSpace = -6
+ decoderErrorFormatHuffmanSpace = -7
+ decoderErrorFormatContextMapRepeat = -8
+ decoderErrorFormatBlockLength1 = -9
+ decoderErrorFormatBlockLength2 = -10
+ decoderErrorFormatTransform = -11
+ decoderErrorFormatDictionary = -12
+ decoderErrorFormatWindowBits = -13
+ decoderErrorFormatPadding1 = -14
+ decoderErrorFormatPadding2 = -15
+ decoderErrorFormatDistance = -16
+ decoderErrorDictionaryNotSet = -19
+ decoderErrorInvalidArguments = -20
+ decoderErrorAllocContextModes = -21
+ decoderErrorAllocTreeGroups = -22
+ decoderErrorAllocContextMap = -25
+ decoderErrorAllocRingBuffer1 = -26
+ decoderErrorAllocRingBuffer2 = -27
+ decoderErrorAllocBlockTypeTrees = -30
+ decoderErrorUnreachable = -31
+)
+
+const huffmanTableBits = 8
+
+const huffmanTableMask = 0xFF
+
+/* We need the slack region for the following reasons:
+ - doing up to two 16-byte copies for fast backward copying
+ - inserting transformed dictionary word (5 prefix + 24 base + 8 suffix) */
+const kRingBufferWriteAheadSlack uint32 = 42
+
+var kCodeLengthCodeOrder = [codeLengthCodes]byte{1, 2, 3, 4, 0, 5, 17, 6, 16, 7, 8, 9, 10, 11, 12, 13, 14, 15}
+
+/* Static prefix code for the complex code length code lengths. */
+var kCodeLengthPrefixLength = [16]byte{2, 2, 2, 3, 2, 2, 2, 4, 2, 2, 2, 3, 2, 2, 2, 4}
+
+var kCodeLengthPrefixValue = [16]byte{0, 4, 3, 2, 0, 4, 3, 1, 0, 4, 3, 2, 0, 4, 3, 5}
+
+/* Saves error code and converts it to BrotliDecoderResult. */
+func saveErrorCode(s *Reader, e int) int {
+ s.error_code = int(e)
+ switch e {
+ case decoderSuccess:
+ return decoderResultSuccess
+
+ case decoderNeedsMoreInput:
+ return decoderResultNeedsMoreInput
+
+ case decoderNeedsMoreOutput:
+ return decoderResultNeedsMoreOutput
+
+ default:
+ return decoderResultError
+ }
+}
+
+/* Decodes WBITS by reading 1 - 7 bits, or 0x11 for "Large Window Brotli".
+ Precondition: bit-reader accumulator has at least 8 bits. */
+func decodeWindowBits(s *Reader, br *bitReader) int {
+ var n uint32
+ var large_window bool = s.large_window
+ s.large_window = false
+ takeBits(br, 1, &n)
+ if n == 0 {
+ s.window_bits = 16
+ return decoderSuccess
+ }
+
+ takeBits(br, 3, &n)
+ if n != 0 {
+ s.window_bits = 17 + n
+ return decoderSuccess
+ }
+
+ takeBits(br, 3, &n)
+ if n == 1 {
+ if large_window {
+ takeBits(br, 1, &n)
+ if n == 1 {
+ return decoderErrorFormatWindowBits
+ }
+
+ s.large_window = true
+ return decoderSuccess
+ } else {
+ return decoderErrorFormatWindowBits
+ }
+ }
+
+ if n != 0 {
+ s.window_bits = 8 + n
+ return decoderSuccess
+ }
+
+ s.window_bits = 17
+ return decoderSuccess
+}
+
+/* Decodes a number in the range [0..255], by reading 1 - 11 bits. */
+func decodeVarLenUint8(s *Reader, br *bitReader, value *uint32) int {
+ var bits uint32
+ switch s.substate_decode_uint8 {
+ case stateDecodeUint8None:
+ if !safeReadBits(br, 1, &bits) {
+ return decoderNeedsMoreInput
+ }
+
+ if bits == 0 {
+ *value = 0
+ return decoderSuccess
+ }
+ fallthrough
+
+ /* Fall through. */
+ case stateDecodeUint8Short:
+ if !safeReadBits(br, 3, &bits) {
+ s.substate_decode_uint8 = stateDecodeUint8Short
+ return decoderNeedsMoreInput
+ }
+
+ if bits == 0 {
+ *value = 1
+ s.substate_decode_uint8 = stateDecodeUint8None
+ return decoderSuccess
+ }
+
+ /* Use output value as a temporary storage. It MUST be persisted. */
+ *value = bits
+ fallthrough
+
+ /* Fall through. */
+ case stateDecodeUint8Long:
+ if !safeReadBits(br, *value, &bits) {
+ s.substate_decode_uint8 = stateDecodeUint8Long
+ return decoderNeedsMoreInput
+ }
+
+ *value = (1 << *value) + bits
+ s.substate_decode_uint8 = stateDecodeUint8None
+ return decoderSuccess
+
+ default:
+ return decoderErrorUnreachable
+ }
+}
+
+/* Decodes a metablock length and flags by reading 2 - 31 bits. */
+func decodeMetaBlockLength(s *Reader, br *bitReader) int {
+ var bits uint32
+ var i int
+ for {
+ switch s.substate_metablock_header {
+ case stateMetablockHeaderNone:
+ if !safeReadBits(br, 1, &bits) {
+ return decoderNeedsMoreInput
+ }
+
+ if bits != 0 {
+ s.is_last_metablock = 1
+ } else {
+ s.is_last_metablock = 0
+ }
+ s.meta_block_remaining_len = 0
+ s.is_uncompressed = 0
+ s.is_metadata = 0
+ if s.is_last_metablock == 0 {
+ s.substate_metablock_header = stateMetablockHeaderNibbles
+ break
+ }
+
+ s.substate_metablock_header = stateMetablockHeaderEmpty
+ fallthrough
+
+ /* Fall through. */
+ case stateMetablockHeaderEmpty:
+ if !safeReadBits(br, 1, &bits) {
+ return decoderNeedsMoreInput
+ }
+
+ if bits != 0 {
+ s.substate_metablock_header = stateMetablockHeaderNone
+ return decoderSuccess
+ }
+
+ s.substate_metablock_header = stateMetablockHeaderNibbles
+ fallthrough
+
+ /* Fall through. */
+ case stateMetablockHeaderNibbles:
+ if !safeReadBits(br, 2, &bits) {
+ return decoderNeedsMoreInput
+ }
+
+ s.size_nibbles = uint(byte(bits + 4))
+ s.loop_counter = 0
+ if bits == 3 {
+ s.is_metadata = 1
+ s.substate_metablock_header = stateMetablockHeaderReserved
+ break
+ }
+
+ s.substate_metablock_header = stateMetablockHeaderSize
+ fallthrough
+
+ /* Fall through. */
+ case stateMetablockHeaderSize:
+ i = s.loop_counter
+
+ for ; i < int(s.size_nibbles); i++ {
+ if !safeReadBits(br, 4, &bits) {
+ s.loop_counter = i
+ return decoderNeedsMoreInput
+ }
+
+ if uint(i+1) == s.size_nibbles && s.size_nibbles > 4 && bits == 0 {
+ return decoderErrorFormatExuberantNibble
+ }
+
+ s.meta_block_remaining_len |= int(bits << uint(i*4))
+ }
+
+ s.substate_metablock_header = stateMetablockHeaderUncompressed
+ fallthrough
+
+ /* Fall through. */
+ case stateMetablockHeaderUncompressed:
+ if s.is_last_metablock == 0 {
+ if !safeReadBits(br, 1, &bits) {
+ return decoderNeedsMoreInput
+ }
+
+ if bits != 0 {
+ s.is_uncompressed = 1
+ } else {
+ s.is_uncompressed = 0
+ }
+ }
+
+ s.meta_block_remaining_len++
+ s.substate_metablock_header = stateMetablockHeaderNone
+ return decoderSuccess
+
+ case stateMetablockHeaderReserved:
+ if !safeReadBits(br, 1, &bits) {
+ return decoderNeedsMoreInput
+ }
+
+ if bits != 0 {
+ return decoderErrorFormatReserved
+ }
+
+ s.substate_metablock_header = stateMetablockHeaderBytes
+ fallthrough
+
+ /* Fall through. */
+ case stateMetablockHeaderBytes:
+ if !safeReadBits(br, 2, &bits) {
+ return decoderNeedsMoreInput
+ }
+
+ if bits == 0 {
+ s.substate_metablock_header = stateMetablockHeaderNone
+ return decoderSuccess
+ }
+
+ s.size_nibbles = uint(byte(bits))
+ s.substate_metablock_header = stateMetablockHeaderMetadata
+ fallthrough
+
+ /* Fall through. */
+ case stateMetablockHeaderMetadata:
+ i = s.loop_counter
+
+ for ; i < int(s.size_nibbles); i++ {
+ if !safeReadBits(br, 8, &bits) {
+ s.loop_counter = i
+ return decoderNeedsMoreInput
+ }
+
+ if uint(i+1) == s.size_nibbles && s.size_nibbles > 1 && bits == 0 {
+ return decoderErrorFormatExuberantMetaNibble
+ }
+
+ s.meta_block_remaining_len |= int(bits << uint(i*8))
+ }
+
+ s.meta_block_remaining_len++
+ s.substate_metablock_header = stateMetablockHeaderNone
+ return decoderSuccess
+
+ default:
+ return decoderErrorUnreachable
+ }
+ }
+}
+
+/* Decodes the Huffman code.
+ This method doesn't read data from the bit reader, BUT drops the amount of
+ bits that correspond to the decoded symbol.
+ bits MUST contain at least 15 (BROTLI_HUFFMAN_MAX_CODE_LENGTH) valid bits. */
+func decodeSymbol(bits uint32, table []huffmanCode, br *bitReader) uint32 {
+ table = table[bits&huffmanTableMask:]
+ if table[0].bits > huffmanTableBits {
+ var nbits uint32 = uint32(table[0].bits) - huffmanTableBits
+ dropBits(br, huffmanTableBits)
+ table = table[uint32(table[0].value)+((bits>>huffmanTableBits)&bitMask(nbits)):]
+ }
+
+ dropBits(br, uint32(table[0].bits))
+ return uint32(table[0].value)
+}
+
+/* Reads and decodes the next Huffman code from bit-stream.
+ This method peeks 16 bits of input and drops 0 - 15 of them. */
+func readSymbol(table []huffmanCode, br *bitReader) uint32 {
+ return decodeSymbol(get16BitsUnmasked(br), table, br)
+}
+
+/* Same as DecodeSymbol, but it is known that there is less than 15 bits of
+ input are currently available. */
+func safeDecodeSymbol(table []huffmanCode, br *bitReader, result *uint32) bool {
+ var val uint32
+ var available_bits uint32 = getAvailableBits(br)
+ if available_bits == 0 {
+ if table[0].bits == 0 {
+ *result = uint32(table[0].value)
+ return true
+ }
+
+ return false /* No valid bits at all. */
+ }
+
+ val = uint32(getBitsUnmasked(br))
+ table = table[val&huffmanTableMask:]
+ if table[0].bits <= huffmanTableBits {
+ if uint32(table[0].bits) <= available_bits {
+ dropBits(br, uint32(table[0].bits))
+ *result = uint32(table[0].value)
+ return true
+ } else {
+ return false /* Not enough bits for the first level. */
+ }
+ }
+
+ if available_bits <= huffmanTableBits {
+ return false /* Not enough bits to move to the second level. */
+ }
+
+ /* Speculatively drop HUFFMAN_TABLE_BITS. */
+ val = (val & bitMask(uint32(table[0].bits))) >> huffmanTableBits
+
+ available_bits -= huffmanTableBits
+ table = table[uint32(table[0].value)+val:]
+ if available_bits < uint32(table[0].bits) {
+ return false /* Not enough bits for the second level. */
+ }
+
+ dropBits(br, huffmanTableBits+uint32(table[0].bits))
+ *result = uint32(table[0].value)
+ return true
+}
+
+func safeReadSymbol(table []huffmanCode, br *bitReader, result *uint32) bool {
+ var val uint32
+ if safeGetBits(br, 15, &val) {
+ *result = decodeSymbol(val, table, br)
+ return true
+ }
+
+ return safeDecodeSymbol(table, br, result)
+}
+
+/* Makes a look-up in first level Huffman table. Peeks 8 bits. */
+func preloadSymbol(safe int, table []huffmanCode, br *bitReader, bits *uint32, value *uint32) {
+ if safe != 0 {
+ return
+ }
+
+ table = table[getBits(br, huffmanTableBits):]
+ *bits = uint32(table[0].bits)
+ *value = uint32(table[0].value)
+}
+
+/* Decodes the next Huffman code using data prepared by PreloadSymbol.
+ Reads 0 - 15 bits. Also peeks 8 following bits. */
+func readPreloadedSymbol(table []huffmanCode, br *bitReader, bits *uint32, value *uint32) uint32 {
+ var result uint32 = *value
+ var ext []huffmanCode
+ if *bits > huffmanTableBits {
+ var val uint32 = get16BitsUnmasked(br)
+ ext = table[val&huffmanTableMask:][*value:]
+ var mask uint32 = bitMask((*bits - huffmanTableBits))
+ dropBits(br, huffmanTableBits)
+ ext = ext[(val>>huffmanTableBits)&mask:]
+ dropBits(br, uint32(ext[0].bits))
+ result = uint32(ext[0].value)
+ } else {
+ dropBits(br, *bits)
+ }
+
+ preloadSymbol(0, table, br, bits, value)
+ return result
+}
+
+func log2Floor(x uint32) uint32 {
+ var result uint32 = 0
+ for x != 0 {
+ x >>= 1
+ result++
+ }
+
+ return result
+}
+
+/* Reads (s->symbol + 1) symbols.
+ Totally 1..4 symbols are read, 1..11 bits each.
+ The list of symbols MUST NOT contain duplicates. */
+func readSimpleHuffmanSymbols(alphabet_size uint32, max_symbol uint32, s *Reader) int {
+ var br *bitReader = &s.br
+ var max_bits uint32 = log2Floor(alphabet_size - 1)
+ var i uint32 = s.sub_loop_counter
+ /* max_bits == 1..11; symbol == 0..3; 1..44 bits will be read. */
+
+ var num_symbols uint32 = s.symbol
+ for i <= num_symbols {
+ var v uint32
+ if !safeReadBits(br, max_bits, &v) {
+ s.sub_loop_counter = i
+ s.substate_huffman = stateHuffmanSimpleRead
+ return decoderNeedsMoreInput
+ }
+
+ if v >= max_symbol {
+ return decoderErrorFormatSimpleHuffmanAlphabet
+ }
+
+ s.symbols_lists_array[i] = uint16(v)
+ i++
+ }
+
+ for i = 0; i < num_symbols; i++ {
+ var k uint32 = i + 1
+ for ; k <= num_symbols; k++ {
+ if s.symbols_lists_array[i] == s.symbols_lists_array[k] {
+ return decoderErrorFormatSimpleHuffmanSame
+ }
+ }
+ }
+
+ return decoderSuccess
+}
+
+/* Process single decoded symbol code length:
+ A) reset the repeat variable
+ B) remember code length (if it is not 0)
+ C) extend corresponding index-chain
+ D) reduce the Huffman space
+ E) update the histogram */
+func processSingleCodeLength(code_len uint32, symbol *uint32, repeat *uint32, space *uint32, prev_code_len *uint32, symbol_lists symbolList, code_length_histo []uint16, next_symbol []int) {
+ *repeat = 0
+ if code_len != 0 { /* code_len == 1..15 */
+ symbolListPut(symbol_lists, next_symbol[code_len], uint16(*symbol))
+ next_symbol[code_len] = int(*symbol)
+ *prev_code_len = code_len
+ *space -= 32768 >> code_len
+ code_length_histo[code_len]++
+ }
+
+ (*symbol)++
+}
+
+/* Process repeated symbol code length.
+ A) Check if it is the extension of previous repeat sequence; if the decoded
+ value is not BROTLI_REPEAT_PREVIOUS_CODE_LENGTH, then it is a new
+ symbol-skip
+ B) Update repeat variable
+ C) Check if operation is feasible (fits alphabet)
+ D) For each symbol do the same operations as in ProcessSingleCodeLength
+
+ PRECONDITION: code_len == BROTLI_REPEAT_PREVIOUS_CODE_LENGTH or
+ code_len == BROTLI_REPEAT_ZERO_CODE_LENGTH */
+func processRepeatedCodeLength(code_len uint32, repeat_delta uint32, alphabet_size uint32, symbol *uint32, repeat *uint32, space *uint32, prev_code_len *uint32, repeat_code_len *uint32, symbol_lists symbolList, code_length_histo []uint16, next_symbol []int) {
+ var old_repeat uint32 /* for BROTLI_REPEAT_ZERO_CODE_LENGTH */ /* for BROTLI_REPEAT_ZERO_CODE_LENGTH */
+ var extra_bits uint32 = 3
+ var new_len uint32 = 0
+ if code_len == repeatPreviousCodeLength {
+ new_len = *prev_code_len
+ extra_bits = 2
+ }
+
+ if *repeat_code_len != new_len {
+ *repeat = 0
+ *repeat_code_len = new_len
+ }
+
+ old_repeat = *repeat
+ if *repeat > 0 {
+ *repeat -= 2
+ *repeat <<= extra_bits
+ }
+
+ *repeat += repeat_delta + 3
+ repeat_delta = *repeat - old_repeat
+ if *symbol+repeat_delta > alphabet_size {
+ *symbol = alphabet_size
+ *space = 0xFFFFF
+ return
+ }
+
+ if *repeat_code_len != 0 {
+ var last uint = uint(*symbol + repeat_delta)
+ var next int = next_symbol[*repeat_code_len]
+ for {
+ symbolListPut(symbol_lists, next, uint16(*symbol))
+ next = int(*symbol)
+ (*symbol)++
+ if (*symbol) == uint32(last) {
+ break
+ }
+ }
+
+ next_symbol[*repeat_code_len] = next
+ *space -= repeat_delta << (15 - *repeat_code_len)
+ code_length_histo[*repeat_code_len] = uint16(uint32(code_length_histo[*repeat_code_len]) + repeat_delta)
+ } else {
+ *symbol += repeat_delta
+ }
+}
+
+/* Reads and decodes symbol codelengths. */
+func readSymbolCodeLengths(alphabet_size uint32, s *Reader) int {
+ var br *bitReader = &s.br
+ var symbol uint32 = s.symbol
+ var repeat uint32 = s.repeat
+ var space uint32 = s.space
+ var prev_code_len uint32 = s.prev_code_len
+ var repeat_code_len uint32 = s.repeat_code_len
+ var symbol_lists symbolList = s.symbol_lists
+ var code_length_histo []uint16 = s.code_length_histo[:]
+ var next_symbol []int = s.next_symbol[:]
+ if !warmupBitReader(br) {
+ return decoderNeedsMoreInput
+ }
+ var p []huffmanCode
+ for symbol < alphabet_size && space > 0 {
+ p = s.table[:]
+ var code_len uint32
+ if !checkInputAmount(br, shortFillBitWindowRead) {
+ s.symbol = symbol
+ s.repeat = repeat
+ s.prev_code_len = prev_code_len
+ s.repeat_code_len = repeat_code_len
+ s.space = space
+ return decoderNeedsMoreInput
+ }
+
+ fillBitWindow16(br)
+ p = p[getBitsUnmasked(br)&uint64(bitMask(huffmanMaxCodeLengthCodeLength)):]
+ dropBits(br, uint32(p[0].bits)) /* Use 1..5 bits. */
+ code_len = uint32(p[0].value) /* code_len == 0..17 */
+ if code_len < repeatPreviousCodeLength {
+ processSingleCodeLength(code_len, &symbol, &repeat, &space, &prev_code_len, symbol_lists, code_length_histo, next_symbol) /* code_len == 16..17, extra_bits == 2..3 */
+ } else {
+ var extra_bits uint32
+ if code_len == repeatPreviousCodeLength {
+ extra_bits = 2
+ } else {
+ extra_bits = 3
+ }
+ var repeat_delta uint32 = uint32(getBitsUnmasked(br)) & bitMask(extra_bits)
+ dropBits(br, extra_bits)
+ processRepeatedCodeLength(code_len, repeat_delta, alphabet_size, &symbol, &repeat, &space, &prev_code_len, &repeat_code_len, symbol_lists, code_length_histo, next_symbol)
+ }
+ }
+
+ s.space = space
+ return decoderSuccess
+}
+
+func safeReadSymbolCodeLengths(alphabet_size uint32, s *Reader) int {
+ var br *bitReader = &s.br
+ var get_byte bool = false
+ var p []huffmanCode
+ for s.symbol < alphabet_size && s.space > 0 {
+ p = s.table[:]
+ var code_len uint32
+ var available_bits uint32
+ var bits uint32 = 0
+ if get_byte && !pullByte(br) {
+ return decoderNeedsMoreInput
+ }
+ get_byte = false
+ available_bits = getAvailableBits(br)
+ if available_bits != 0 {
+ bits = uint32(getBitsUnmasked(br))
+ }
+
+ p = p[bits&bitMask(huffmanMaxCodeLengthCodeLength):]
+ if uint32(p[0].bits) > available_bits {
+ get_byte = true
+ continue
+ }
+
+ code_len = uint32(p[0].value) /* code_len == 0..17 */
+ if code_len < repeatPreviousCodeLength {
+ dropBits(br, uint32(p[0].bits))
+ processSingleCodeLength(code_len, &s.symbol, &s.repeat, &s.space, &s.prev_code_len, s.symbol_lists, s.code_length_histo[:], s.next_symbol[:]) /* code_len == 16..17, extra_bits == 2..3 */
+ } else {
+ var extra_bits uint32 = code_len - 14
+ var repeat_delta uint32 = (bits >> p[0].bits) & bitMask(extra_bits)
+ if available_bits < uint32(p[0].bits)+extra_bits {
+ get_byte = true
+ continue
+ }
+
+ dropBits(br, uint32(p[0].bits)+extra_bits)
+ processRepeatedCodeLength(code_len, repeat_delta, alphabet_size, &s.symbol, &s.repeat, &s.space, &s.prev_code_len, &s.repeat_code_len, s.symbol_lists, s.code_length_histo[:], s.next_symbol[:])
+ }
+ }
+
+ return decoderSuccess
+}
+
+/* Reads and decodes 15..18 codes using static prefix code.
+ Each code is 2..4 bits long. In total 30..72 bits are used. */
+func readCodeLengthCodeLengths(s *Reader) int {
+ var br *bitReader = &s.br
+ var num_codes uint32 = s.repeat
+ var space uint32 = s.space
+ var i uint32 = s.sub_loop_counter
+ for ; i < codeLengthCodes; i++ {
+ var code_len_idx byte = kCodeLengthCodeOrder[i]
+ var ix uint32
+ var v uint32
+ if !safeGetBits(br, 4, &ix) {
+ var available_bits uint32 = getAvailableBits(br)
+ if available_bits != 0 {
+ ix = uint32(getBitsUnmasked(br) & 0xF)
+ } else {
+ ix = 0
+ }
+
+ if uint32(kCodeLengthPrefixLength[ix]) > available_bits {
+ s.sub_loop_counter = i
+ s.repeat = num_codes
+ s.space = space
+ s.substate_huffman = stateHuffmanComplex
+ return decoderNeedsMoreInput
+ }
+ }
+
+ v = uint32(kCodeLengthPrefixValue[ix])
+ dropBits(br, uint32(kCodeLengthPrefixLength[ix]))
+ s.code_length_code_lengths[code_len_idx] = byte(v)
+ if v != 0 {
+ space = space - (32 >> v)
+ num_codes++
+ s.code_length_histo[v]++
+ if space-1 >= 32 {
+ /* space is 0 or wrapped around. */
+ break
+ }
+ }
+ }
+
+ if num_codes != 1 && space != 0 {
+ return decoderErrorFormatClSpace
+ }
+
+ return decoderSuccess
+}
+
+/* Decodes the Huffman tables.
+ There are 2 scenarios:
+ A) Huffman code contains only few symbols (1..4). Those symbols are read
+ directly; their code lengths are defined by the number of symbols.
+ For this scenario 4 - 49 bits will be read.
+
+ B) 2-phase decoding:
+ B.1) Small Huffman table is decoded; it is specified with code lengths
+ encoded with predefined entropy code. 32 - 74 bits are used.
+ B.2) Decoded table is used to decode code lengths of symbols in resulting
+ Huffman table. In worst case 3520 bits are read. */
+func readHuffmanCode(alphabet_size uint32, max_symbol uint32, table []huffmanCode, opt_table_size *uint32, s *Reader) int {
+ var br *bitReader = &s.br
+
+ /* Unnecessary masking, but might be good for safety. */
+ alphabet_size &= 0x7FF
+
+ /* State machine. */
+ for {
+ switch s.substate_huffman {
+ case stateHuffmanNone:
+ if !safeReadBits(br, 2, &s.sub_loop_counter) {
+ return decoderNeedsMoreInput
+ }
+
+ /* The value is used as follows:
+ 1 for simple code;
+ 0 for no skipping, 2 skips 2 code lengths, 3 skips 3 code lengths */
+ if s.sub_loop_counter != 1 {
+ s.space = 32
+ s.repeat = 0 /* num_codes */
+ var i int
+ for i = 0; i <= huffmanMaxCodeLengthCodeLength; i++ {
+ s.code_length_histo[i] = 0
+ }
+
+ for i = 0; i < codeLengthCodes; i++ {
+ s.code_length_code_lengths[i] = 0
+ }
+
+ s.substate_huffman = stateHuffmanComplex
+ continue
+ }
+ fallthrough
+
+ /* Read symbols, codes & code lengths directly. */
+ case stateHuffmanSimpleSize:
+ if !safeReadBits(br, 2, &s.symbol) { /* num_symbols */
+ s.substate_huffman = stateHuffmanSimpleSize
+ return decoderNeedsMoreInput
+ }
+
+ s.sub_loop_counter = 0
+ fallthrough
+
+ case stateHuffmanSimpleRead:
+ {
+ var result int = readSimpleHuffmanSymbols(alphabet_size, max_symbol, s)
+ if result != decoderSuccess {
+ return result
+ }
+ }
+ fallthrough
+
+ case stateHuffmanSimpleBuild:
+ var table_size uint32
+ if s.symbol == 3 {
+ var bits uint32
+ if !safeReadBits(br, 1, &bits) {
+ s.substate_huffman = stateHuffmanSimpleBuild
+ return decoderNeedsMoreInput
+ }
+
+ s.symbol += bits
+ }
+
+ table_size = buildSimpleHuffmanTable(table, huffmanTableBits, s.symbols_lists_array[:], s.symbol)
+ if opt_table_size != nil {
+ *opt_table_size = table_size
+ }
+
+ s.substate_huffman = stateHuffmanNone
+ return decoderSuccess
+
+ /* Decode Huffman-coded code lengths. */
+ case stateHuffmanComplex:
+ {
+ var i uint32
+ var result int = readCodeLengthCodeLengths(s)
+ if result != decoderSuccess {
+ return result
+ }
+
+ buildCodeLengthsHuffmanTable(s.table[:], s.code_length_code_lengths[:], s.code_length_histo[:])
+ for i = 0; i < 16; i++ {
+ s.code_length_histo[i] = 0
+ }
+
+ for i = 0; i <= huffmanMaxCodeLength; i++ {
+ s.next_symbol[i] = int(i) - (huffmanMaxCodeLength + 1)
+ symbolListPut(s.symbol_lists, s.next_symbol[i], 0xFFFF)
+ }
+
+ s.symbol = 0
+ s.prev_code_len = initialRepeatedCodeLength
+ s.repeat = 0
+ s.repeat_code_len = 0
+ s.space = 32768
+ s.substate_huffman = stateHuffmanLengthSymbols
+ }
+ fallthrough
+
+ case stateHuffmanLengthSymbols:
+ var table_size uint32
+ var result int = readSymbolCodeLengths(max_symbol, s)
+ if result == decoderNeedsMoreInput {
+ result = safeReadSymbolCodeLengths(max_symbol, s)
+ }
+
+ if result != decoderSuccess {
+ return result
+ }
+
+ if s.space != 0 {
+ return decoderErrorFormatHuffmanSpace
+ }
+
+ table_size = buildHuffmanTable(table, huffmanTableBits, s.symbol_lists, s.code_length_histo[:])
+ if opt_table_size != nil {
+ *opt_table_size = table_size
+ }
+
+ s.substate_huffman = stateHuffmanNone
+ return decoderSuccess
+
+ default:
+ return decoderErrorUnreachable
+ }
+ }
+}
+
+/* Decodes a block length by reading 3..39 bits. */
+func readBlockLength(table []huffmanCode, br *bitReader) uint32 {
+ var code uint32
+ var nbits uint32
+ code = readSymbol(table, br)
+ nbits = kBlockLengthPrefixCode[code].nbits /* nbits == 2..24 */
+ return kBlockLengthPrefixCode[code].offset + readBits(br, nbits)
+}
+
+/* WARNING: if state is not BROTLI_STATE_READ_BLOCK_LENGTH_NONE, then
+ reading can't be continued with ReadBlockLength. */
+func safeReadBlockLength(s *Reader, result *uint32, table []huffmanCode, br *bitReader) bool {
+ var index uint32
+ if s.substate_read_block_length == stateReadBlockLengthNone {
+ if !safeReadSymbol(table, br, &index) {
+ return false
+ }
+ } else {
+ index = s.block_length_index
+ }
+ {
+ var bits uint32 /* nbits == 2..24 */
+ var nbits uint32 = kBlockLengthPrefixCode[index].nbits
+ if !safeReadBits(br, nbits, &bits) {
+ s.block_length_index = index
+ s.substate_read_block_length = stateReadBlockLengthSuffix
+ return false
+ }
+
+ *result = kBlockLengthPrefixCode[index].offset + bits
+ s.substate_read_block_length = stateReadBlockLengthNone
+ return true
+ }
+}
+
+/* Transform:
+ 1) initialize list L with values 0, 1,... 255
+ 2) For each input element X:
+ 2.1) let Y = L[X]
+ 2.2) remove X-th element from L
+ 2.3) prepend Y to L
+ 2.4) append Y to output
+
+ In most cases max(Y) <= 7, so most of L remains intact.
+ To reduce the cost of initialization, we reuse L, remember the upper bound
+ of Y values, and reinitialize only first elements in L.
+
+ Most of input values are 0 and 1. To reduce number of branches, we replace
+ inner for loop with do-while. */
+func inverseMoveToFrontTransform(v []byte, v_len uint32, state *Reader) {
+ var mtf [256]byte
+ var i int
+ for i = 1; i < 256; i++ {
+ mtf[i] = byte(i)
+ }
+ var mtf_1 byte
+
+ /* Transform the input. */
+ for i = 0; uint32(i) < v_len; i++ {
+ var index int = int(v[i])
+ var value byte = mtf[index]
+ v[i] = value
+ mtf_1 = value
+ for index >= 1 {
+ index--
+ mtf[index+1] = mtf[index]
+ }
+
+ mtf[0] = mtf_1
+ }
+}
+
+/* Decodes a series of Huffman table using ReadHuffmanCode function. */
+func huffmanTreeGroupDecode(group *huffmanTreeGroup, s *Reader) int {
+ if s.substate_tree_group != stateTreeGroupLoop {
+ s.next = group.codes
+ s.htree_index = 0
+ s.substate_tree_group = stateTreeGroupLoop
+ }
+
+ for s.htree_index < int(group.num_htrees) {
+ var table_size uint32
+ var result int = readHuffmanCode(uint32(group.alphabet_size), uint32(group.max_symbol), s.next, &table_size, s)
+ if result != decoderSuccess {
+ return result
+ }
+ group.htrees[s.htree_index] = s.next
+ s.next = s.next[table_size:]
+ s.htree_index++
+ }
+
+ s.substate_tree_group = stateTreeGroupNone
+ return decoderSuccess
+}
+
+/* Decodes a context map.
+ Decoding is done in 4 phases:
+ 1) Read auxiliary information (6..16 bits) and allocate memory.
+ In case of trivial context map, decoding is finished at this phase.
+ 2) Decode Huffman table using ReadHuffmanCode function.
+ This table will be used for reading context map items.
+ 3) Read context map items; "0" values could be run-length encoded.
+ 4) Optionally, apply InverseMoveToFront transform to the resulting map. */
+func decodeContextMap(context_map_size uint32, num_htrees *uint32, context_map_arg *[]byte, s *Reader) int {
+ var br *bitReader = &s.br
+ var result int = decoderSuccess
+
+ switch int(s.substate_context_map) {
+ case stateContextMapNone:
+ result = decodeVarLenUint8(s, br, num_htrees)
+ if result != decoderSuccess {
+ return result
+ }
+
+ (*num_htrees)++
+ s.context_index = 0
+ *context_map_arg = make([]byte, uint(context_map_size))
+ if *context_map_arg == nil {
+ return decoderErrorAllocContextMap
+ }
+
+ if *num_htrees <= 1 {
+ for i := 0; i < int(context_map_size); i++ {
+ (*context_map_arg)[i] = 0
+ }
+ return decoderSuccess
+ }
+
+ s.substate_context_map = stateContextMapReadPrefix
+ fallthrough
+ /* Fall through. */
+ case stateContextMapReadPrefix:
+ {
+ var bits uint32
+
+ /* In next stage ReadHuffmanCode uses at least 4 bits, so it is safe
+ to peek 4 bits ahead. */
+ if !safeGetBits(br, 5, &bits) {
+ return decoderNeedsMoreInput
+ }
+
+ if bits&1 != 0 { /* Use RLE for zeros. */
+ s.max_run_length_prefix = (bits >> 1) + 1
+ dropBits(br, 5)
+ } else {
+ s.max_run_length_prefix = 0
+ dropBits(br, 1)
+ }
+
+ s.substate_context_map = stateContextMapHuffman
+ }
+ fallthrough
+
+ /* Fall through. */
+ case stateContextMapHuffman:
+ {
+ var alphabet_size uint32 = *num_htrees + s.max_run_length_prefix
+ result = readHuffmanCode(alphabet_size, alphabet_size, s.context_map_table[:], nil, s)
+ if result != decoderSuccess {
+ return result
+ }
+ s.code = 0xFFFF
+ s.substate_context_map = stateContextMapDecode
+ }
+ fallthrough
+
+ /* Fall through. */
+ case stateContextMapDecode:
+ {
+ var context_index uint32 = s.context_index
+ var max_run_length_prefix uint32 = s.max_run_length_prefix
+ var context_map []byte = *context_map_arg
+ var code uint32 = s.code
+ var skip_preamble bool = (code != 0xFFFF)
+ for context_index < context_map_size || skip_preamble {
+ if !skip_preamble {
+ if !safeReadSymbol(s.context_map_table[:], br, &code) {
+ s.code = 0xFFFF
+ s.context_index = context_index
+ return decoderNeedsMoreInput
+ }
+
+ if code == 0 {
+ context_map[context_index] = 0
+ context_index++
+ continue
+ }
+
+ if code > max_run_length_prefix {
+ context_map[context_index] = byte(code - max_run_length_prefix)
+ context_index++
+ continue
+ }
+ } else {
+ skip_preamble = false
+ }
+
+ /* RLE sub-stage. */
+ {
+ var reps uint32
+ if !safeReadBits(br, code, &reps) {
+ s.code = code
+ s.context_index = context_index
+ return decoderNeedsMoreInput
+ }
+
+ reps += 1 << code
+ if context_index+reps > context_map_size {
+ return decoderErrorFormatContextMapRepeat
+ }
+
+ for {
+ context_map[context_index] = 0
+ context_index++
+ reps--
+ if reps == 0 {
+ break
+ }
+ }
+ }
+ }
+ }
+ fallthrough
+
+ case stateContextMapTransform:
+ var bits uint32
+ if !safeReadBits(br, 1, &bits) {
+ s.substate_context_map = stateContextMapTransform
+ return decoderNeedsMoreInput
+ }
+
+ if bits != 0 {
+ inverseMoveToFrontTransform(*context_map_arg, context_map_size, s)
+ }
+
+ s.substate_context_map = stateContextMapNone
+ return decoderSuccess
+
+ default:
+ return decoderErrorUnreachable
+ }
+}
+
+/* Decodes a command or literal and updates block type ring-buffer.
+ Reads 3..54 bits. */
+func decodeBlockTypeAndLength(safe int, s *Reader, tree_type int) bool {
+ var max_block_type uint32 = s.num_block_types[tree_type]
+ type_tree := s.block_type_trees[tree_type*huffmanMaxSize258:]
+ len_tree := s.block_len_trees[tree_type*huffmanMaxSize26:]
+ var br *bitReader = &s.br
+ var ringbuffer []uint32 = s.block_type_rb[tree_type*2:]
+ var block_type uint32
+ if max_block_type <= 1 {
+ return false
+ }
+
+ /* Read 0..15 + 3..39 bits. */
+ if safe == 0 {
+ block_type = readSymbol(type_tree, br)
+ s.block_length[tree_type] = readBlockLength(len_tree, br)
+ } else {
+ var memento bitReaderState
+ bitReaderSaveState(br, &memento)
+ if !safeReadSymbol(type_tree, br, &block_type) {
+ return false
+ }
+ if !safeReadBlockLength(s, &s.block_length[tree_type], len_tree, br) {
+ s.substate_read_block_length = stateReadBlockLengthNone
+ bitReaderRestoreState(br, &memento)
+ return false
+ }
+ }
+
+ if block_type == 1 {
+ block_type = ringbuffer[1] + 1
+ } else if block_type == 0 {
+ block_type = ringbuffer[0]
+ } else {
+ block_type -= 2
+ }
+
+ if block_type >= max_block_type {
+ block_type -= max_block_type
+ }
+
+ ringbuffer[0] = ringbuffer[1]
+ ringbuffer[1] = block_type
+ return true
+}
+
+func detectTrivialLiteralBlockTypes(s *Reader) {
+ var i uint
+ for i = 0; i < 8; i++ {
+ s.trivial_literal_contexts[i] = 0
+ }
+ for i = 0; uint32(i) < s.num_block_types[0]; i++ {
+ var offset uint = i << literalContextBits
+ var error uint = 0
+ var sample uint = uint(s.context_map[offset])
+ var j uint
+ for j = 0; j < 1<>5] |= 1 << (i & 31)
+ }
+ }
+}
+
+func prepareLiteralDecoding(s *Reader) {
+ var context_mode byte
+ var trivial uint
+ var block_type uint32 = s.block_type_rb[1]
+ var context_offset uint32 = block_type << literalContextBits
+ s.context_map_slice = s.context_map[context_offset:]
+ trivial = uint(s.trivial_literal_contexts[block_type>>5])
+ s.trivial_literal_context = int((trivial >> (block_type & 31)) & 1)
+ s.literal_htree = []huffmanCode(s.literal_hgroup.htrees[s.context_map_slice[0]])
+ context_mode = s.context_modes[block_type] & 3
+ s.context_lookup = getContextLUT(int(context_mode))
+}
+
+/* Decodes the block type and updates the state for literal context.
+ Reads 3..54 bits. */
+func decodeLiteralBlockSwitchInternal(safe int, s *Reader) bool {
+ if !decodeBlockTypeAndLength(safe, s, 0) {
+ return false
+ }
+
+ prepareLiteralDecoding(s)
+ return true
+}
+
+func decodeLiteralBlockSwitch(s *Reader) {
+ decodeLiteralBlockSwitchInternal(0, s)
+}
+
+func safeDecodeLiteralBlockSwitch(s *Reader) bool {
+ return decodeLiteralBlockSwitchInternal(1, s)
+}
+
+/* Block switch for insert/copy length.
+ Reads 3..54 bits. */
+func decodeCommandBlockSwitchInternal(safe int, s *Reader) bool {
+ if !decodeBlockTypeAndLength(safe, s, 1) {
+ return false
+ }
+
+ s.htree_command = []huffmanCode(s.insert_copy_hgroup.htrees[s.block_type_rb[3]])
+ return true
+}
+
+func decodeCommandBlockSwitch(s *Reader) {
+ decodeCommandBlockSwitchInternal(0, s)
+}
+
+func safeDecodeCommandBlockSwitch(s *Reader) bool {
+ return decodeCommandBlockSwitchInternal(1, s)
+}
+
+/* Block switch for distance codes.
+ Reads 3..54 bits. */
+func decodeDistanceBlockSwitchInternal(safe int, s *Reader) bool {
+ if !decodeBlockTypeAndLength(safe, s, 2) {
+ return false
+ }
+
+ s.dist_context_map_slice = s.dist_context_map[s.block_type_rb[5]< s.ringbuffer_size {
+ pos = uint(s.ringbuffer_size)
+ } else {
+ pos = uint(s.pos)
+ }
+ var partial_pos_rb uint = (s.rb_roundtrips * uint(s.ringbuffer_size)) + pos
+ return partial_pos_rb - s.partial_pos_out
+}
+
+/* Dumps output.
+ Returns BROTLI_DECODER_NEEDS_MORE_OUTPUT only if there is more output to push
+ and either ring-buffer is as big as window size, or |force| is true. */
+func writeRingBuffer(s *Reader, available_out *uint, next_out *[]byte, total_out *uint, force bool) int {
+ start := s.ringbuffer[s.partial_pos_out&uint(s.ringbuffer_mask):]
+ var to_write uint = unwrittenBytes(s, true)
+ var num_written uint = *available_out
+ if num_written > to_write {
+ num_written = to_write
+ }
+
+ if s.meta_block_remaining_len < 0 {
+ return decoderErrorFormatBlockLength1
+ }
+
+ if next_out != nil && *next_out == nil {
+ *next_out = start
+ } else {
+ if next_out != nil {
+ copy(*next_out, start[:num_written])
+ *next_out = (*next_out)[num_written:]
+ }
+ }
+
+ *available_out -= num_written
+ s.partial_pos_out += num_written
+ if total_out != nil {
+ *total_out = s.partial_pos_out
+ }
+
+ if num_written < to_write {
+ if s.ringbuffer_size == 1<= s.ringbuffer_size {
+ s.pos -= s.ringbuffer_size
+ s.rb_roundtrips++
+ if uint(s.pos) != 0 {
+ s.should_wrap_ringbuffer = 1
+ } else {
+ s.should_wrap_ringbuffer = 0
+ }
+ }
+
+ return decoderSuccess
+}
+
+func wrapRingBuffer(s *Reader) {
+ if s.should_wrap_ringbuffer != 0 {
+ copy(s.ringbuffer, s.ringbuffer_end[:uint(s.pos)])
+ s.should_wrap_ringbuffer = 0
+ }
+}
+
+/* Allocates ring-buffer.
+
+ s->ringbuffer_size MUST be updated by BrotliCalculateRingBufferSize before
+ this function is called.
+
+ Last two bytes of ring-buffer are initialized to 0, so context calculation
+ could be done uniformly for the first two and all other positions. */
+func ensureRingBuffer(s *Reader) bool {
+ var old_ringbuffer []byte
+ if s.ringbuffer_size == s.new_ringbuffer_size {
+ return true
+ }
+ spaceNeeded := int(s.new_ringbuffer_size) + int(kRingBufferWriteAheadSlack)
+ if len(s.ringbuffer) < spaceNeeded {
+ old_ringbuffer = s.ringbuffer
+ s.ringbuffer = make([]byte, spaceNeeded)
+ }
+
+ s.ringbuffer[s.new_ringbuffer_size-2] = 0
+ s.ringbuffer[s.new_ringbuffer_size-1] = 0
+
+ if old_ringbuffer != nil {
+ copy(s.ringbuffer, old_ringbuffer[:uint(s.pos)])
+ }
+
+ s.ringbuffer_size = s.new_ringbuffer_size
+ s.ringbuffer_mask = s.new_ringbuffer_size - 1
+ s.ringbuffer_end = s.ringbuffer[s.ringbuffer_size:]
+
+ return true
+}
+
+func copyUncompressedBlockToOutput(available_out *uint, next_out *[]byte, total_out *uint, s *Reader) int {
+ /* TODO: avoid allocation for single uncompressed block. */
+ if !ensureRingBuffer(s) {
+ return decoderErrorAllocRingBuffer1
+ }
+
+ /* State machine */
+ for {
+ switch s.substate_uncompressed {
+ case stateUncompressedNone:
+ {
+ var nbytes int = int(getRemainingBytes(&s.br))
+ if nbytes > s.meta_block_remaining_len {
+ nbytes = s.meta_block_remaining_len
+ }
+
+ if s.pos+nbytes > s.ringbuffer_size {
+ nbytes = s.ringbuffer_size - s.pos
+ }
+
+ /* Copy remaining bytes from s->br.buf_ to ring-buffer. */
+ copyBytes(s.ringbuffer[s.pos:], &s.br, uint(nbytes))
+
+ s.pos += nbytes
+ s.meta_block_remaining_len -= nbytes
+ if s.pos < 1<>1 >= min_size {
+ new_ringbuffer_size >>= 1
+ }
+ }
+
+ s.new_ringbuffer_size = new_ringbuffer_size
+}
+
+/* Reads 1..256 2-bit context modes. */
+func readContextModes(s *Reader) int {
+ var br *bitReader = &s.br
+ var i int = s.loop_counter
+
+ for i < int(s.num_block_types[0]) {
+ var bits uint32
+ if !safeReadBits(br, 2, &bits) {
+ s.loop_counter = i
+ return decoderNeedsMoreInput
+ }
+
+ s.context_modes[i] = byte(bits)
+ i++
+ }
+
+ return decoderSuccess
+}
+
+func takeDistanceFromRingBuffer(s *Reader) {
+ if s.distance_code == 0 {
+ s.dist_rb_idx--
+ s.distance_code = s.dist_rb[s.dist_rb_idx&3]
+
+ /* Compensate double distance-ring-buffer roll for dictionary items. */
+ s.distance_context = 1
+ } else {
+ var distance_code int = s.distance_code << 1
+ const kDistanceShortCodeIndexOffset uint32 = 0xAAAFFF1B
+ const kDistanceShortCodeValueOffset uint32 = 0xFA5FA500
+ var v int = (s.dist_rb_idx + int(kDistanceShortCodeIndexOffset>>uint(distance_code))) & 0x3
+ /* kDistanceShortCodeIndexOffset has 2-bit values from LSB:
+ 3, 2, 1, 0, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2 */
+
+ /* kDistanceShortCodeValueOffset has 2-bit values from LSB:
+ -0, 0,-0, 0,-1, 1,-2, 2,-3, 3,-1, 1,-2, 2,-3, 3 */
+ s.distance_code = s.dist_rb[v]
+
+ v = int(kDistanceShortCodeValueOffset>>uint(distance_code)) & 0x3
+ if distance_code&0x3 != 0 {
+ s.distance_code += v
+ } else {
+ s.distance_code -= v
+ if s.distance_code <= 0 {
+ /* A huge distance will cause a () soon.
+ This is a little faster than failing here. */
+ s.distance_code = 0x7FFFFFFF
+ }
+ }
+ }
+}
+
+func safeReadBitsMaybeZero(br *bitReader, n_bits uint32, val *uint32) bool {
+ if n_bits != 0 {
+ return safeReadBits(br, n_bits, val)
+ } else {
+ *val = 0
+ return true
+ }
+}
+
+/* Precondition: s->distance_code < 0. */
+func readDistanceInternal(safe int, s *Reader, br *bitReader) bool {
+ var distval int
+ var memento bitReaderState
+ var distance_tree []huffmanCode = []huffmanCode(s.distance_hgroup.htrees[s.dist_htree_index])
+ if safe == 0 {
+ s.distance_code = int(readSymbol(distance_tree, br))
+ } else {
+ var code uint32
+ bitReaderSaveState(br, &memento)
+ if !safeReadSymbol(distance_tree, br, &code) {
+ return false
+ }
+
+ s.distance_code = int(code)
+ }
+
+ /* Convert the distance code to the actual distance by possibly
+ looking up past distances from the s->ringbuffer. */
+ s.distance_context = 0
+
+ if s.distance_code&^0xF == 0 {
+ takeDistanceFromRingBuffer(s)
+ s.block_length[2]--
+ return true
+ }
+
+ distval = s.distance_code - int(s.num_direct_distance_codes)
+ if distval >= 0 {
+ var nbits uint32
+ var postfix int
+ var offset int
+ if safe == 0 && (s.distance_postfix_bits == 0) {
+ nbits = (uint32(distval) >> 1) + 1
+ offset = ((2 + (distval & 1)) << nbits) - 4
+ s.distance_code = int(s.num_direct_distance_codes) + offset + int(readBits(br, nbits))
+ } else {
+ /* This branch also works well when s->distance_postfix_bits == 0. */
+ var bits uint32
+ postfix = distval & s.distance_postfix_mask
+ distval >>= s.distance_postfix_bits
+ nbits = (uint32(distval) >> 1) + 1
+ if safe != 0 {
+ if !safeReadBitsMaybeZero(br, nbits, &bits) {
+ s.distance_code = -1 /* Restore precondition. */
+ bitReaderRestoreState(br, &memento)
+ return false
+ }
+ } else {
+ bits = readBits(br, nbits)
+ }
+
+ offset = ((2 + (distval & 1)) << nbits) - 4
+ s.distance_code = int(s.num_direct_distance_codes) + ((offset + int(bits)) << s.distance_postfix_bits) + postfix
+ }
+ }
+
+ s.distance_code = s.distance_code - numDistanceShortCodes + 1
+ s.block_length[2]--
+ return true
+}
+
+func readDistance(s *Reader, br *bitReader) {
+ readDistanceInternal(0, s, br)
+}
+
+func safeReadDistance(s *Reader, br *bitReader) bool {
+ return readDistanceInternal(1, s, br)
+}
+
+func readCommandInternal(safe int, s *Reader, br *bitReader, insert_length *int) bool {
+ var cmd_code uint32
+ var insert_len_extra uint32 = 0
+ var copy_length uint32
+ var v cmdLutElement
+ var memento bitReaderState
+ if safe == 0 {
+ cmd_code = readSymbol(s.htree_command, br)
+ } else {
+ bitReaderSaveState(br, &memento)
+ if !safeReadSymbol(s.htree_command, br, &cmd_code) {
+ return false
+ }
+ }
+
+ v = kCmdLut[cmd_code]
+ s.distance_code = int(v.distance_code)
+ s.distance_context = int(v.context)
+ s.dist_htree_index = s.dist_context_map_slice[s.distance_context]
+ *insert_length = int(v.insert_len_offset)
+ if safe == 0 {
+ if v.insert_len_extra_bits != 0 {
+ insert_len_extra = readBits(br, uint32(v.insert_len_extra_bits))
+ }
+
+ copy_length = readBits(br, uint32(v.copy_len_extra_bits))
+ } else {
+ if !safeReadBitsMaybeZero(br, uint32(v.insert_len_extra_bits), &insert_len_extra) || !safeReadBitsMaybeZero(br, uint32(v.copy_len_extra_bits), ©_length) {
+ bitReaderRestoreState(br, &memento)
+ return false
+ }
+ }
+
+ s.copy_length = int(copy_length) + int(v.copy_len_offset)
+ s.block_length[1]--
+ *insert_length += int(insert_len_extra)
+ return true
+}
+
+func readCommand(s *Reader, br *bitReader, insert_length *int) {
+ readCommandInternal(0, s, br, insert_length)
+}
+
+func safeReadCommand(s *Reader, br *bitReader, insert_length *int) bool {
+ return readCommandInternal(1, s, br, insert_length)
+}
+
+func checkInputAmountMaybeSafe(safe int, br *bitReader, num uint) bool {
+ if safe != 0 {
+ return true
+ }
+
+ return checkInputAmount(br, num)
+}
+
+func processCommandsInternal(safe int, s *Reader) int {
+ var pos int = s.pos
+ var i int = s.loop_counter
+ var result int = decoderSuccess
+ var br *bitReader = &s.br
+ var hc []huffmanCode
+
+ if !checkInputAmountMaybeSafe(safe, br, 28) {
+ result = decoderNeedsMoreInput
+ goto saveStateAndReturn
+ }
+
+ if safe == 0 {
+ warmupBitReader(br)
+ }
+
+ /* Jump into state machine. */
+ if s.state == stateCommandBegin {
+ goto CommandBegin
+ } else if s.state == stateCommandInner {
+ goto CommandInner
+ } else if s.state == stateCommandPostDecodeLiterals {
+ goto CommandPostDecodeLiterals
+ } else if s.state == stateCommandPostWrapCopy {
+ goto CommandPostWrapCopy
+ } else {
+ return decoderErrorUnreachable
+ }
+
+CommandBegin:
+ if safe != 0 {
+ s.state = stateCommandBegin
+ }
+
+ if !checkInputAmountMaybeSafe(safe, br, 28) { /* 156 bits + 7 bytes */
+ s.state = stateCommandBegin
+ result = decoderNeedsMoreInput
+ goto saveStateAndReturn
+ }
+
+ if s.block_length[1] == 0 {
+ if safe != 0 {
+ if !safeDecodeCommandBlockSwitch(s) {
+ result = decoderNeedsMoreInput
+ goto saveStateAndReturn
+ }
+ } else {
+ decodeCommandBlockSwitch(s)
+ }
+
+ goto CommandBegin
+ }
+
+ /* Read the insert/copy length in the command. */
+ if safe != 0 {
+ if !safeReadCommand(s, br, &i) {
+ result = decoderNeedsMoreInput
+ goto saveStateAndReturn
+ }
+ } else {
+ readCommand(s, br, &i)
+ }
+
+ if i == 0 {
+ goto CommandPostDecodeLiterals
+ }
+
+ s.meta_block_remaining_len -= i
+
+CommandInner:
+ if safe != 0 {
+ s.state = stateCommandInner
+ }
+
+ /* Read the literals in the command. */
+ if s.trivial_literal_context != 0 {
+ var bits uint32
+ var value uint32
+ preloadSymbol(safe, s.literal_htree, br, &bits, &value)
+ for {
+ if !checkInputAmountMaybeSafe(safe, br, 28) { /* 162 bits + 7 bytes */
+ s.state = stateCommandInner
+ result = decoderNeedsMoreInput
+ goto saveStateAndReturn
+ }
+
+ if s.block_length[0] == 0 {
+ if safe != 0 {
+ if !safeDecodeLiteralBlockSwitch(s) {
+ result = decoderNeedsMoreInput
+ goto saveStateAndReturn
+ }
+ } else {
+ decodeLiteralBlockSwitch(s)
+ }
+
+ preloadSymbol(safe, s.literal_htree, br, &bits, &value)
+ if s.trivial_literal_context == 0 {
+ goto CommandInner
+ }
+ }
+
+ if safe == 0 {
+ s.ringbuffer[pos] = byte(readPreloadedSymbol(s.literal_htree, br, &bits, &value))
+ } else {
+ var literal uint32
+ if !safeReadSymbol(s.literal_htree, br, &literal) {
+ result = decoderNeedsMoreInput
+ goto saveStateAndReturn
+ }
+
+ s.ringbuffer[pos] = byte(literal)
+ }
+
+ s.block_length[0]--
+ pos++
+ if pos == s.ringbuffer_size {
+ s.state = stateCommandInnerWrite
+ i--
+ goto saveStateAndReturn
+ }
+ i--
+ if i == 0 {
+ break
+ }
+ }
+ } else {
+ var p1 byte = s.ringbuffer[(pos-1)&s.ringbuffer_mask]
+ var p2 byte = s.ringbuffer[(pos-2)&s.ringbuffer_mask]
+ for {
+ var context byte
+ if !checkInputAmountMaybeSafe(safe, br, 28) { /* 162 bits + 7 bytes */
+ s.state = stateCommandInner
+ result = decoderNeedsMoreInput
+ goto saveStateAndReturn
+ }
+
+ if s.block_length[0] == 0 {
+ if safe != 0 {
+ if !safeDecodeLiteralBlockSwitch(s) {
+ result = decoderNeedsMoreInput
+ goto saveStateAndReturn
+ }
+ } else {
+ decodeLiteralBlockSwitch(s)
+ }
+
+ if s.trivial_literal_context != 0 {
+ goto CommandInner
+ }
+ }
+
+ context = getContext(p1, p2, s.context_lookup)
+ hc = []huffmanCode(s.literal_hgroup.htrees[s.context_map_slice[context]])
+ p2 = p1
+ if safe == 0 {
+ p1 = byte(readSymbol(hc, br))
+ } else {
+ var literal uint32
+ if !safeReadSymbol(hc, br, &literal) {
+ result = decoderNeedsMoreInput
+ goto saveStateAndReturn
+ }
+
+ p1 = byte(literal)
+ }
+
+ s.ringbuffer[pos] = p1
+ s.block_length[0]--
+ pos++
+ if pos == s.ringbuffer_size {
+ s.state = stateCommandInnerWrite
+ i--
+ goto saveStateAndReturn
+ }
+ i--
+ if i == 0 {
+ break
+ }
+ }
+ }
+
+ if s.meta_block_remaining_len <= 0 {
+ s.state = stateMetablockDone
+ goto saveStateAndReturn
+ }
+
+CommandPostDecodeLiterals:
+ if safe != 0 {
+ s.state = stateCommandPostDecodeLiterals
+ }
+
+ if s.distance_code >= 0 {
+ /* Implicit distance case. */
+ if s.distance_code != 0 {
+ s.distance_context = 0
+ } else {
+ s.distance_context = 1
+ }
+
+ s.dist_rb_idx--
+ s.distance_code = s.dist_rb[s.dist_rb_idx&3]
+ } else {
+ /* Read distance code in the command, unless it was implicitly zero. */
+ if s.block_length[2] == 0 {
+ if safe != 0 {
+ if !safeDecodeDistanceBlockSwitch(s) {
+ result = decoderNeedsMoreInput
+ goto saveStateAndReturn
+ }
+ } else {
+ decodeDistanceBlockSwitch(s)
+ }
+ }
+
+ if safe != 0 {
+ if !safeReadDistance(s, br) {
+ result = decoderNeedsMoreInput
+ goto saveStateAndReturn
+ }
+ } else {
+ readDistance(s, br)
+ }
+ }
+
+ if s.max_distance != s.max_backward_distance {
+ if pos < s.max_backward_distance {
+ s.max_distance = pos
+ } else {
+ s.max_distance = s.max_backward_distance
+ }
+ }
+
+ i = s.copy_length
+
+ /* Apply copy of LZ77 back-reference, or static dictionary reference if
+ the distance is larger than the max LZ77 distance */
+ if s.distance_code > s.max_distance {
+ /* The maximum allowed distance is BROTLI_MAX_ALLOWED_DISTANCE = 0x7FFFFFFC.
+ With this choice, no signed overflow can occur after decoding
+ a special distance code (e.g., after adding 3 to the last distance). */
+ if s.distance_code > maxAllowedDistance {
+ return decoderErrorFormatDistance
+ }
+
+ if i >= minDictionaryWordLength && i <= maxDictionaryWordLength {
+ var address int = s.distance_code - s.max_distance - 1
+ var words *dictionary = s.dictionary
+ var trans *transforms = s.transforms
+ var offset int = int(s.dictionary.offsets_by_length[i])
+ var shift uint32 = uint32(s.dictionary.size_bits_by_length[i])
+ var mask int = int(bitMask(shift))
+ var word_idx int = address & mask
+ var transform_idx int = address >> shift
+
+ /* Compensate double distance-ring-buffer roll. */
+ s.dist_rb_idx += s.distance_context
+
+ offset += word_idx * i
+ if words.data == nil {
+ return decoderErrorDictionaryNotSet
+ }
+
+ if transform_idx < int(trans.num_transforms) {
+ word := words.data[offset:]
+ var len int = i
+ if transform_idx == int(trans.cutOffTransforms[0]) {
+ copy(s.ringbuffer[pos:], word[:uint(len)])
+ } else {
+ len = transformDictionaryWord(s.ringbuffer[pos:], word, int(len), trans, transform_idx)
+ }
+
+ pos += int(len)
+ s.meta_block_remaining_len -= int(len)
+ if pos >= s.ringbuffer_size {
+ s.state = stateCommandPostWrite1
+ goto saveStateAndReturn
+ }
+ } else {
+ return decoderErrorFormatTransform
+ }
+ } else {
+ return decoderErrorFormatDictionary
+ }
+ } else {
+ var src_start int = (pos - s.distance_code) & s.ringbuffer_mask
+ copy_dst := s.ringbuffer[pos:]
+ copy_src := s.ringbuffer[src_start:]
+ var dst_end int = pos + i
+ var src_end int = src_start + i
+
+ /* Update the recent distances cache. */
+ s.dist_rb[s.dist_rb_idx&3] = s.distance_code
+
+ s.dist_rb_idx++
+ s.meta_block_remaining_len -= i
+
+ /* There are 32+ bytes of slack in the ring-buffer allocation.
+ Also, we have 16 short codes, that make these 16 bytes irrelevant
+ in the ring-buffer. Let's copy over them as a first guess. */
+ copy(copy_dst, copy_src[:16])
+
+ if src_end > pos && dst_end > src_start {
+ /* Regions intersect. */
+ goto CommandPostWrapCopy
+ }
+
+ if dst_end >= s.ringbuffer_size || src_end >= s.ringbuffer_size {
+ /* At least one region wraps. */
+ goto CommandPostWrapCopy
+ }
+
+ pos += i
+ if i > 16 {
+ if i > 32 {
+ copy(copy_dst[16:], copy_src[16:][:uint(i-16)])
+ } else {
+ /* This branch covers about 45% cases.
+ Fixed size short copy allows more compiler optimizations. */
+ copy(copy_dst[16:], copy_src[16:][:16])
+ }
+ }
+ }
+
+ if s.meta_block_remaining_len <= 0 {
+ /* Next metablock, if any. */
+ s.state = stateMetablockDone
+
+ goto saveStateAndReturn
+ } else {
+ goto CommandBegin
+ }
+CommandPostWrapCopy:
+ {
+ var wrap_guard int = s.ringbuffer_size - pos
+ for {
+ i--
+ if i < 0 {
+ break
+ }
+ s.ringbuffer[pos] = s.ringbuffer[(pos-s.distance_code)&s.ringbuffer_mask]
+ pos++
+ wrap_guard--
+ if wrap_guard == 0 {
+ s.state = stateCommandPostWrite2
+ goto saveStateAndReturn
+ }
+ }
+ }
+
+ if s.meta_block_remaining_len <= 0 {
+ /* Next metablock, if any. */
+ s.state = stateMetablockDone
+
+ goto saveStateAndReturn
+ } else {
+ goto CommandBegin
+ }
+
+saveStateAndReturn:
+ s.pos = pos
+ s.loop_counter = i
+ return result
+}
+
+func processCommands(s *Reader) int {
+ return processCommandsInternal(0, s)
+}
+
+func safeProcessCommands(s *Reader) int {
+ return processCommandsInternal(1, s)
+}
+
+/* Returns the maximum number of distance symbols which can only represent
+ distances not exceeding BROTLI_MAX_ALLOWED_DISTANCE. */
+
+var maxDistanceSymbol_bound = [maxNpostfix + 1]uint32{0, 4, 12, 28}
+var maxDistanceSymbol_diff = [maxNpostfix + 1]uint32{73, 126, 228, 424}
+
+func maxDistanceSymbol(ndirect uint32, npostfix uint32) uint32 {
+ var postfix uint32 = 1 << npostfix
+ if ndirect < maxDistanceSymbol_bound[npostfix] {
+ return ndirect + maxDistanceSymbol_diff[npostfix] + postfix
+ } else if ndirect > maxDistanceSymbol_bound[npostfix]+postfix {
+ return ndirect + maxDistanceSymbol_diff[npostfix]
+ } else {
+ return maxDistanceSymbol_bound[npostfix] + maxDistanceSymbol_diff[npostfix] + postfix
+ }
+}
+
+/* Invariant: input stream is never overconsumed:
+ - invalid input implies that the whole stream is invalid -> any amount of
+ input could be read and discarded
+ - when result is "needs more input", then at least one more byte is REQUIRED
+ to complete decoding; all input data MUST be consumed by decoder, so
+ client could swap the input buffer
+ - when result is "needs more output" decoder MUST ensure that it doesn't
+ hold more than 7 bits in bit reader; this saves client from swapping input
+ buffer ahead of time
+ - when result is "success" decoder MUST return all unused data back to input
+ buffer; this is possible because the invariant is held on enter */
+func decoderDecompressStream(s *Reader, available_in *uint, next_in *[]byte, available_out *uint, next_out *[]byte) int {
+ var result int = decoderSuccess
+ var br *bitReader = &s.br
+
+ /* Do not try to process further in a case of unrecoverable error. */
+ if int(s.error_code) < 0 {
+ return decoderResultError
+ }
+
+ if *available_out != 0 && (next_out == nil || *next_out == nil) {
+ return saveErrorCode(s, decoderErrorInvalidArguments)
+ }
+
+ if *available_out == 0 {
+ next_out = nil
+ }
+ if s.buffer_length == 0 { /* Just connect bit reader to input stream. */
+ br.input_len = *available_in
+ br.input = *next_in
+ br.byte_pos = 0
+ } else {
+ /* At least one byte of input is required. More than one byte of input may
+ be required to complete the transaction -> reading more data must be
+ done in a loop -> do it in a main loop. */
+ result = decoderNeedsMoreInput
+
+ br.input = s.buffer.u8[:]
+ br.byte_pos = 0
+ }
+
+ /* State machine */
+ for {
+ if result != decoderSuccess {
+ /* Error, needs more input/output. */
+ if result == decoderNeedsMoreInput {
+ if s.ringbuffer != nil { /* Pro-actively push output. */
+ var intermediate_result int = writeRingBuffer(s, available_out, next_out, nil, true)
+
+ /* WriteRingBuffer checks s->meta_block_remaining_len validity. */
+ if int(intermediate_result) < 0 {
+ result = intermediate_result
+ break
+ }
+ }
+
+ if s.buffer_length != 0 { /* Used with internal buffer. */
+ if br.byte_pos == br.input_len {
+ /* Successfully finished read transaction.
+ Accumulator contains less than 8 bits, because internal buffer
+ is expanded byte-by-byte until it is enough to complete read. */
+ s.buffer_length = 0
+
+ /* Switch to input stream and restart. */
+ result = decoderSuccess
+
+ br.input_len = *available_in
+ br.input = *next_in
+ br.byte_pos = 0
+ continue
+ } else if *available_in != 0 {
+ /* Not enough data in buffer, but can take one more byte from
+ input stream. */
+ result = decoderSuccess
+
+ s.buffer.u8[s.buffer_length] = (*next_in)[0]
+ s.buffer_length++
+ br.input_len = uint(s.buffer_length)
+ *next_in = (*next_in)[1:]
+ (*available_in)--
+
+ /* Retry with more data in buffer. */
+ continue
+ }
+
+ /* Can't finish reading and no more input. */
+ break
+ /* Input stream doesn't contain enough input. */
+ } else {
+ /* Copy tail to internal buffer and return. */
+ *next_in = br.input[br.byte_pos:]
+
+ *available_in = br.input_len - br.byte_pos
+ for *available_in != 0 {
+ s.buffer.u8[s.buffer_length] = (*next_in)[0]
+ s.buffer_length++
+ *next_in = (*next_in)[1:]
+ (*available_in)--
+ }
+
+ break
+ }
+ }
+
+ /* Unreachable. */
+
+ /* Fail or needs more output. */
+ if s.buffer_length != 0 {
+ /* Just consumed the buffered input and produced some output. Otherwise
+ it would result in "needs more input". Reset internal buffer. */
+ s.buffer_length = 0
+ } else {
+ /* Using input stream in last iteration. When decoder switches to input
+ stream it has less than 8 bits in accumulator, so it is safe to
+ return unused accumulator bits there. */
+ bitReaderUnload(br)
+
+ *available_in = br.input_len - br.byte_pos
+ *next_in = br.input[br.byte_pos:]
+ }
+
+ break
+ }
+
+ switch s.state {
+ /* Prepare to the first read. */
+ case stateUninited:
+ if !warmupBitReader(br) {
+ result = decoderNeedsMoreInput
+ break
+ }
+
+ /* Decode window size. */
+ result = decodeWindowBits(s, br) /* Reads 1..8 bits. */
+ if result != decoderSuccess {
+ break
+ }
+
+ if s.large_window {
+ s.state = stateLargeWindowBits
+ break
+ }
+
+ s.state = stateInitialize
+
+ case stateLargeWindowBits:
+ if !safeReadBits(br, 6, &s.window_bits) {
+ result = decoderNeedsMoreInput
+ break
+ }
+
+ if s.window_bits < largeMinWbits || s.window_bits > largeMaxWbits {
+ result = decoderErrorFormatWindowBits
+ break
+ }
+
+ s.state = stateInitialize
+ fallthrough
+
+ /* Maximum distance, see section 9.1. of the spec. */
+ /* Fall through. */
+ case stateInitialize:
+ s.max_backward_distance = (1 << s.window_bits) - windowGap
+
+ /* Allocate memory for both block_type_trees and block_len_trees. */
+ s.block_type_trees = make([]huffmanCode, (3 * (huffmanMaxSize258 + huffmanMaxSize26)))
+
+ if s.block_type_trees == nil {
+ result = decoderErrorAllocBlockTypeTrees
+ break
+ }
+
+ s.block_len_trees = s.block_type_trees[3*huffmanMaxSize258:]
+
+ s.state = stateMetablockBegin
+ fallthrough
+
+ /* Fall through. */
+ case stateMetablockBegin:
+ decoderStateMetablockBegin(s)
+
+ s.state = stateMetablockHeader
+ fallthrough
+
+ /* Fall through. */
+ case stateMetablockHeader:
+ result = decodeMetaBlockLength(s, br)
+ /* Reads 2 - 31 bits. */
+ if result != decoderSuccess {
+ break
+ }
+
+ if s.is_metadata != 0 || s.is_uncompressed != 0 {
+ if !bitReaderJumpToByteBoundary(br) {
+ result = decoderErrorFormatPadding1
+ break
+ }
+ }
+
+ if s.is_metadata != 0 {
+ s.state = stateMetadata
+ break
+ }
+
+ if s.meta_block_remaining_len == 0 {
+ s.state = stateMetablockDone
+ break
+ }
+
+ calculateRingBufferSize(s)
+ if s.is_uncompressed != 0 {
+ s.state = stateUncompressed
+ break
+ }
+
+ s.loop_counter = 0
+ s.state = stateHuffmanCode0
+
+ case stateUncompressed:
+ result = copyUncompressedBlockToOutput(available_out, next_out, nil, s)
+ if result == decoderSuccess {
+ s.state = stateMetablockDone
+ }
+
+ case stateMetadata:
+ for ; s.meta_block_remaining_len > 0; s.meta_block_remaining_len-- {
+ var bits uint32
+
+ /* Read one byte and ignore it. */
+ if !safeReadBits(br, 8, &bits) {
+ result = decoderNeedsMoreInput
+ break
+ }
+ }
+
+ if result == decoderSuccess {
+ s.state = stateMetablockDone
+ }
+
+ case stateHuffmanCode0:
+ if s.loop_counter >= 3 {
+ s.state = stateMetablockHeader2
+ break
+ }
+
+ /* Reads 1..11 bits. */
+ result = decodeVarLenUint8(s, br, &s.num_block_types[s.loop_counter])
+
+ if result != decoderSuccess {
+ break
+ }
+
+ s.num_block_types[s.loop_counter]++
+ if s.num_block_types[s.loop_counter] < 2 {
+ s.loop_counter++
+ break
+ }
+
+ s.state = stateHuffmanCode1
+ fallthrough
+
+ case stateHuffmanCode1:
+ {
+ var alphabet_size uint32 = s.num_block_types[s.loop_counter] + 2
+ var tree_offset int = s.loop_counter * huffmanMaxSize258
+ result = readHuffmanCode(alphabet_size, alphabet_size, s.block_type_trees[tree_offset:], nil, s)
+ if result != decoderSuccess {
+ break
+ }
+ s.state = stateHuffmanCode2
+ }
+ fallthrough
+
+ case stateHuffmanCode2:
+ {
+ var alphabet_size uint32 = numBlockLenSymbols
+ var tree_offset int = s.loop_counter * huffmanMaxSize26
+ result = readHuffmanCode(alphabet_size, alphabet_size, s.block_len_trees[tree_offset:], nil, s)
+ if result != decoderSuccess {
+ break
+ }
+ s.state = stateHuffmanCode3
+ }
+ fallthrough
+
+ case stateHuffmanCode3:
+ var tree_offset int = s.loop_counter * huffmanMaxSize26
+ if !safeReadBlockLength(s, &s.block_length[s.loop_counter], s.block_len_trees[tree_offset:], br) {
+ result = decoderNeedsMoreInput
+ break
+ }
+
+ s.loop_counter++
+ s.state = stateHuffmanCode0
+
+ case stateMetablockHeader2:
+ {
+ var bits uint32
+ if !safeReadBits(br, 6, &bits) {
+ result = decoderNeedsMoreInput
+ break
+ }
+
+ s.distance_postfix_bits = bits & bitMask(2)
+ bits >>= 2
+ s.num_direct_distance_codes = numDistanceShortCodes + (bits << s.distance_postfix_bits)
+ s.distance_postfix_mask = int(bitMask(s.distance_postfix_bits))
+ s.context_modes = make([]byte, uint(s.num_block_types[0]))
+ if s.context_modes == nil {
+ result = decoderErrorAllocContextModes
+ break
+ }
+
+ s.loop_counter = 0
+ s.state = stateContextModes
+ }
+ fallthrough
+
+ case stateContextModes:
+ result = readContextModes(s)
+
+ if result != decoderSuccess {
+ break
+ }
+
+ s.state = stateContextMap1
+ fallthrough
+
+ case stateContextMap1:
+ result = decodeContextMap(s.num_block_types[0]<= 3 {
+ prepareLiteralDecoding(s)
+ s.dist_context_map_slice = s.dist_context_map
+ s.htree_command = []huffmanCode(s.insert_copy_hgroup.htrees[0])
+ if !ensureRingBuffer(s) {
+ result = decoderErrorAllocRingBuffer2
+ break
+ }
+
+ s.state = stateCommandBegin
+ }
+
+ case stateCommandBegin, stateCommandInner, stateCommandPostDecodeLiterals, stateCommandPostWrapCopy:
+ result = processCommands(s)
+
+ if result == decoderNeedsMoreInput {
+ result = safeProcessCommands(s)
+ }
+
+ case stateCommandInnerWrite, stateCommandPostWrite1, stateCommandPostWrite2:
+ result = writeRingBuffer(s, available_out, next_out, nil, false)
+
+ if result != decoderSuccess {
+ break
+ }
+
+ wrapRingBuffer(s)
+ if s.ringbuffer_size == 1<= uint64(block_size) {
+ return 0
+ }
+ return block_size - uint(delta)
+}
+
+/* Wraps 64-bit input position to 32-bit ring-buffer position preserving
+ "not-a-first-lap" feature. */
+func wrapPosition(position uint64) uint32 {
+ var result uint32 = uint32(position)
+ var gb uint64 = position >> 30
+ if gb > 2 {
+ /* Wrap every 2GiB; The first 3GB are continuous. */
+ result = result&((1<<30)-1) | (uint32((gb-1)&1)+1)<<30
+ }
+
+ return result
+}
+
+func (s *Writer) getStorage(size int) []byte {
+ if len(s.storage) < size {
+ s.storage = make([]byte, size)
+ }
+
+ return s.storage
+}
+
+func hashTableSize(max_table_size uint, input_size uint) uint {
+ var htsize uint = 256
+ for htsize < max_table_size && htsize < input_size {
+ htsize <<= 1
+ }
+
+ return htsize
+}
+
+func getHashTable(s *Writer, quality int, input_size uint, table_size *uint) []int {
+ var max_table_size uint = maxHashTableSize(quality)
+ var htsize uint = hashTableSize(max_table_size, input_size)
+ /* Use smaller hash table when input.size() is smaller, since we
+ fill the table, incurring O(hash table size) overhead for
+ compression, and if the input is short, we won't need that
+ many hash table entries anyway. */
+
+ var table []int
+ assert(max_table_size >= 256)
+ if quality == fastOnePassCompressionQuality {
+ /* Only odd shifts are supported by fast-one-pass. */
+ if htsize&0xAAAAA == 0 {
+ htsize <<= 1
+ }
+ }
+
+ if htsize <= uint(len(s.small_table_)) {
+ table = s.small_table_[:]
+ } else {
+ if htsize > s.large_table_size_ {
+ s.large_table_size_ = htsize
+ s.large_table_ = nil
+ s.large_table_ = make([]int, htsize)
+ }
+
+ table = s.large_table_
+ }
+
+ *table_size = htsize
+ for i := 0; i < int(htsize); i++ {
+ table[i] = 0
+ }
+ return table
+}
+
+func encodeWindowBits(lgwin int, large_window bool, last_bytes *uint16, last_bytes_bits *byte) {
+ if large_window {
+ *last_bytes = uint16((lgwin&0x3F)<<8 | 0x11)
+ *last_bytes_bits = 14
+ } else {
+ if lgwin == 16 {
+ *last_bytes = 0
+ *last_bytes_bits = 1
+ } else if lgwin == 17 {
+ *last_bytes = 1
+ *last_bytes_bits = 7
+ } else if lgwin > 17 {
+ *last_bytes = uint16((lgwin-17)<<1 | 0x01)
+ *last_bytes_bits = 4
+ } else {
+ *last_bytes = uint16((lgwin-8)<<4 | 0x01)
+ *last_bytes_bits = 7
+ }
+ }
+}
+
+/* Decide about the context map based on the ability of the prediction
+ ability of the previous byte UTF8-prefix on the next byte. The
+ prediction ability is calculated as Shannon entropy. Here we need
+ Shannon entropy instead of 'BitsEntropy' since the prefix will be
+ encoded with the remaining 6 bits of the following byte, and
+ BitsEntropy will assume that symbol to be stored alone using Huffman
+ coding. */
+
+var kStaticContextMapContinuation = [64]uint32{
+ 1, 1, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+}
+var kStaticContextMapSimpleUTF8 = [64]uint32{
+ 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+}
+
+func chooseContextMap(quality int, bigram_histo []uint32, num_literal_contexts *uint, literal_context_map *[]uint32) {
+ var monogram_histo = [3]uint32{0}
+ var two_prefix_histo = [6]uint32{0}
+ var total uint
+ var i uint
+ var dummy uint
+ var entropy [4]float64
+ for i = 0; i < 9; i++ {
+ monogram_histo[i%3] += bigram_histo[i]
+ two_prefix_histo[i%6] += bigram_histo[i]
+ }
+
+ entropy[1] = shannonEntropy(monogram_histo[:], 3, &dummy)
+ entropy[2] = (shannonEntropy(two_prefix_histo[:], 3, &dummy) + shannonEntropy(two_prefix_histo[3:], 3, &dummy))
+ entropy[3] = 0
+ for i = 0; i < 3; i++ {
+ entropy[3] += shannonEntropy(bigram_histo[3*i:], 3, &dummy)
+ }
+
+ total = uint(monogram_histo[0] + monogram_histo[1] + monogram_histo[2])
+ assert(total != 0)
+ entropy[0] = 1.0 / float64(total)
+ entropy[1] *= entropy[0]
+ entropy[2] *= entropy[0]
+ entropy[3] *= entropy[0]
+
+ if quality < minQualityForHqContextModeling {
+ /* 3 context models is a bit slower, don't use it at lower qualities. */
+ entropy[3] = entropy[1] * 10
+ }
+
+ /* If expected savings by symbol are less than 0.2 bits, skip the
+ context modeling -- in exchange for faster decoding speed. */
+ if entropy[1]-entropy[2] < 0.2 && entropy[1]-entropy[3] < 0.2 {
+ *num_literal_contexts = 1
+ } else if entropy[2]-entropy[3] < 0.02 {
+ *num_literal_contexts = 2
+ *literal_context_map = kStaticContextMapSimpleUTF8[:]
+ } else {
+ *num_literal_contexts = 3
+ *literal_context_map = kStaticContextMapContinuation[:]
+ }
+}
+
+/* Decide if we want to use a more complex static context map containing 13
+ context values, based on the entropy reduction of histograms over the
+ first 5 bits of literals. */
+
+var kStaticContextMapComplexUTF8 = [64]uint32{
+ 11, 11, 12, 12, /* 0 special */
+ 0, 0, 0, 0, /* 4 lf */
+ 1, 1, 9, 9, /* 8 space */
+ 2, 2, 2, 2, /* !, first after space/lf and after something else. */
+ 1, 1, 1, 1, /* " */
+ 8, 3, 3, 3, /* % */
+ 1, 1, 1, 1, /* ({[ */
+ 2, 2, 2, 2, /* }]) */
+ 8, 4, 4, 4, /* :; */
+ 8, 7, 4, 4, /* . */
+ 8, 0, 0, 0, /* > */
+ 3, 3, 3, 3, /* [0..9] */
+ 5, 5, 10, 5, /* [A-Z] */
+ 5, 5, 10, 5,
+ 6, 6, 6, 6, /* [a-z] */
+ 6, 6, 6, 6,
+}
+
+func shouldUseComplexStaticContextMap(input []byte, start_pos uint, length uint, mask uint, quality int, size_hint uint, num_literal_contexts *uint, literal_context_map *[]uint32) bool {
+ /* Try the more complex static context map only for long data. */
+ if size_hint < 1<<20 {
+ return false
+ } else {
+ var end_pos uint = start_pos + length
+ var combined_histo = [32]uint32{0}
+ var context_histo = [13][32]uint32{[32]uint32{0}}
+ var total uint32 = 0
+ var entropy [3]float64
+ var dummy uint
+ var i uint
+ var utf8_lut contextLUT = getContextLUT(contextUTF8)
+ /* To make entropy calculations faster and to fit on the stack, we collect
+ histograms over the 5 most significant bits of literals. One histogram
+ without context and 13 additional histograms for each context value. */
+ for ; start_pos+64 <= end_pos; start_pos += 4096 {
+ var stride_end_pos uint = start_pos + 64
+ var prev2 byte = input[start_pos&mask]
+ var prev1 byte = input[(start_pos+1)&mask]
+ var pos uint
+
+ /* To make the analysis of the data faster we only examine 64 byte long
+ strides at every 4kB intervals. */
+ for pos = start_pos + 2; pos < stride_end_pos; pos++ {
+ var literal byte = input[pos&mask]
+ var context byte = byte(kStaticContextMapComplexUTF8[getContext(prev1, prev2, utf8_lut)])
+ total++
+ combined_histo[literal>>3]++
+ context_histo[context][literal>>3]++
+ prev2 = prev1
+ prev1 = literal
+ }
+ }
+
+ entropy[1] = shannonEntropy(combined_histo[:], 32, &dummy)
+ entropy[2] = 0
+ for i = 0; i < 13; i++ {
+ entropy[2] += shannonEntropy(context_histo[i][0:], 32, &dummy)
+ }
+
+ entropy[0] = 1.0 / float64(total)
+ entropy[1] *= entropy[0]
+ entropy[2] *= entropy[0]
+
+ /* The triggering heuristics below were tuned by compressing the individual
+ files of the silesia corpus. If we skip this kind of context modeling
+ for not very well compressible input (i.e. entropy using context modeling
+ is 60% of maximal entropy) or if expected savings by symbol are less
+ than 0.2 bits, then in every case when it triggers, the final compression
+ ratio is improved. Note however that this heuristics might be too strict
+ for some cases and could be tuned further. */
+ if entropy[2] > 3.0 || entropy[1]-entropy[2] < 0.2 {
+ return false
+ } else {
+ *num_literal_contexts = 13
+ *literal_context_map = kStaticContextMapComplexUTF8[:]
+ return true
+ }
+ }
+}
+
+func decideOverLiteralContextModeling(input []byte, start_pos uint, length uint, mask uint, quality int, size_hint uint, num_literal_contexts *uint, literal_context_map *[]uint32) {
+ if quality < minQualityForContextModeling || length < 64 {
+ return
+ } else if shouldUseComplexStaticContextMap(input, start_pos, length, mask, quality, size_hint, num_literal_contexts, literal_context_map) {
+ } else /* Context map was already set, nothing else to do. */
+ {
+ var end_pos uint = start_pos + length
+ /* Gather bi-gram data of the UTF8 byte prefixes. To make the analysis of
+ UTF8 data faster we only examine 64 byte long strides at every 4kB
+ intervals. */
+
+ var bigram_prefix_histo = [9]uint32{0}
+ for ; start_pos+64 <= end_pos; start_pos += 4096 {
+ var lut = [4]int{0, 0, 1, 2}
+ var stride_end_pos uint = start_pos + 64
+ var prev int = lut[input[start_pos&mask]>>6] * 3
+ var pos uint
+ for pos = start_pos + 1; pos < stride_end_pos; pos++ {
+ var literal byte = input[pos&mask]
+ bigram_prefix_histo[prev+lut[literal>>6]]++
+ prev = lut[literal>>6] * 3
+ }
+ }
+
+ chooseContextMap(quality, bigram_prefix_histo[0:], num_literal_contexts, literal_context_map)
+ }
+}
+
+func shouldCompress_encode(data []byte, mask uint, last_flush_pos uint64, bytes uint, num_literals uint, num_commands uint) bool {
+ /* TODO: find more precise minimal block overhead. */
+ if bytes <= 2 {
+ return false
+ }
+ if num_commands < (bytes>>8)+2 {
+ if float64(num_literals) > 0.99*float64(bytes) {
+ var literal_histo = [256]uint32{0}
+ const kSampleRate uint32 = 13
+ const kMinEntropy float64 = 7.92
+ var bit_cost_threshold float64 = float64(bytes) * kMinEntropy / float64(kSampleRate)
+ var t uint = uint((uint32(bytes) + kSampleRate - 1) / kSampleRate)
+ var pos uint32 = uint32(last_flush_pos)
+ var i uint
+ for i = 0; i < t; i++ {
+ literal_histo[data[pos&uint32(mask)]]++
+ pos += kSampleRate
+ }
+
+ if bitsEntropy(literal_histo[:], 256) > bit_cost_threshold {
+ return false
+ }
+ }
+ }
+
+ return true
+}
+
+/* Chooses the literal context mode for a metablock */
+func chooseContextMode(params *encoderParams, data []byte, pos uint, mask uint, length uint) int {
+ /* We only do the computation for the option of something else than
+ CONTEXT_UTF8 for the highest qualities */
+ if params.quality >= minQualityForHqBlockSplitting && !isMostlyUTF8(data, pos, mask, length, kMinUTF8Ratio) {
+ return contextSigned
+ }
+
+ return contextUTF8
+}
+
+func writeMetaBlockInternal(data []byte, mask uint, last_flush_pos uint64, bytes uint, is_last bool, literal_context_mode int, params *encoderParams, prev_byte byte, prev_byte2 byte, num_literals uint, commands []command, saved_dist_cache []int, dist_cache []int, storage_ix *uint, storage []byte) {
+ var wrapped_last_flush_pos uint32 = wrapPosition(last_flush_pos)
+ var last_bytes uint16
+ var last_bytes_bits byte
+ var literal_context_lut contextLUT = getContextLUT(literal_context_mode)
+ var block_params encoderParams = *params
+
+ if bytes == 0 {
+ /* Write the ISLAST and ISEMPTY bits. */
+ writeBits(2, 3, storage_ix, storage)
+
+ *storage_ix = (*storage_ix + 7) &^ 7
+ return
+ }
+
+ if !shouldCompress_encode(data, mask, last_flush_pos, bytes, num_literals, uint(len(commands))) {
+ /* Restore the distance cache, as its last update by
+ CreateBackwardReferences is now unused. */
+ copy(dist_cache, saved_dist_cache[:4])
+
+ storeUncompressedMetaBlock(is_last, data, uint(wrapped_last_flush_pos), mask, bytes, storage_ix, storage)
+ return
+ }
+
+ assert(*storage_ix <= 14)
+ last_bytes = uint16(storage[1])<<8 | uint16(storage[0])
+ last_bytes_bits = byte(*storage_ix)
+ if params.quality <= maxQualityForStaticEntropyCodes {
+ storeMetaBlockFast(data, uint(wrapped_last_flush_pos), bytes, mask, is_last, params, commands, storage_ix, storage)
+ } else if params.quality < minQualityForBlockSplit {
+ storeMetaBlockTrivial(data, uint(wrapped_last_flush_pos), bytes, mask, is_last, params, commands, storage_ix, storage)
+ } else {
+ mb := getMetaBlockSplit()
+ if params.quality < minQualityForHqBlockSplitting {
+ var num_literal_contexts uint = 1
+ var literal_context_map []uint32 = nil
+ if !params.disable_literal_context_modeling {
+ decideOverLiteralContextModeling(data, uint(wrapped_last_flush_pos), bytes, mask, params.quality, params.size_hint, &num_literal_contexts, &literal_context_map)
+ }
+
+ buildMetaBlockGreedy(data, uint(wrapped_last_flush_pos), mask, prev_byte, prev_byte2, literal_context_lut, num_literal_contexts, literal_context_map, commands, mb)
+ } else {
+ buildMetaBlock(data, uint(wrapped_last_flush_pos), mask, &block_params, prev_byte, prev_byte2, commands, literal_context_mode, mb)
+ }
+
+ if params.quality >= minQualityForOptimizeHistograms {
+ /* The number of distance symbols effectively used for distance
+ histograms. It might be less than distance alphabet size
+ for "Large Window Brotli" (32-bit). */
+ var num_effective_dist_codes uint32 = block_params.dist.alphabet_size
+ if num_effective_dist_codes > numHistogramDistanceSymbols {
+ num_effective_dist_codes = numHistogramDistanceSymbols
+ }
+
+ optimizeHistograms(num_effective_dist_codes, mb)
+ }
+
+ storeMetaBlock(data, uint(wrapped_last_flush_pos), bytes, mask, prev_byte, prev_byte2, is_last, &block_params, literal_context_mode, commands, mb, storage_ix, storage)
+ freeMetaBlockSplit(mb)
+ }
+
+ if bytes+4 < *storage_ix>>3 {
+ /* Restore the distance cache and last byte. */
+ copy(dist_cache, saved_dist_cache[:4])
+
+ storage[0] = byte(last_bytes)
+ storage[1] = byte(last_bytes >> 8)
+ *storage_ix = uint(last_bytes_bits)
+ storeUncompressedMetaBlock(is_last, data, uint(wrapped_last_flush_pos), mask, bytes, storage_ix, storage)
+ }
+}
+
+func chooseDistanceParams(params *encoderParams) {
+ var distance_postfix_bits uint32 = 0
+ var num_direct_distance_codes uint32 = 0
+
+ if params.quality >= minQualityForNonzeroDistanceParams {
+ var ndirect_msb uint32
+ if params.mode == modeFont {
+ distance_postfix_bits = 1
+ num_direct_distance_codes = 12
+ } else {
+ distance_postfix_bits = params.dist.distance_postfix_bits
+ num_direct_distance_codes = params.dist.num_direct_distance_codes
+ }
+
+ ndirect_msb = (num_direct_distance_codes >> distance_postfix_bits) & 0x0F
+ if distance_postfix_bits > maxNpostfix || num_direct_distance_codes > maxNdirect || ndirect_msb<>25)), (last_command.dist_prefix_&0x3FF == 0), &last_command.cmd_prefix_)
+ }
+}
+
+/*
+ Processes the accumulated input data and writes
+ the new output meta-block to s.dest, if one has been
+ created (otherwise the processed input data is buffered internally).
+ If |is_last| or |force_flush| is true, an output meta-block is
+ always created. However, until |is_last| is true encoder may retain up
+ to 7 bits of the last byte of output. To force encoder to dump the remaining
+ bits use WriteMetadata() to append an empty meta-data block.
+ Returns false if the size of the input data is larger than
+ input_block_size().
+*/
+func encodeData(s *Writer, is_last bool, force_flush bool) bool {
+ var delta uint64 = unprocessedInputSize(s)
+ var bytes uint32 = uint32(delta)
+ var wrapped_last_processed_pos uint32 = wrapPosition(s.last_processed_pos_)
+ var data []byte
+ var mask uint32
+ var literal_context_mode int
+
+ data = s.ringbuffer_.buffer_
+ mask = s.ringbuffer_.mask_
+
+ /* Adding more blocks after "last" block is forbidden. */
+ if s.is_last_block_emitted_ {
+ return false
+ }
+ if is_last {
+ s.is_last_block_emitted_ = true
+ }
+
+ if delta > uint64(inputBlockSize(s)) {
+ return false
+ }
+
+ if s.params.quality == fastTwoPassCompressionQuality {
+ if s.command_buf_ == nil || cap(s.command_buf_) < int(kCompressFragmentTwoPassBlockSize) {
+ s.command_buf_ = make([]uint32, kCompressFragmentTwoPassBlockSize)
+ s.literal_buf_ = make([]byte, kCompressFragmentTwoPassBlockSize)
+ } else {
+ s.command_buf_ = s.command_buf_[:kCompressFragmentTwoPassBlockSize]
+ s.literal_buf_ = s.literal_buf_[:kCompressFragmentTwoPassBlockSize]
+ }
+ }
+
+ if s.params.quality == fastOnePassCompressionQuality || s.params.quality == fastTwoPassCompressionQuality {
+ var storage []byte
+ var storage_ix uint = uint(s.last_bytes_bits_)
+ var table_size uint
+ var table []int
+
+ if delta == 0 && !is_last {
+ /* We have no new input data and we don't have to finish the stream, so
+ nothing to do. */
+ return true
+ }
+
+ storage = s.getStorage(int(2*bytes + 503))
+ storage[0] = byte(s.last_bytes_)
+ storage[1] = byte(s.last_bytes_ >> 8)
+ table = getHashTable(s, s.params.quality, uint(bytes), &table_size)
+ if s.params.quality == fastOnePassCompressionQuality {
+ compressFragmentFast(data[wrapped_last_processed_pos&mask:], uint(bytes), is_last, table, table_size, s.cmd_depths_[:], s.cmd_bits_[:], &s.cmd_code_numbits_, s.cmd_code_[:], &storage_ix, storage)
+ } else {
+ compressFragmentTwoPass(data[wrapped_last_processed_pos&mask:], uint(bytes), is_last, s.command_buf_, s.literal_buf_, table, table_size, &storage_ix, storage)
+ }
+
+ s.last_bytes_ = uint16(storage[storage_ix>>3])
+ s.last_bytes_bits_ = byte(storage_ix & 7)
+ updateLastProcessedPos(s)
+ s.writeOutput(storage[:storage_ix>>3])
+ return true
+ }
+ {
+ /* Theoretical max number of commands is 1 per 2 bytes. */
+ newsize := len(s.commands) + int(bytes)/2 + 1
+ if newsize > cap(s.commands) {
+ /* Reserve a bit more memory to allow merging with a next block
+ without reallocation: that would impact speed. */
+ newsize += int(bytes/4) + 16
+
+ new_commands := make([]command, len(s.commands), newsize)
+ if s.commands != nil {
+ copy(new_commands, s.commands)
+ }
+
+ s.commands = new_commands
+ }
+ }
+
+ initOrStitchToPreviousBlock(&s.hasher_, data, uint(mask), &s.params, uint(wrapped_last_processed_pos), uint(bytes), is_last)
+
+ literal_context_mode = chooseContextMode(&s.params, data, uint(wrapPosition(s.last_flush_pos_)), uint(mask), uint(s.input_pos_-s.last_flush_pos_))
+
+ if len(s.commands) != 0 && s.last_insert_len_ == 0 {
+ extendLastCommand(s, &bytes, &wrapped_last_processed_pos)
+ }
+
+ if s.params.quality == zopflificationQuality {
+ assert(s.params.hasher.type_ == 10)
+ createZopfliBackwardReferences(uint(bytes), uint(wrapped_last_processed_pos), data, uint(mask), &s.params, s.hasher_.(*h10), s.dist_cache_[:], &s.last_insert_len_, &s.commands, &s.num_literals_)
+ } else if s.params.quality == hqZopflificationQuality {
+ assert(s.params.hasher.type_ == 10)
+ createHqZopfliBackwardReferences(uint(bytes), uint(wrapped_last_processed_pos), data, uint(mask), &s.params, s.hasher_, s.dist_cache_[:], &s.last_insert_len_, &s.commands, &s.num_literals_)
+ } else {
+ createBackwardReferences(uint(bytes), uint(wrapped_last_processed_pos), data, uint(mask), &s.params, s.hasher_, s.dist_cache_[:], &s.last_insert_len_, &s.commands, &s.num_literals_)
+ }
+ {
+ var max_length uint = maxMetablockSize(&s.params)
+ var max_literals uint = max_length / 8
+ max_commands := int(max_length / 8)
+ var processed_bytes uint = uint(s.input_pos_ - s.last_flush_pos_)
+ var next_input_fits_metablock bool = (processed_bytes+inputBlockSize(s) <= max_length)
+ var should_flush bool = (s.params.quality < minQualityForBlockSplit && s.num_literals_+uint(len(s.commands)) >= maxNumDelayedSymbols)
+ /* If maximal possible additional block doesn't fit metablock, flush now. */
+ /* TODO: Postpone decision until next block arrives? */
+
+ /* If block splitting is not used, then flush as soon as there is some
+ amount of commands / literals produced. */
+ if !is_last && !force_flush && !should_flush && next_input_fits_metablock && s.num_literals_ < max_literals && len(s.commands) < max_commands {
+ /* Merge with next input block. Everything will happen later. */
+ if updateLastProcessedPos(s) {
+ hasherReset(s.hasher_)
+ }
+
+ return true
+ }
+ }
+
+ /* Create the last insert-only command. */
+ if s.last_insert_len_ > 0 {
+ s.commands = append(s.commands, makeInsertCommand(s.last_insert_len_))
+ s.num_literals_ += s.last_insert_len_
+ s.last_insert_len_ = 0
+ }
+
+ if !is_last && s.input_pos_ == s.last_flush_pos_ {
+ /* We have no new input data and we don't have to finish the stream, so
+ nothing to do. */
+ return true
+ }
+
+ assert(s.input_pos_ >= s.last_flush_pos_)
+ assert(s.input_pos_ > s.last_flush_pos_ || is_last)
+ assert(s.input_pos_-s.last_flush_pos_ <= 1<<24)
+ {
+ var metablock_size uint32 = uint32(s.input_pos_ - s.last_flush_pos_)
+ var storage []byte = s.getStorage(int(2*metablock_size + 503))
+ var storage_ix uint = uint(s.last_bytes_bits_)
+ storage[0] = byte(s.last_bytes_)
+ storage[1] = byte(s.last_bytes_ >> 8)
+ writeMetaBlockInternal(data, uint(mask), s.last_flush_pos_, uint(metablock_size), is_last, literal_context_mode, &s.params, s.prev_byte_, s.prev_byte2_, s.num_literals_, s.commands, s.saved_dist_cache_[:], s.dist_cache_[:], &storage_ix, storage)
+ s.last_bytes_ = uint16(storage[storage_ix>>3])
+ s.last_bytes_bits_ = byte(storage_ix & 7)
+ s.last_flush_pos_ = s.input_pos_
+ if updateLastProcessedPos(s) {
+ hasherReset(s.hasher_)
+ }
+
+ if s.last_flush_pos_ > 0 {
+ s.prev_byte_ = data[(uint32(s.last_flush_pos_)-1)&mask]
+ }
+
+ if s.last_flush_pos_ > 1 {
+ s.prev_byte2_ = data[uint32(s.last_flush_pos_-2)&mask]
+ }
+
+ s.commands = s.commands[:0]
+ s.num_literals_ = 0
+
+ /* Save the state of the distance cache in case we need to restore it for
+ emitting an uncompressed block. */
+ copy(s.saved_dist_cache_[:], s.dist_cache_[:])
+
+ s.writeOutput(storage[:storage_ix>>3])
+ return true
+ }
+}
+
+/* Dumps remaining output bits and metadata header to |header|.
+ Returns number of produced bytes.
+ REQUIRED: |header| should be 8-byte aligned and at least 16 bytes long.
+ REQUIRED: |block_size| <= (1 << 24). */
+func writeMetadataHeader(s *Writer, block_size uint, header []byte) uint {
+ storage_ix := uint(s.last_bytes_bits_)
+ header[0] = byte(s.last_bytes_)
+ header[1] = byte(s.last_bytes_ >> 8)
+ s.last_bytes_ = 0
+ s.last_bytes_bits_ = 0
+
+ writeBits(1, 0, &storage_ix, header)
+ writeBits(2, 3, &storage_ix, header)
+ writeBits(1, 0, &storage_ix, header)
+ if block_size == 0 {
+ writeBits(2, 0, &storage_ix, header)
+ } else {
+ var nbits uint32
+ if block_size == 1 {
+ nbits = 0
+ } else {
+ nbits = log2FloorNonZero(uint(uint32(block_size)-1)) + 1
+ }
+ var nbytes uint32 = (nbits + 7) / 8
+ writeBits(2, uint64(nbytes), &storage_ix, header)
+ writeBits(uint(8*nbytes), uint64(block_size)-1, &storage_ix, header)
+ }
+
+ return (storage_ix + 7) >> 3
+}
+
+func injectBytePaddingBlock(s *Writer) {
+ var seal uint32 = uint32(s.last_bytes_)
+ var seal_bits uint = uint(s.last_bytes_bits_)
+ s.last_bytes_ = 0
+ s.last_bytes_bits_ = 0
+
+ /* is_last = 0, data_nibbles = 11, reserved = 0, meta_nibbles = 00 */
+ seal |= 0x6 << seal_bits
+
+ seal_bits += 6
+
+ destination := s.tiny_buf_.u8[:]
+
+ destination[0] = byte(seal)
+ if seal_bits > 8 {
+ destination[1] = byte(seal >> 8)
+ }
+ if seal_bits > 16 {
+ destination[2] = byte(seal >> 16)
+ }
+ s.writeOutput(destination[:(seal_bits+7)>>3])
+}
+
+func checkFlushComplete(s *Writer) {
+ if s.stream_state_ == streamFlushRequested && s.err == nil {
+ s.stream_state_ = streamProcessing
+ }
+}
+
+func encoderCompressStreamFast(s *Writer, op int, available_in *uint, next_in *[]byte) bool {
+ var block_size_limit uint = uint(1) << s.params.lgwin
+ var buf_size uint = brotli_min_size_t(kCompressFragmentTwoPassBlockSize, brotli_min_size_t(*available_in, block_size_limit))
+ var command_buf []uint32 = nil
+ var literal_buf []byte = nil
+ if s.params.quality != fastOnePassCompressionQuality && s.params.quality != fastTwoPassCompressionQuality {
+ return false
+ }
+
+ if s.params.quality == fastTwoPassCompressionQuality {
+ if s.command_buf_ == nil || cap(s.command_buf_) < int(buf_size) {
+ s.command_buf_ = make([]uint32, buf_size)
+ s.literal_buf_ = make([]byte, buf_size)
+ } else {
+ s.command_buf_ = s.command_buf_[:buf_size]
+ s.literal_buf_ = s.literal_buf_[:buf_size]
+ }
+
+ command_buf = s.command_buf_
+ literal_buf = s.literal_buf_
+ }
+
+ for {
+ if s.stream_state_ == streamFlushRequested && s.last_bytes_bits_ != 0 {
+ injectBytePaddingBlock(s)
+ continue
+ }
+
+ /* Compress block only when stream is not
+ finished, there is no pending flush request, and there is either
+ additional input or pending operation. */
+ if s.stream_state_ == streamProcessing && (*available_in != 0 || op != int(operationProcess)) {
+ var block_size uint = brotli_min_size_t(block_size_limit, *available_in)
+ var is_last bool = (*available_in == block_size) && (op == int(operationFinish))
+ var force_flush bool = (*available_in == block_size) && (op == int(operationFlush))
+ var max_out_size uint = 2*block_size + 503
+ var storage []byte = nil
+ var storage_ix uint = uint(s.last_bytes_bits_)
+ var table_size uint
+ var table []int
+
+ if force_flush && block_size == 0 {
+ s.stream_state_ = streamFlushRequested
+ continue
+ }
+
+ storage = s.getStorage(int(max_out_size))
+
+ storage[0] = byte(s.last_bytes_)
+ storage[1] = byte(s.last_bytes_ >> 8)
+ table = getHashTable(s, s.params.quality, block_size, &table_size)
+
+ if s.params.quality == fastOnePassCompressionQuality {
+ compressFragmentFast(*next_in, block_size, is_last, table, table_size, s.cmd_depths_[:], s.cmd_bits_[:], &s.cmd_code_numbits_, s.cmd_code_[:], &storage_ix, storage)
+ } else {
+ compressFragmentTwoPass(*next_in, block_size, is_last, command_buf, literal_buf, table, table_size, &storage_ix, storage)
+ }
+
+ *next_in = (*next_in)[block_size:]
+ *available_in -= block_size
+ var out_bytes uint = storage_ix >> 3
+ s.writeOutput(storage[:out_bytes])
+
+ s.last_bytes_ = uint16(storage[storage_ix>>3])
+ s.last_bytes_bits_ = byte(storage_ix & 7)
+
+ if force_flush {
+ s.stream_state_ = streamFlushRequested
+ }
+ if is_last {
+ s.stream_state_ = streamFinished
+ }
+ continue
+ }
+
+ break
+ }
+
+ checkFlushComplete(s)
+ return true
+}
+
+func processMetadata(s *Writer, available_in *uint, next_in *[]byte) bool {
+ if *available_in > 1<<24 {
+ return false
+ }
+
+ /* Switch to metadata block workflow, if required. */
+ if s.stream_state_ == streamProcessing {
+ s.remaining_metadata_bytes_ = uint32(*available_in)
+ s.stream_state_ = streamMetadataHead
+ }
+
+ if s.stream_state_ != streamMetadataHead && s.stream_state_ != streamMetadataBody {
+ return false
+ }
+
+ for {
+ if s.stream_state_ == streamFlushRequested && s.last_bytes_bits_ != 0 {
+ injectBytePaddingBlock(s)
+ continue
+ }
+
+ if s.input_pos_ != s.last_flush_pos_ {
+ var result bool = encodeData(s, false, true)
+ if !result {
+ return false
+ }
+ continue
+ }
+
+ if s.stream_state_ == streamMetadataHead {
+ n := writeMetadataHeader(s, uint(s.remaining_metadata_bytes_), s.tiny_buf_.u8[:])
+ s.writeOutput(s.tiny_buf_.u8[:n])
+ s.stream_state_ = streamMetadataBody
+ continue
+ } else {
+ /* Exit workflow only when there is no more input and no more output.
+ Otherwise client may continue producing empty metadata blocks. */
+ if s.remaining_metadata_bytes_ == 0 {
+ s.remaining_metadata_bytes_ = math.MaxUint32
+ s.stream_state_ = streamProcessing
+ break
+ }
+
+ /* This guarantees progress in "TakeOutput" workflow. */
+ var c uint32 = brotli_min_uint32_t(s.remaining_metadata_bytes_, 16)
+ copy(s.tiny_buf_.u8[:], (*next_in)[:c])
+ *next_in = (*next_in)[c:]
+ *available_in -= uint(c)
+ s.remaining_metadata_bytes_ -= c
+ s.writeOutput(s.tiny_buf_.u8[:c])
+
+ continue
+ }
+ }
+
+ return true
+}
+
+func updateSizeHint(s *Writer, available_in uint) {
+ if s.params.size_hint == 0 {
+ var delta uint64 = unprocessedInputSize(s)
+ var tail uint64 = uint64(available_in)
+ var limit uint32 = 1 << 30
+ var total uint32
+ if (delta >= uint64(limit)) || (tail >= uint64(limit)) || ((delta + tail) >= uint64(limit)) {
+ total = limit
+ } else {
+ total = uint32(delta + tail)
+ }
+
+ s.params.size_hint = uint(total)
+ }
+}
+
+func encoderCompressStream(s *Writer, op int, available_in *uint, next_in *[]byte) bool {
+ if !ensureInitialized(s) {
+ return false
+ }
+
+ /* Unfinished metadata block; check requirements. */
+ if s.remaining_metadata_bytes_ != math.MaxUint32 {
+ if uint32(*available_in) != s.remaining_metadata_bytes_ {
+ return false
+ }
+ if op != int(operationEmitMetadata) {
+ return false
+ }
+ }
+
+ if op == int(operationEmitMetadata) {
+ updateSizeHint(s, 0) /* First data metablock might be emitted here. */
+ return processMetadata(s, available_in, next_in)
+ }
+
+ if s.stream_state_ == streamMetadataHead || s.stream_state_ == streamMetadataBody {
+ return false
+ }
+
+ if s.stream_state_ != streamProcessing && *available_in != 0 {
+ return false
+ }
+
+ if s.params.quality == fastOnePassCompressionQuality || s.params.quality == fastTwoPassCompressionQuality {
+ return encoderCompressStreamFast(s, op, available_in, next_in)
+ }
+
+ for {
+ var remaining_block_size uint = remainingInputBlockSize(s)
+
+ if remaining_block_size != 0 && *available_in != 0 {
+ var copy_input_size uint = brotli_min_size_t(remaining_block_size, *available_in)
+ copyInputToRingBuffer(s, copy_input_size, *next_in)
+ *next_in = (*next_in)[copy_input_size:]
+ *available_in -= copy_input_size
+ continue
+ }
+
+ if s.stream_state_ == streamFlushRequested && s.last_bytes_bits_ != 0 {
+ injectBytePaddingBlock(s)
+ continue
+ }
+
+ /* Compress data only when stream is not
+ finished and there is no pending flush request. */
+ if s.stream_state_ == streamProcessing {
+ if remaining_block_size == 0 || op != int(operationProcess) {
+ var is_last bool = ((*available_in == 0) && op == int(operationFinish))
+ var force_flush bool = ((*available_in == 0) && op == int(operationFlush))
+ var result bool
+ updateSizeHint(s, *available_in)
+ result = encodeData(s, is_last, force_flush)
+ if !result {
+ return false
+ }
+ if force_flush {
+ s.stream_state_ = streamFlushRequested
+ }
+ if is_last {
+ s.stream_state_ = streamFinished
+ }
+ continue
+ }
+ }
+
+ break
+ }
+
+ checkFlushComplete(s)
+ return true
+}
+
+func (w *Writer) writeOutput(data []byte) {
+ if w.err != nil {
+ return
+ }
+
+ _, w.err = w.dst.Write(data)
+ if w.err == nil {
+ checkFlushComplete(w)
+ }
+}
diff --git a/vendor/github.com/andybalholm/brotli/encoder_dict.go b/vendor/github.com/andybalholm/brotli/encoder_dict.go
new file mode 100644
index 0000000..55c051c
--- /dev/null
+++ b/vendor/github.com/andybalholm/brotli/encoder_dict.go
@@ -0,0 +1,22 @@
+package brotli
+
+/* Dictionary data (words and transforms) for 1 possible context */
+type encoderDictionary struct {
+ words *dictionary
+ cutoffTransformsCount uint32
+ cutoffTransforms uint64
+ hash_table []uint16
+ buckets []uint16
+ dict_words []dictWord
+}
+
+func initEncoderDictionary(dict *encoderDictionary) {
+ dict.words = getDictionary()
+
+ dict.hash_table = kStaticDictionaryHash[:]
+ dict.buckets = kStaticDictionaryBuckets[:]
+ dict.dict_words = kStaticDictionaryWords[:]
+
+ dict.cutoffTransformsCount = kCutoffTransformsCount
+ dict.cutoffTransforms = kCutoffTransforms
+}
diff --git a/vendor/github.com/andybalholm/brotli/entropy_encode.go b/vendor/github.com/andybalholm/brotli/entropy_encode.go
new file mode 100644
index 0000000..3f469a3
--- /dev/null
+++ b/vendor/github.com/andybalholm/brotli/entropy_encode.go
@@ -0,0 +1,592 @@
+package brotli
+
+import "math"
+
+/* Copyright 2010 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Entropy encoding (Huffman) utilities. */
+
+/* A node of a Huffman tree. */
+type huffmanTree struct {
+ total_count_ uint32
+ index_left_ int16
+ index_right_or_value_ int16
+}
+
+func initHuffmanTree(self *huffmanTree, count uint32, left int16, right int16) {
+ self.total_count_ = count
+ self.index_left_ = left
+ self.index_right_or_value_ = right
+}
+
+/* Input size optimized Shell sort. */
+type huffmanTreeComparator func(huffmanTree, huffmanTree) bool
+
+var sortHuffmanTreeItems_gaps = []uint{132, 57, 23, 10, 4, 1}
+
+func sortHuffmanTreeItems(items []huffmanTree, n uint, comparator huffmanTreeComparator) {
+ if n < 13 {
+ /* Insertion sort. */
+ var i uint
+ for i = 1; i < n; i++ {
+ var tmp huffmanTree = items[i]
+ var k uint = i
+ var j uint = i - 1
+ for comparator(tmp, items[j]) {
+ items[k] = items[j]
+ k = j
+ if j == 0 {
+ break
+ }
+ j--
+ }
+
+ items[k] = tmp
+ }
+
+ return
+ } else {
+ var g int
+ if n < 57 {
+ g = 2
+ } else {
+ g = 0
+ }
+ for ; g < 6; g++ {
+ var gap uint = sortHuffmanTreeItems_gaps[g]
+ var i uint
+ for i = gap; i < n; i++ {
+ var j uint = i
+ var tmp huffmanTree = items[i]
+ for ; j >= gap && comparator(tmp, items[j-gap]); j -= gap {
+ items[j] = items[j-gap]
+ }
+
+ items[j] = tmp
+ }
+ }
+ }
+}
+
+/* Returns 1 if assignment of depths succeeded, otherwise 0. */
+func setDepth(p0 int, pool []huffmanTree, depth []byte, max_depth int) bool {
+ var stack [16]int
+ var level int = 0
+ var p int = p0
+ assert(max_depth <= 15)
+ stack[0] = -1
+ for {
+ if pool[p].index_left_ >= 0 {
+ level++
+ if level > max_depth {
+ return false
+ }
+ stack[level] = int(pool[p].index_right_or_value_)
+ p = int(pool[p].index_left_)
+ continue
+ } else {
+ depth[pool[p].index_right_or_value_] = byte(level)
+ }
+
+ for level >= 0 && stack[level] == -1 {
+ level--
+ }
+ if level < 0 {
+ return true
+ }
+ p = stack[level]
+ stack[level] = -1
+ }
+}
+
+/* Sort the root nodes, least popular first. */
+func sortHuffmanTree(v0 huffmanTree, v1 huffmanTree) bool {
+ if v0.total_count_ != v1.total_count_ {
+ return v0.total_count_ < v1.total_count_
+ }
+
+ return v0.index_right_or_value_ > v1.index_right_or_value_
+}
+
+/* This function will create a Huffman tree.
+
+ The catch here is that the tree cannot be arbitrarily deep.
+ Brotli specifies a maximum depth of 15 bits for "code trees"
+ and 7 bits for "code length code trees."
+
+ count_limit is the value that is to be faked as the minimum value
+ and this minimum value is raised until the tree matches the
+ maximum length requirement.
+
+ This algorithm is not of excellent performance for very long data blocks,
+ especially when population counts are longer than 2**tree_limit, but
+ we are not planning to use this with extremely long blocks.
+
+ See http://en.wikipedia.org/wiki/Huffman_coding */
+func createHuffmanTree(data []uint32, length uint, tree_limit int, tree []huffmanTree, depth []byte) {
+ var count_limit uint32
+ var sentinel huffmanTree
+ initHuffmanTree(&sentinel, math.MaxUint32, -1, -1)
+
+ /* For block sizes below 64 kB, we never need to do a second iteration
+ of this loop. Probably all of our block sizes will be smaller than
+ that, so this loop is mostly of academic interest. If we actually
+ would need this, we would be better off with the Katajainen algorithm. */
+ for count_limit = 1; ; count_limit *= 2 {
+ var n uint = 0
+ var i uint
+ var j uint
+ var k uint
+ for i = length; i != 0; {
+ i--
+ if data[i] != 0 {
+ var count uint32 = brotli_max_uint32_t(data[i], count_limit)
+ initHuffmanTree(&tree[n], count, -1, int16(i))
+ n++
+ }
+ }
+
+ if n == 1 {
+ depth[tree[0].index_right_or_value_] = 1 /* Only one element. */
+ break
+ }
+
+ sortHuffmanTreeItems(tree, n, huffmanTreeComparator(sortHuffmanTree))
+
+ /* The nodes are:
+ [0, n): the sorted leaf nodes that we start with.
+ [n]: we add a sentinel here.
+ [n + 1, 2n): new parent nodes are added here, starting from
+ (n+1). These are naturally in ascending order.
+ [2n]: we add a sentinel at the end as well.
+ There will be (2n+1) elements at the end. */
+ tree[n] = sentinel
+
+ tree[n+1] = sentinel
+
+ i = 0 /* Points to the next leaf node. */
+ j = n + 1 /* Points to the next non-leaf node. */
+ for k = n - 1; k != 0; k-- {
+ var left uint
+ var right uint
+ if tree[i].total_count_ <= tree[j].total_count_ {
+ left = i
+ i++
+ } else {
+ left = j
+ j++
+ }
+
+ if tree[i].total_count_ <= tree[j].total_count_ {
+ right = i
+ i++
+ } else {
+ right = j
+ j++
+ }
+ {
+ /* The sentinel node becomes the parent node. */
+ var j_end uint = 2*n - k
+ tree[j_end].total_count_ = tree[left].total_count_ + tree[right].total_count_
+ tree[j_end].index_left_ = int16(left)
+ tree[j_end].index_right_or_value_ = int16(right)
+
+ /* Add back the last sentinel node. */
+ tree[j_end+1] = sentinel
+ }
+ }
+
+ if setDepth(int(2*n-1), tree[0:], depth, tree_limit) {
+ /* We need to pack the Huffman tree in tree_limit bits. If this was not
+ successful, add fake entities to the lowest values and retry. */
+ break
+ }
+ }
+}
+
+func reverse(v []byte, start uint, end uint) {
+ end--
+ for start < end {
+ var tmp byte = v[start]
+ v[start] = v[end]
+ v[end] = tmp
+ start++
+ end--
+ }
+}
+
+func writeHuffmanTreeRepetitions(previous_value byte, value byte, repetitions uint, tree_size *uint, tree []byte, extra_bits_data []byte) {
+ assert(repetitions > 0)
+ if previous_value != value {
+ tree[*tree_size] = value
+ extra_bits_data[*tree_size] = 0
+ (*tree_size)++
+ repetitions--
+ }
+
+ if repetitions == 7 {
+ tree[*tree_size] = value
+ extra_bits_data[*tree_size] = 0
+ (*tree_size)++
+ repetitions--
+ }
+
+ if repetitions < 3 {
+ var i uint
+ for i = 0; i < repetitions; i++ {
+ tree[*tree_size] = value
+ extra_bits_data[*tree_size] = 0
+ (*tree_size)++
+ }
+ } else {
+ var start uint = *tree_size
+ repetitions -= 3
+ for {
+ tree[*tree_size] = repeatPreviousCodeLength
+ extra_bits_data[*tree_size] = byte(repetitions & 0x3)
+ (*tree_size)++
+ repetitions >>= 2
+ if repetitions == 0 {
+ break
+ }
+
+ repetitions--
+ }
+
+ reverse(tree, start, *tree_size)
+ reverse(extra_bits_data, start, *tree_size)
+ }
+}
+
+func writeHuffmanTreeRepetitionsZeros(repetitions uint, tree_size *uint, tree []byte, extra_bits_data []byte) {
+ if repetitions == 11 {
+ tree[*tree_size] = 0
+ extra_bits_data[*tree_size] = 0
+ (*tree_size)++
+ repetitions--
+ }
+
+ if repetitions < 3 {
+ var i uint
+ for i = 0; i < repetitions; i++ {
+ tree[*tree_size] = 0
+ extra_bits_data[*tree_size] = 0
+ (*tree_size)++
+ }
+ } else {
+ var start uint = *tree_size
+ repetitions -= 3
+ for {
+ tree[*tree_size] = repeatZeroCodeLength
+ extra_bits_data[*tree_size] = byte(repetitions & 0x7)
+ (*tree_size)++
+ repetitions >>= 3
+ if repetitions == 0 {
+ break
+ }
+
+ repetitions--
+ }
+
+ reverse(tree, start, *tree_size)
+ reverse(extra_bits_data, start, *tree_size)
+ }
+}
+
+/* Change the population counts in a way that the consequent
+ Huffman tree compression, especially its RLE-part will be more
+ likely to compress this data more efficiently.
+
+ length contains the size of the histogram.
+ counts contains the population counts.
+ good_for_rle is a buffer of at least length size */
+func optimizeHuffmanCountsForRLE(length uint, counts []uint32, good_for_rle []byte) {
+ var nonzero_count uint = 0
+ var stride uint
+ var limit uint
+ var sum uint
+ var streak_limit uint = 1240
+ var i uint
+ /* Let's make the Huffman code more compatible with RLE encoding. */
+ for i = 0; i < length; i++ {
+ if counts[i] != 0 {
+ nonzero_count++
+ }
+ }
+
+ if nonzero_count < 16 {
+ return
+ }
+
+ for length != 0 && counts[length-1] == 0 {
+ length--
+ }
+
+ if length == 0 {
+ return /* All zeros. */
+ }
+
+ /* Now counts[0..length - 1] does not have trailing zeros. */
+ {
+ var nonzeros uint = 0
+ var smallest_nonzero uint32 = 1 << 30
+ for i = 0; i < length; i++ {
+ if counts[i] != 0 {
+ nonzeros++
+ if smallest_nonzero > counts[i] {
+ smallest_nonzero = counts[i]
+ }
+ }
+ }
+
+ if nonzeros < 5 {
+ /* Small histogram will model it well. */
+ return
+ }
+
+ if smallest_nonzero < 4 {
+ var zeros uint = length - nonzeros
+ if zeros < 6 {
+ for i = 1; i < length-1; i++ {
+ if counts[i-1] != 0 && counts[i] == 0 && counts[i+1] != 0 {
+ counts[i] = 1
+ }
+ }
+ }
+ }
+
+ if nonzeros < 28 {
+ return
+ }
+ }
+
+ /* 2) Let's mark all population counts that already can be encoded
+ with an RLE code. */
+ for i := 0; i < int(length); i++ {
+ good_for_rle[i] = 0
+ }
+ {
+ var symbol uint32 = counts[0]
+ /* Let's not spoil any of the existing good RLE codes.
+ Mark any seq of 0's that is longer as 5 as a good_for_rle.
+ Mark any seq of non-0's that is longer as 7 as a good_for_rle. */
+
+ var step uint = 0
+ for i = 0; i <= length; i++ {
+ if i == length || counts[i] != symbol {
+ if (symbol == 0 && step >= 5) || (symbol != 0 && step >= 7) {
+ var k uint
+ for k = 0; k < step; k++ {
+ good_for_rle[i-k-1] = 1
+ }
+ }
+
+ step = 1
+ if i != length {
+ symbol = counts[i]
+ }
+ } else {
+ step++
+ }
+ }
+ }
+
+ /* 3) Let's replace those population counts that lead to more RLE codes.
+ Math here is in 24.8 fixed point representation. */
+ stride = 0
+
+ limit = uint(256*(counts[0]+counts[1]+counts[2])/3 + 420)
+ sum = 0
+ for i = 0; i <= length; i++ {
+ if i == length || good_for_rle[i] != 0 || (i != 0 && good_for_rle[i-1] != 0) || (256*counts[i]-uint32(limit)+uint32(streak_limit)) >= uint32(2*streak_limit) {
+ if stride >= 4 || (stride >= 3 && sum == 0) {
+ var k uint
+ var count uint = (sum + stride/2) / stride
+ /* The stride must end, collapse what we have, if we have enough (4). */
+ if count == 0 {
+ count = 1
+ }
+
+ if sum == 0 {
+ /* Don't make an all zeros stride to be upgraded to ones. */
+ count = 0
+ }
+
+ for k = 0; k < stride; k++ {
+ /* We don't want to change value at counts[i],
+ that is already belonging to the next stride. Thus - 1. */
+ counts[i-k-1] = uint32(count)
+ }
+ }
+
+ stride = 0
+ sum = 0
+ if i < length-2 {
+ /* All interesting strides have a count of at least 4, */
+ /* at least when non-zeros. */
+ limit = uint(256*(counts[i]+counts[i+1]+counts[i+2])/3 + 420)
+ } else if i < length {
+ limit = uint(256 * counts[i])
+ } else {
+ limit = 0
+ }
+ }
+
+ stride++
+ if i != length {
+ sum += uint(counts[i])
+ if stride >= 4 {
+ limit = (256*sum + stride/2) / stride
+ }
+
+ if stride == 4 {
+ limit += 120
+ }
+ }
+ }
+}
+
+func decideOverRLEUse(depth []byte, length uint, use_rle_for_non_zero *bool, use_rle_for_zero *bool) {
+ var total_reps_zero uint = 0
+ var total_reps_non_zero uint = 0
+ var count_reps_zero uint = 1
+ var count_reps_non_zero uint = 1
+ var i uint
+ for i = 0; i < length; {
+ var value byte = depth[i]
+ var reps uint = 1
+ var k uint
+ for k = i + 1; k < length && depth[k] == value; k++ {
+ reps++
+ }
+
+ if reps >= 3 && value == 0 {
+ total_reps_zero += reps
+ count_reps_zero++
+ }
+
+ if reps >= 4 && value != 0 {
+ total_reps_non_zero += reps
+ count_reps_non_zero++
+ }
+
+ i += reps
+ }
+
+ *use_rle_for_non_zero = total_reps_non_zero > count_reps_non_zero*2
+ *use_rle_for_zero = total_reps_zero > count_reps_zero*2
+}
+
+/* Write a Huffman tree from bit depths into the bit-stream representation
+ of a Huffman tree. The generated Huffman tree is to be compressed once
+ more using a Huffman tree */
+func writeHuffmanTree(depth []byte, length uint, tree_size *uint, tree []byte, extra_bits_data []byte) {
+ var previous_value byte = initialRepeatedCodeLength
+ var i uint
+ var use_rle_for_non_zero bool = false
+ var use_rle_for_zero bool = false
+ var new_length uint = length
+ /* Throw away trailing zeros. */
+ for i = 0; i < length; i++ {
+ if depth[length-i-1] == 0 {
+ new_length--
+ } else {
+ break
+ }
+ }
+
+ /* First gather statistics on if it is a good idea to do RLE. */
+ if length > 50 {
+ /* Find RLE coding for longer codes.
+ Shorter codes seem not to benefit from RLE. */
+ decideOverRLEUse(depth, new_length, &use_rle_for_non_zero, &use_rle_for_zero)
+ }
+
+ /* Actual RLE coding. */
+ for i = 0; i < new_length; {
+ var value byte = depth[i]
+ var reps uint = 1
+ if (value != 0 && use_rle_for_non_zero) || (value == 0 && use_rle_for_zero) {
+ var k uint
+ for k = i + 1; k < new_length && depth[k] == value; k++ {
+ reps++
+ }
+ }
+
+ if value == 0 {
+ writeHuffmanTreeRepetitionsZeros(reps, tree_size, tree, extra_bits_data)
+ } else {
+ writeHuffmanTreeRepetitions(previous_value, value, reps, tree_size, tree, extra_bits_data)
+ previous_value = value
+ }
+
+ i += reps
+ }
+}
+
+var reverseBits_kLut = [16]uint{
+ 0x00,
+ 0x08,
+ 0x04,
+ 0x0C,
+ 0x02,
+ 0x0A,
+ 0x06,
+ 0x0E,
+ 0x01,
+ 0x09,
+ 0x05,
+ 0x0D,
+ 0x03,
+ 0x0B,
+ 0x07,
+ 0x0F,
+}
+
+func reverseBits(num_bits uint, bits uint16) uint16 {
+ var retval uint = reverseBits_kLut[bits&0x0F]
+ var i uint
+ for i = 4; i < num_bits; i += 4 {
+ retval <<= 4
+ bits = uint16(bits >> 4)
+ retval |= reverseBits_kLut[bits&0x0F]
+ }
+
+ retval >>= ((0 - num_bits) & 0x03)
+ return uint16(retval)
+}
+
+/* 0..15 are values for bits */
+const maxHuffmanBits = 16
+
+/* Get the actual bit values for a tree of bit depths. */
+func convertBitDepthsToSymbols(depth []byte, len uint, bits []uint16) {
+ var bl_count = [maxHuffmanBits]uint16{0}
+ var next_code [maxHuffmanBits]uint16
+ var i uint
+ /* In Brotli, all bit depths are [1..15]
+ 0 bit depth means that the symbol does not exist. */
+
+ var code int = 0
+ for i = 0; i < len; i++ {
+ bl_count[depth[i]]++
+ }
+
+ bl_count[0] = 0
+ next_code[0] = 0
+ for i = 1; i < maxHuffmanBits; i++ {
+ code = (code + int(bl_count[i-1])) << 1
+ next_code[i] = uint16(code)
+ }
+
+ for i = 0; i < len; i++ {
+ if depth[i] != 0 {
+ bits[i] = reverseBits(uint(depth[i]), next_code[depth[i]])
+ next_code[depth[i]]++
+ }
+ }
+}
diff --git a/vendor/github.com/andybalholm/brotli/entropy_encode_static.go b/vendor/github.com/andybalholm/brotli/entropy_encode_static.go
new file mode 100644
index 0000000..5ddf3fc
--- /dev/null
+++ b/vendor/github.com/andybalholm/brotli/entropy_encode_static.go
@@ -0,0 +1,4394 @@
+package brotli
+
+var kCodeLengthDepth = [18]byte{4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 0, 4, 4}
+
+var kStaticCommandCodeDepth = [numCommandSymbols]byte{
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+}
+
+var kStaticDistanceCodeDepth = [64]byte{
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+}
+
+var kCodeLengthBits = [18]uint32{0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 15, 31, 0, 11, 7}
+
+func storeStaticCodeLengthCode(storage_ix *uint, storage []byte) {
+ writeBits(40, 0x0000FF55555554, storage_ix, storage)
+}
+
+var kZeroRepsBits = [numCommandSymbols]uint64{
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000007,
+ 0x00000017,
+ 0x00000027,
+ 0x00000037,
+ 0x00000047,
+ 0x00000057,
+ 0x00000067,
+ 0x00000077,
+ 0x00000770,
+ 0x00000b87,
+ 0x00001387,
+ 0x00001b87,
+ 0x00002387,
+ 0x00002b87,
+ 0x00003387,
+ 0x00003b87,
+ 0x00000397,
+ 0x00000b97,
+ 0x00001397,
+ 0x00001b97,
+ 0x00002397,
+ 0x00002b97,
+ 0x00003397,
+ 0x00003b97,
+ 0x000003a7,
+ 0x00000ba7,
+ 0x000013a7,
+ 0x00001ba7,
+ 0x000023a7,
+ 0x00002ba7,
+ 0x000033a7,
+ 0x00003ba7,
+ 0x000003b7,
+ 0x00000bb7,
+ 0x000013b7,
+ 0x00001bb7,
+ 0x000023b7,
+ 0x00002bb7,
+ 0x000033b7,
+ 0x00003bb7,
+ 0x000003c7,
+ 0x00000bc7,
+ 0x000013c7,
+ 0x00001bc7,
+ 0x000023c7,
+ 0x00002bc7,
+ 0x000033c7,
+ 0x00003bc7,
+ 0x000003d7,
+ 0x00000bd7,
+ 0x000013d7,
+ 0x00001bd7,
+ 0x000023d7,
+ 0x00002bd7,
+ 0x000033d7,
+ 0x00003bd7,
+ 0x000003e7,
+ 0x00000be7,
+ 0x000013e7,
+ 0x00001be7,
+ 0x000023e7,
+ 0x00002be7,
+ 0x000033e7,
+ 0x00003be7,
+ 0x000003f7,
+ 0x00000bf7,
+ 0x000013f7,
+ 0x00001bf7,
+ 0x000023f7,
+ 0x00002bf7,
+ 0x000033f7,
+ 0x00003bf7,
+ 0x0001c387,
+ 0x0005c387,
+ 0x0009c387,
+ 0x000dc387,
+ 0x0011c387,
+ 0x0015c387,
+ 0x0019c387,
+ 0x001dc387,
+ 0x0001cb87,
+ 0x0005cb87,
+ 0x0009cb87,
+ 0x000dcb87,
+ 0x0011cb87,
+ 0x0015cb87,
+ 0x0019cb87,
+ 0x001dcb87,
+ 0x0001d387,
+ 0x0005d387,
+ 0x0009d387,
+ 0x000dd387,
+ 0x0011d387,
+ 0x0015d387,
+ 0x0019d387,
+ 0x001dd387,
+ 0x0001db87,
+ 0x0005db87,
+ 0x0009db87,
+ 0x000ddb87,
+ 0x0011db87,
+ 0x0015db87,
+ 0x0019db87,
+ 0x001ddb87,
+ 0x0001e387,
+ 0x0005e387,
+ 0x0009e387,
+ 0x000de387,
+ 0x0011e387,
+ 0x0015e387,
+ 0x0019e387,
+ 0x001de387,
+ 0x0001eb87,
+ 0x0005eb87,
+ 0x0009eb87,
+ 0x000deb87,
+ 0x0011eb87,
+ 0x0015eb87,
+ 0x0019eb87,
+ 0x001deb87,
+ 0x0001f387,
+ 0x0005f387,
+ 0x0009f387,
+ 0x000df387,
+ 0x0011f387,
+ 0x0015f387,
+ 0x0019f387,
+ 0x001df387,
+ 0x0001fb87,
+ 0x0005fb87,
+ 0x0009fb87,
+ 0x000dfb87,
+ 0x0011fb87,
+ 0x0015fb87,
+ 0x0019fb87,
+ 0x001dfb87,
+ 0x0001c397,
+ 0x0005c397,
+ 0x0009c397,
+ 0x000dc397,
+ 0x0011c397,
+ 0x0015c397,
+ 0x0019c397,
+ 0x001dc397,
+ 0x0001cb97,
+ 0x0005cb97,
+ 0x0009cb97,
+ 0x000dcb97,
+ 0x0011cb97,
+ 0x0015cb97,
+ 0x0019cb97,
+ 0x001dcb97,
+ 0x0001d397,
+ 0x0005d397,
+ 0x0009d397,
+ 0x000dd397,
+ 0x0011d397,
+ 0x0015d397,
+ 0x0019d397,
+ 0x001dd397,
+ 0x0001db97,
+ 0x0005db97,
+ 0x0009db97,
+ 0x000ddb97,
+ 0x0011db97,
+ 0x0015db97,
+ 0x0019db97,
+ 0x001ddb97,
+ 0x0001e397,
+ 0x0005e397,
+ 0x0009e397,
+ 0x000de397,
+ 0x0011e397,
+ 0x0015e397,
+ 0x0019e397,
+ 0x001de397,
+ 0x0001eb97,
+ 0x0005eb97,
+ 0x0009eb97,
+ 0x000deb97,
+ 0x0011eb97,
+ 0x0015eb97,
+ 0x0019eb97,
+ 0x001deb97,
+ 0x0001f397,
+ 0x0005f397,
+ 0x0009f397,
+ 0x000df397,
+ 0x0011f397,
+ 0x0015f397,
+ 0x0019f397,
+ 0x001df397,
+ 0x0001fb97,
+ 0x0005fb97,
+ 0x0009fb97,
+ 0x000dfb97,
+ 0x0011fb97,
+ 0x0015fb97,
+ 0x0019fb97,
+ 0x001dfb97,
+ 0x0001c3a7,
+ 0x0005c3a7,
+ 0x0009c3a7,
+ 0x000dc3a7,
+ 0x0011c3a7,
+ 0x0015c3a7,
+ 0x0019c3a7,
+ 0x001dc3a7,
+ 0x0001cba7,
+ 0x0005cba7,
+ 0x0009cba7,
+ 0x000dcba7,
+ 0x0011cba7,
+ 0x0015cba7,
+ 0x0019cba7,
+ 0x001dcba7,
+ 0x0001d3a7,
+ 0x0005d3a7,
+ 0x0009d3a7,
+ 0x000dd3a7,
+ 0x0011d3a7,
+ 0x0015d3a7,
+ 0x0019d3a7,
+ 0x001dd3a7,
+ 0x0001dba7,
+ 0x0005dba7,
+ 0x0009dba7,
+ 0x000ddba7,
+ 0x0011dba7,
+ 0x0015dba7,
+ 0x0019dba7,
+ 0x001ddba7,
+ 0x0001e3a7,
+ 0x0005e3a7,
+ 0x0009e3a7,
+ 0x000de3a7,
+ 0x0011e3a7,
+ 0x0015e3a7,
+ 0x0019e3a7,
+ 0x001de3a7,
+ 0x0001eba7,
+ 0x0005eba7,
+ 0x0009eba7,
+ 0x000deba7,
+ 0x0011eba7,
+ 0x0015eba7,
+ 0x0019eba7,
+ 0x001deba7,
+ 0x0001f3a7,
+ 0x0005f3a7,
+ 0x0009f3a7,
+ 0x000df3a7,
+ 0x0011f3a7,
+ 0x0015f3a7,
+ 0x0019f3a7,
+ 0x001df3a7,
+ 0x0001fba7,
+ 0x0005fba7,
+ 0x0009fba7,
+ 0x000dfba7,
+ 0x0011fba7,
+ 0x0015fba7,
+ 0x0019fba7,
+ 0x001dfba7,
+ 0x0001c3b7,
+ 0x0005c3b7,
+ 0x0009c3b7,
+ 0x000dc3b7,
+ 0x0011c3b7,
+ 0x0015c3b7,
+ 0x0019c3b7,
+ 0x001dc3b7,
+ 0x0001cbb7,
+ 0x0005cbb7,
+ 0x0009cbb7,
+ 0x000dcbb7,
+ 0x0011cbb7,
+ 0x0015cbb7,
+ 0x0019cbb7,
+ 0x001dcbb7,
+ 0x0001d3b7,
+ 0x0005d3b7,
+ 0x0009d3b7,
+ 0x000dd3b7,
+ 0x0011d3b7,
+ 0x0015d3b7,
+ 0x0019d3b7,
+ 0x001dd3b7,
+ 0x0001dbb7,
+ 0x0005dbb7,
+ 0x0009dbb7,
+ 0x000ddbb7,
+ 0x0011dbb7,
+ 0x0015dbb7,
+ 0x0019dbb7,
+ 0x001ddbb7,
+ 0x0001e3b7,
+ 0x0005e3b7,
+ 0x0009e3b7,
+ 0x000de3b7,
+ 0x0011e3b7,
+ 0x0015e3b7,
+ 0x0019e3b7,
+ 0x001de3b7,
+ 0x0001ebb7,
+ 0x0005ebb7,
+ 0x0009ebb7,
+ 0x000debb7,
+ 0x0011ebb7,
+ 0x0015ebb7,
+ 0x0019ebb7,
+ 0x001debb7,
+ 0x0001f3b7,
+ 0x0005f3b7,
+ 0x0009f3b7,
+ 0x000df3b7,
+ 0x0011f3b7,
+ 0x0015f3b7,
+ 0x0019f3b7,
+ 0x001df3b7,
+ 0x0001fbb7,
+ 0x0005fbb7,
+ 0x0009fbb7,
+ 0x000dfbb7,
+ 0x0011fbb7,
+ 0x0015fbb7,
+ 0x0019fbb7,
+ 0x001dfbb7,
+ 0x0001c3c7,
+ 0x0005c3c7,
+ 0x0009c3c7,
+ 0x000dc3c7,
+ 0x0011c3c7,
+ 0x0015c3c7,
+ 0x0019c3c7,
+ 0x001dc3c7,
+ 0x0001cbc7,
+ 0x0005cbc7,
+ 0x0009cbc7,
+ 0x000dcbc7,
+ 0x0011cbc7,
+ 0x0015cbc7,
+ 0x0019cbc7,
+ 0x001dcbc7,
+ 0x0001d3c7,
+ 0x0005d3c7,
+ 0x0009d3c7,
+ 0x000dd3c7,
+ 0x0011d3c7,
+ 0x0015d3c7,
+ 0x0019d3c7,
+ 0x001dd3c7,
+ 0x0001dbc7,
+ 0x0005dbc7,
+ 0x0009dbc7,
+ 0x000ddbc7,
+ 0x0011dbc7,
+ 0x0015dbc7,
+ 0x0019dbc7,
+ 0x001ddbc7,
+ 0x0001e3c7,
+ 0x0005e3c7,
+ 0x0009e3c7,
+ 0x000de3c7,
+ 0x0011e3c7,
+ 0x0015e3c7,
+ 0x0019e3c7,
+ 0x001de3c7,
+ 0x0001ebc7,
+ 0x0005ebc7,
+ 0x0009ebc7,
+ 0x000debc7,
+ 0x0011ebc7,
+ 0x0015ebc7,
+ 0x0019ebc7,
+ 0x001debc7,
+ 0x0001f3c7,
+ 0x0005f3c7,
+ 0x0009f3c7,
+ 0x000df3c7,
+ 0x0011f3c7,
+ 0x0015f3c7,
+ 0x0019f3c7,
+ 0x001df3c7,
+ 0x0001fbc7,
+ 0x0005fbc7,
+ 0x0009fbc7,
+ 0x000dfbc7,
+ 0x0011fbc7,
+ 0x0015fbc7,
+ 0x0019fbc7,
+ 0x001dfbc7,
+ 0x0001c3d7,
+ 0x0005c3d7,
+ 0x0009c3d7,
+ 0x000dc3d7,
+ 0x0011c3d7,
+ 0x0015c3d7,
+ 0x0019c3d7,
+ 0x001dc3d7,
+ 0x0001cbd7,
+ 0x0005cbd7,
+ 0x0009cbd7,
+ 0x000dcbd7,
+ 0x0011cbd7,
+ 0x0015cbd7,
+ 0x0019cbd7,
+ 0x001dcbd7,
+ 0x0001d3d7,
+ 0x0005d3d7,
+ 0x0009d3d7,
+ 0x000dd3d7,
+ 0x0011d3d7,
+ 0x0015d3d7,
+ 0x0019d3d7,
+ 0x001dd3d7,
+ 0x0001dbd7,
+ 0x0005dbd7,
+ 0x0009dbd7,
+ 0x000ddbd7,
+ 0x0011dbd7,
+ 0x0015dbd7,
+ 0x0019dbd7,
+ 0x001ddbd7,
+ 0x0001e3d7,
+ 0x0005e3d7,
+ 0x0009e3d7,
+ 0x000de3d7,
+ 0x0011e3d7,
+ 0x0015e3d7,
+ 0x0019e3d7,
+ 0x001de3d7,
+ 0x0001ebd7,
+ 0x0005ebd7,
+ 0x0009ebd7,
+ 0x000debd7,
+ 0x0011ebd7,
+ 0x0015ebd7,
+ 0x0019ebd7,
+ 0x001debd7,
+ 0x0001f3d7,
+ 0x0005f3d7,
+ 0x0009f3d7,
+ 0x000df3d7,
+ 0x0011f3d7,
+ 0x0015f3d7,
+ 0x0019f3d7,
+ 0x001df3d7,
+ 0x0001fbd7,
+ 0x0005fbd7,
+ 0x0009fbd7,
+ 0x000dfbd7,
+ 0x0011fbd7,
+ 0x0015fbd7,
+ 0x0019fbd7,
+ 0x001dfbd7,
+ 0x0001c3e7,
+ 0x0005c3e7,
+ 0x0009c3e7,
+ 0x000dc3e7,
+ 0x0011c3e7,
+ 0x0015c3e7,
+ 0x0019c3e7,
+ 0x001dc3e7,
+ 0x0001cbe7,
+ 0x0005cbe7,
+ 0x0009cbe7,
+ 0x000dcbe7,
+ 0x0011cbe7,
+ 0x0015cbe7,
+ 0x0019cbe7,
+ 0x001dcbe7,
+ 0x0001d3e7,
+ 0x0005d3e7,
+ 0x0009d3e7,
+ 0x000dd3e7,
+ 0x0011d3e7,
+ 0x0015d3e7,
+ 0x0019d3e7,
+ 0x001dd3e7,
+ 0x0001dbe7,
+ 0x0005dbe7,
+ 0x0009dbe7,
+ 0x000ddbe7,
+ 0x0011dbe7,
+ 0x0015dbe7,
+ 0x0019dbe7,
+ 0x001ddbe7,
+ 0x0001e3e7,
+ 0x0005e3e7,
+ 0x0009e3e7,
+ 0x000de3e7,
+ 0x0011e3e7,
+ 0x0015e3e7,
+ 0x0019e3e7,
+ 0x001de3e7,
+ 0x0001ebe7,
+ 0x0005ebe7,
+ 0x0009ebe7,
+ 0x000debe7,
+ 0x0011ebe7,
+ 0x0015ebe7,
+ 0x0019ebe7,
+ 0x001debe7,
+ 0x0001f3e7,
+ 0x0005f3e7,
+ 0x0009f3e7,
+ 0x000df3e7,
+ 0x0011f3e7,
+ 0x0015f3e7,
+ 0x0019f3e7,
+ 0x001df3e7,
+ 0x0001fbe7,
+ 0x0005fbe7,
+ 0x0009fbe7,
+ 0x000dfbe7,
+ 0x0011fbe7,
+ 0x0015fbe7,
+ 0x0019fbe7,
+ 0x001dfbe7,
+ 0x0001c3f7,
+ 0x0005c3f7,
+ 0x0009c3f7,
+ 0x000dc3f7,
+ 0x0011c3f7,
+ 0x0015c3f7,
+ 0x0019c3f7,
+ 0x001dc3f7,
+ 0x0001cbf7,
+ 0x0005cbf7,
+ 0x0009cbf7,
+ 0x000dcbf7,
+ 0x0011cbf7,
+ 0x0015cbf7,
+ 0x0019cbf7,
+ 0x001dcbf7,
+ 0x0001d3f7,
+ 0x0005d3f7,
+ 0x0009d3f7,
+ 0x000dd3f7,
+ 0x0011d3f7,
+ 0x0015d3f7,
+ 0x0019d3f7,
+ 0x001dd3f7,
+ 0x0001dbf7,
+ 0x0005dbf7,
+ 0x0009dbf7,
+ 0x000ddbf7,
+ 0x0011dbf7,
+ 0x0015dbf7,
+ 0x0019dbf7,
+ 0x001ddbf7,
+ 0x0001e3f7,
+ 0x0005e3f7,
+ 0x0009e3f7,
+ 0x000de3f7,
+ 0x0011e3f7,
+ 0x0015e3f7,
+ 0x0019e3f7,
+ 0x001de3f7,
+ 0x0001ebf7,
+ 0x0005ebf7,
+ 0x0009ebf7,
+ 0x000debf7,
+ 0x0011ebf7,
+ 0x0015ebf7,
+ 0x0019ebf7,
+ 0x001debf7,
+ 0x0001f3f7,
+ 0x0005f3f7,
+ 0x0009f3f7,
+ 0x000df3f7,
+ 0x0011f3f7,
+ 0x0015f3f7,
+ 0x0019f3f7,
+ 0x001df3f7,
+ 0x0001fbf7,
+ 0x0005fbf7,
+ 0x0009fbf7,
+ 0x000dfbf7,
+ 0x0011fbf7,
+ 0x0015fbf7,
+ 0x0019fbf7,
+ 0x001dfbf7,
+ 0x00e1c387,
+ 0x02e1c387,
+ 0x04e1c387,
+ 0x06e1c387,
+ 0x08e1c387,
+ 0x0ae1c387,
+ 0x0ce1c387,
+ 0x0ee1c387,
+ 0x00e5c387,
+ 0x02e5c387,
+ 0x04e5c387,
+ 0x06e5c387,
+ 0x08e5c387,
+ 0x0ae5c387,
+ 0x0ce5c387,
+ 0x0ee5c387,
+ 0x00e9c387,
+ 0x02e9c387,
+ 0x04e9c387,
+ 0x06e9c387,
+ 0x08e9c387,
+ 0x0ae9c387,
+ 0x0ce9c387,
+ 0x0ee9c387,
+ 0x00edc387,
+ 0x02edc387,
+ 0x04edc387,
+ 0x06edc387,
+ 0x08edc387,
+ 0x0aedc387,
+ 0x0cedc387,
+ 0x0eedc387,
+ 0x00f1c387,
+ 0x02f1c387,
+ 0x04f1c387,
+ 0x06f1c387,
+ 0x08f1c387,
+ 0x0af1c387,
+ 0x0cf1c387,
+ 0x0ef1c387,
+ 0x00f5c387,
+ 0x02f5c387,
+ 0x04f5c387,
+ 0x06f5c387,
+ 0x08f5c387,
+ 0x0af5c387,
+ 0x0cf5c387,
+ 0x0ef5c387,
+ 0x00f9c387,
+ 0x02f9c387,
+ 0x04f9c387,
+ 0x06f9c387,
+ 0x08f9c387,
+ 0x0af9c387,
+ 0x0cf9c387,
+ 0x0ef9c387,
+ 0x00fdc387,
+ 0x02fdc387,
+ 0x04fdc387,
+ 0x06fdc387,
+ 0x08fdc387,
+ 0x0afdc387,
+ 0x0cfdc387,
+ 0x0efdc387,
+ 0x00e1cb87,
+ 0x02e1cb87,
+ 0x04e1cb87,
+ 0x06e1cb87,
+ 0x08e1cb87,
+ 0x0ae1cb87,
+ 0x0ce1cb87,
+ 0x0ee1cb87,
+ 0x00e5cb87,
+ 0x02e5cb87,
+ 0x04e5cb87,
+ 0x06e5cb87,
+ 0x08e5cb87,
+ 0x0ae5cb87,
+ 0x0ce5cb87,
+ 0x0ee5cb87,
+ 0x00e9cb87,
+ 0x02e9cb87,
+ 0x04e9cb87,
+ 0x06e9cb87,
+ 0x08e9cb87,
+ 0x0ae9cb87,
+ 0x0ce9cb87,
+ 0x0ee9cb87,
+ 0x00edcb87,
+ 0x02edcb87,
+ 0x04edcb87,
+ 0x06edcb87,
+ 0x08edcb87,
+ 0x0aedcb87,
+ 0x0cedcb87,
+ 0x0eedcb87,
+ 0x00f1cb87,
+ 0x02f1cb87,
+ 0x04f1cb87,
+ 0x06f1cb87,
+ 0x08f1cb87,
+ 0x0af1cb87,
+ 0x0cf1cb87,
+ 0x0ef1cb87,
+ 0x00f5cb87,
+ 0x02f5cb87,
+ 0x04f5cb87,
+ 0x06f5cb87,
+ 0x08f5cb87,
+ 0x0af5cb87,
+ 0x0cf5cb87,
+ 0x0ef5cb87,
+ 0x00f9cb87,
+ 0x02f9cb87,
+ 0x04f9cb87,
+ 0x06f9cb87,
+ 0x08f9cb87,
+}
+
+var kZeroRepsDepth = [numCommandSymbols]uint32{
+ 0,
+ 4,
+ 8,
+ 7,
+ 7,
+ 7,
+ 7,
+ 7,
+ 7,
+ 7,
+ 7,
+ 11,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+}
+
+var kNonZeroRepsBits = [numCommandSymbols]uint64{
+ 0x0000000b,
+ 0x0000001b,
+ 0x0000002b,
+ 0x0000003b,
+ 0x000002cb,
+ 0x000006cb,
+ 0x00000acb,
+ 0x00000ecb,
+ 0x000002db,
+ 0x000006db,
+ 0x00000adb,
+ 0x00000edb,
+ 0x000002eb,
+ 0x000006eb,
+ 0x00000aeb,
+ 0x00000eeb,
+ 0x000002fb,
+ 0x000006fb,
+ 0x00000afb,
+ 0x00000efb,
+ 0x0000b2cb,
+ 0x0001b2cb,
+ 0x0002b2cb,
+ 0x0003b2cb,
+ 0x0000b6cb,
+ 0x0001b6cb,
+ 0x0002b6cb,
+ 0x0003b6cb,
+ 0x0000bacb,
+ 0x0001bacb,
+ 0x0002bacb,
+ 0x0003bacb,
+ 0x0000becb,
+ 0x0001becb,
+ 0x0002becb,
+ 0x0003becb,
+ 0x0000b2db,
+ 0x0001b2db,
+ 0x0002b2db,
+ 0x0003b2db,
+ 0x0000b6db,
+ 0x0001b6db,
+ 0x0002b6db,
+ 0x0003b6db,
+ 0x0000badb,
+ 0x0001badb,
+ 0x0002badb,
+ 0x0003badb,
+ 0x0000bedb,
+ 0x0001bedb,
+ 0x0002bedb,
+ 0x0003bedb,
+ 0x0000b2eb,
+ 0x0001b2eb,
+ 0x0002b2eb,
+ 0x0003b2eb,
+ 0x0000b6eb,
+ 0x0001b6eb,
+ 0x0002b6eb,
+ 0x0003b6eb,
+ 0x0000baeb,
+ 0x0001baeb,
+ 0x0002baeb,
+ 0x0003baeb,
+ 0x0000beeb,
+ 0x0001beeb,
+ 0x0002beeb,
+ 0x0003beeb,
+ 0x0000b2fb,
+ 0x0001b2fb,
+ 0x0002b2fb,
+ 0x0003b2fb,
+ 0x0000b6fb,
+ 0x0001b6fb,
+ 0x0002b6fb,
+ 0x0003b6fb,
+ 0x0000bafb,
+ 0x0001bafb,
+ 0x0002bafb,
+ 0x0003bafb,
+ 0x0000befb,
+ 0x0001befb,
+ 0x0002befb,
+ 0x0003befb,
+ 0x002cb2cb,
+ 0x006cb2cb,
+ 0x00acb2cb,
+ 0x00ecb2cb,
+ 0x002db2cb,
+ 0x006db2cb,
+ 0x00adb2cb,
+ 0x00edb2cb,
+ 0x002eb2cb,
+ 0x006eb2cb,
+ 0x00aeb2cb,
+ 0x00eeb2cb,
+ 0x002fb2cb,
+ 0x006fb2cb,
+ 0x00afb2cb,
+ 0x00efb2cb,
+ 0x002cb6cb,
+ 0x006cb6cb,
+ 0x00acb6cb,
+ 0x00ecb6cb,
+ 0x002db6cb,
+ 0x006db6cb,
+ 0x00adb6cb,
+ 0x00edb6cb,
+ 0x002eb6cb,
+ 0x006eb6cb,
+ 0x00aeb6cb,
+ 0x00eeb6cb,
+ 0x002fb6cb,
+ 0x006fb6cb,
+ 0x00afb6cb,
+ 0x00efb6cb,
+ 0x002cbacb,
+ 0x006cbacb,
+ 0x00acbacb,
+ 0x00ecbacb,
+ 0x002dbacb,
+ 0x006dbacb,
+ 0x00adbacb,
+ 0x00edbacb,
+ 0x002ebacb,
+ 0x006ebacb,
+ 0x00aebacb,
+ 0x00eebacb,
+ 0x002fbacb,
+ 0x006fbacb,
+ 0x00afbacb,
+ 0x00efbacb,
+ 0x002cbecb,
+ 0x006cbecb,
+ 0x00acbecb,
+ 0x00ecbecb,
+ 0x002dbecb,
+ 0x006dbecb,
+ 0x00adbecb,
+ 0x00edbecb,
+ 0x002ebecb,
+ 0x006ebecb,
+ 0x00aebecb,
+ 0x00eebecb,
+ 0x002fbecb,
+ 0x006fbecb,
+ 0x00afbecb,
+ 0x00efbecb,
+ 0x002cb2db,
+ 0x006cb2db,
+ 0x00acb2db,
+ 0x00ecb2db,
+ 0x002db2db,
+ 0x006db2db,
+ 0x00adb2db,
+ 0x00edb2db,
+ 0x002eb2db,
+ 0x006eb2db,
+ 0x00aeb2db,
+ 0x00eeb2db,
+ 0x002fb2db,
+ 0x006fb2db,
+ 0x00afb2db,
+ 0x00efb2db,
+ 0x002cb6db,
+ 0x006cb6db,
+ 0x00acb6db,
+ 0x00ecb6db,
+ 0x002db6db,
+ 0x006db6db,
+ 0x00adb6db,
+ 0x00edb6db,
+ 0x002eb6db,
+ 0x006eb6db,
+ 0x00aeb6db,
+ 0x00eeb6db,
+ 0x002fb6db,
+ 0x006fb6db,
+ 0x00afb6db,
+ 0x00efb6db,
+ 0x002cbadb,
+ 0x006cbadb,
+ 0x00acbadb,
+ 0x00ecbadb,
+ 0x002dbadb,
+ 0x006dbadb,
+ 0x00adbadb,
+ 0x00edbadb,
+ 0x002ebadb,
+ 0x006ebadb,
+ 0x00aebadb,
+ 0x00eebadb,
+ 0x002fbadb,
+ 0x006fbadb,
+ 0x00afbadb,
+ 0x00efbadb,
+ 0x002cbedb,
+ 0x006cbedb,
+ 0x00acbedb,
+ 0x00ecbedb,
+ 0x002dbedb,
+ 0x006dbedb,
+ 0x00adbedb,
+ 0x00edbedb,
+ 0x002ebedb,
+ 0x006ebedb,
+ 0x00aebedb,
+ 0x00eebedb,
+ 0x002fbedb,
+ 0x006fbedb,
+ 0x00afbedb,
+ 0x00efbedb,
+ 0x002cb2eb,
+ 0x006cb2eb,
+ 0x00acb2eb,
+ 0x00ecb2eb,
+ 0x002db2eb,
+ 0x006db2eb,
+ 0x00adb2eb,
+ 0x00edb2eb,
+ 0x002eb2eb,
+ 0x006eb2eb,
+ 0x00aeb2eb,
+ 0x00eeb2eb,
+ 0x002fb2eb,
+ 0x006fb2eb,
+ 0x00afb2eb,
+ 0x00efb2eb,
+ 0x002cb6eb,
+ 0x006cb6eb,
+ 0x00acb6eb,
+ 0x00ecb6eb,
+ 0x002db6eb,
+ 0x006db6eb,
+ 0x00adb6eb,
+ 0x00edb6eb,
+ 0x002eb6eb,
+ 0x006eb6eb,
+ 0x00aeb6eb,
+ 0x00eeb6eb,
+ 0x002fb6eb,
+ 0x006fb6eb,
+ 0x00afb6eb,
+ 0x00efb6eb,
+ 0x002cbaeb,
+ 0x006cbaeb,
+ 0x00acbaeb,
+ 0x00ecbaeb,
+ 0x002dbaeb,
+ 0x006dbaeb,
+ 0x00adbaeb,
+ 0x00edbaeb,
+ 0x002ebaeb,
+ 0x006ebaeb,
+ 0x00aebaeb,
+ 0x00eebaeb,
+ 0x002fbaeb,
+ 0x006fbaeb,
+ 0x00afbaeb,
+ 0x00efbaeb,
+ 0x002cbeeb,
+ 0x006cbeeb,
+ 0x00acbeeb,
+ 0x00ecbeeb,
+ 0x002dbeeb,
+ 0x006dbeeb,
+ 0x00adbeeb,
+ 0x00edbeeb,
+ 0x002ebeeb,
+ 0x006ebeeb,
+ 0x00aebeeb,
+ 0x00eebeeb,
+ 0x002fbeeb,
+ 0x006fbeeb,
+ 0x00afbeeb,
+ 0x00efbeeb,
+ 0x002cb2fb,
+ 0x006cb2fb,
+ 0x00acb2fb,
+ 0x00ecb2fb,
+ 0x002db2fb,
+ 0x006db2fb,
+ 0x00adb2fb,
+ 0x00edb2fb,
+ 0x002eb2fb,
+ 0x006eb2fb,
+ 0x00aeb2fb,
+ 0x00eeb2fb,
+ 0x002fb2fb,
+ 0x006fb2fb,
+ 0x00afb2fb,
+ 0x00efb2fb,
+ 0x002cb6fb,
+ 0x006cb6fb,
+ 0x00acb6fb,
+ 0x00ecb6fb,
+ 0x002db6fb,
+ 0x006db6fb,
+ 0x00adb6fb,
+ 0x00edb6fb,
+ 0x002eb6fb,
+ 0x006eb6fb,
+ 0x00aeb6fb,
+ 0x00eeb6fb,
+ 0x002fb6fb,
+ 0x006fb6fb,
+ 0x00afb6fb,
+ 0x00efb6fb,
+ 0x002cbafb,
+ 0x006cbafb,
+ 0x00acbafb,
+ 0x00ecbafb,
+ 0x002dbafb,
+ 0x006dbafb,
+ 0x00adbafb,
+ 0x00edbafb,
+ 0x002ebafb,
+ 0x006ebafb,
+ 0x00aebafb,
+ 0x00eebafb,
+ 0x002fbafb,
+ 0x006fbafb,
+ 0x00afbafb,
+ 0x00efbafb,
+ 0x002cbefb,
+ 0x006cbefb,
+ 0x00acbefb,
+ 0x00ecbefb,
+ 0x002dbefb,
+ 0x006dbefb,
+ 0x00adbefb,
+ 0x00edbefb,
+ 0x002ebefb,
+ 0x006ebefb,
+ 0x00aebefb,
+ 0x00eebefb,
+ 0x002fbefb,
+ 0x006fbefb,
+ 0x00afbefb,
+ 0x00efbefb,
+ 0x0b2cb2cb,
+ 0x1b2cb2cb,
+ 0x2b2cb2cb,
+ 0x3b2cb2cb,
+ 0x0b6cb2cb,
+ 0x1b6cb2cb,
+ 0x2b6cb2cb,
+ 0x3b6cb2cb,
+ 0x0bacb2cb,
+ 0x1bacb2cb,
+ 0x2bacb2cb,
+ 0x3bacb2cb,
+ 0x0becb2cb,
+ 0x1becb2cb,
+ 0x2becb2cb,
+ 0x3becb2cb,
+ 0x0b2db2cb,
+ 0x1b2db2cb,
+ 0x2b2db2cb,
+ 0x3b2db2cb,
+ 0x0b6db2cb,
+ 0x1b6db2cb,
+ 0x2b6db2cb,
+ 0x3b6db2cb,
+ 0x0badb2cb,
+ 0x1badb2cb,
+ 0x2badb2cb,
+ 0x3badb2cb,
+ 0x0bedb2cb,
+ 0x1bedb2cb,
+ 0x2bedb2cb,
+ 0x3bedb2cb,
+ 0x0b2eb2cb,
+ 0x1b2eb2cb,
+ 0x2b2eb2cb,
+ 0x3b2eb2cb,
+ 0x0b6eb2cb,
+ 0x1b6eb2cb,
+ 0x2b6eb2cb,
+ 0x3b6eb2cb,
+ 0x0baeb2cb,
+ 0x1baeb2cb,
+ 0x2baeb2cb,
+ 0x3baeb2cb,
+ 0x0beeb2cb,
+ 0x1beeb2cb,
+ 0x2beeb2cb,
+ 0x3beeb2cb,
+ 0x0b2fb2cb,
+ 0x1b2fb2cb,
+ 0x2b2fb2cb,
+ 0x3b2fb2cb,
+ 0x0b6fb2cb,
+ 0x1b6fb2cb,
+ 0x2b6fb2cb,
+ 0x3b6fb2cb,
+ 0x0bafb2cb,
+ 0x1bafb2cb,
+ 0x2bafb2cb,
+ 0x3bafb2cb,
+ 0x0befb2cb,
+ 0x1befb2cb,
+ 0x2befb2cb,
+ 0x3befb2cb,
+ 0x0b2cb6cb,
+ 0x1b2cb6cb,
+ 0x2b2cb6cb,
+ 0x3b2cb6cb,
+ 0x0b6cb6cb,
+ 0x1b6cb6cb,
+ 0x2b6cb6cb,
+ 0x3b6cb6cb,
+ 0x0bacb6cb,
+ 0x1bacb6cb,
+ 0x2bacb6cb,
+ 0x3bacb6cb,
+ 0x0becb6cb,
+ 0x1becb6cb,
+ 0x2becb6cb,
+ 0x3becb6cb,
+ 0x0b2db6cb,
+ 0x1b2db6cb,
+ 0x2b2db6cb,
+ 0x3b2db6cb,
+ 0x0b6db6cb,
+ 0x1b6db6cb,
+ 0x2b6db6cb,
+ 0x3b6db6cb,
+ 0x0badb6cb,
+ 0x1badb6cb,
+ 0x2badb6cb,
+ 0x3badb6cb,
+ 0x0bedb6cb,
+ 0x1bedb6cb,
+ 0x2bedb6cb,
+ 0x3bedb6cb,
+ 0x0b2eb6cb,
+ 0x1b2eb6cb,
+ 0x2b2eb6cb,
+ 0x3b2eb6cb,
+ 0x0b6eb6cb,
+ 0x1b6eb6cb,
+ 0x2b6eb6cb,
+ 0x3b6eb6cb,
+ 0x0baeb6cb,
+ 0x1baeb6cb,
+ 0x2baeb6cb,
+ 0x3baeb6cb,
+ 0x0beeb6cb,
+ 0x1beeb6cb,
+ 0x2beeb6cb,
+ 0x3beeb6cb,
+ 0x0b2fb6cb,
+ 0x1b2fb6cb,
+ 0x2b2fb6cb,
+ 0x3b2fb6cb,
+ 0x0b6fb6cb,
+ 0x1b6fb6cb,
+ 0x2b6fb6cb,
+ 0x3b6fb6cb,
+ 0x0bafb6cb,
+ 0x1bafb6cb,
+ 0x2bafb6cb,
+ 0x3bafb6cb,
+ 0x0befb6cb,
+ 0x1befb6cb,
+ 0x2befb6cb,
+ 0x3befb6cb,
+ 0x0b2cbacb,
+ 0x1b2cbacb,
+ 0x2b2cbacb,
+ 0x3b2cbacb,
+ 0x0b6cbacb,
+ 0x1b6cbacb,
+ 0x2b6cbacb,
+ 0x3b6cbacb,
+ 0x0bacbacb,
+ 0x1bacbacb,
+ 0x2bacbacb,
+ 0x3bacbacb,
+ 0x0becbacb,
+ 0x1becbacb,
+ 0x2becbacb,
+ 0x3becbacb,
+ 0x0b2dbacb,
+ 0x1b2dbacb,
+ 0x2b2dbacb,
+ 0x3b2dbacb,
+ 0x0b6dbacb,
+ 0x1b6dbacb,
+ 0x2b6dbacb,
+ 0x3b6dbacb,
+ 0x0badbacb,
+ 0x1badbacb,
+ 0x2badbacb,
+ 0x3badbacb,
+ 0x0bedbacb,
+ 0x1bedbacb,
+ 0x2bedbacb,
+ 0x3bedbacb,
+ 0x0b2ebacb,
+ 0x1b2ebacb,
+ 0x2b2ebacb,
+ 0x3b2ebacb,
+ 0x0b6ebacb,
+ 0x1b6ebacb,
+ 0x2b6ebacb,
+ 0x3b6ebacb,
+ 0x0baebacb,
+ 0x1baebacb,
+ 0x2baebacb,
+ 0x3baebacb,
+ 0x0beebacb,
+ 0x1beebacb,
+ 0x2beebacb,
+ 0x3beebacb,
+ 0x0b2fbacb,
+ 0x1b2fbacb,
+ 0x2b2fbacb,
+ 0x3b2fbacb,
+ 0x0b6fbacb,
+ 0x1b6fbacb,
+ 0x2b6fbacb,
+ 0x3b6fbacb,
+ 0x0bafbacb,
+ 0x1bafbacb,
+ 0x2bafbacb,
+ 0x3bafbacb,
+ 0x0befbacb,
+ 0x1befbacb,
+ 0x2befbacb,
+ 0x3befbacb,
+ 0x0b2cbecb,
+ 0x1b2cbecb,
+ 0x2b2cbecb,
+ 0x3b2cbecb,
+ 0x0b6cbecb,
+ 0x1b6cbecb,
+ 0x2b6cbecb,
+ 0x3b6cbecb,
+ 0x0bacbecb,
+ 0x1bacbecb,
+ 0x2bacbecb,
+ 0x3bacbecb,
+ 0x0becbecb,
+ 0x1becbecb,
+ 0x2becbecb,
+ 0x3becbecb,
+ 0x0b2dbecb,
+ 0x1b2dbecb,
+ 0x2b2dbecb,
+ 0x3b2dbecb,
+ 0x0b6dbecb,
+ 0x1b6dbecb,
+ 0x2b6dbecb,
+ 0x3b6dbecb,
+ 0x0badbecb,
+ 0x1badbecb,
+ 0x2badbecb,
+ 0x3badbecb,
+ 0x0bedbecb,
+ 0x1bedbecb,
+ 0x2bedbecb,
+ 0x3bedbecb,
+ 0x0b2ebecb,
+ 0x1b2ebecb,
+ 0x2b2ebecb,
+ 0x3b2ebecb,
+ 0x0b6ebecb,
+ 0x1b6ebecb,
+ 0x2b6ebecb,
+ 0x3b6ebecb,
+ 0x0baebecb,
+ 0x1baebecb,
+ 0x2baebecb,
+ 0x3baebecb,
+ 0x0beebecb,
+ 0x1beebecb,
+ 0x2beebecb,
+ 0x3beebecb,
+ 0x0b2fbecb,
+ 0x1b2fbecb,
+ 0x2b2fbecb,
+ 0x3b2fbecb,
+ 0x0b6fbecb,
+ 0x1b6fbecb,
+ 0x2b6fbecb,
+ 0x3b6fbecb,
+ 0x0bafbecb,
+ 0x1bafbecb,
+ 0x2bafbecb,
+ 0x3bafbecb,
+ 0x0befbecb,
+ 0x1befbecb,
+ 0x2befbecb,
+ 0x3befbecb,
+ 0x0b2cb2db,
+ 0x1b2cb2db,
+ 0x2b2cb2db,
+ 0x3b2cb2db,
+ 0x0b6cb2db,
+ 0x1b6cb2db,
+ 0x2b6cb2db,
+ 0x3b6cb2db,
+ 0x0bacb2db,
+ 0x1bacb2db,
+ 0x2bacb2db,
+ 0x3bacb2db,
+ 0x0becb2db,
+ 0x1becb2db,
+ 0x2becb2db,
+ 0x3becb2db,
+ 0x0b2db2db,
+ 0x1b2db2db,
+ 0x2b2db2db,
+ 0x3b2db2db,
+ 0x0b6db2db,
+ 0x1b6db2db,
+ 0x2b6db2db,
+ 0x3b6db2db,
+ 0x0badb2db,
+ 0x1badb2db,
+ 0x2badb2db,
+ 0x3badb2db,
+ 0x0bedb2db,
+ 0x1bedb2db,
+ 0x2bedb2db,
+ 0x3bedb2db,
+ 0x0b2eb2db,
+ 0x1b2eb2db,
+ 0x2b2eb2db,
+ 0x3b2eb2db,
+ 0x0b6eb2db,
+ 0x1b6eb2db,
+ 0x2b6eb2db,
+ 0x3b6eb2db,
+ 0x0baeb2db,
+ 0x1baeb2db,
+ 0x2baeb2db,
+ 0x3baeb2db,
+ 0x0beeb2db,
+ 0x1beeb2db,
+ 0x2beeb2db,
+ 0x3beeb2db,
+ 0x0b2fb2db,
+ 0x1b2fb2db,
+ 0x2b2fb2db,
+ 0x3b2fb2db,
+ 0x0b6fb2db,
+ 0x1b6fb2db,
+ 0x2b6fb2db,
+ 0x3b6fb2db,
+ 0x0bafb2db,
+ 0x1bafb2db,
+ 0x2bafb2db,
+ 0x3bafb2db,
+ 0x0befb2db,
+ 0x1befb2db,
+ 0x2befb2db,
+ 0x3befb2db,
+ 0x0b2cb6db,
+ 0x1b2cb6db,
+ 0x2b2cb6db,
+ 0x3b2cb6db,
+ 0x0b6cb6db,
+ 0x1b6cb6db,
+ 0x2b6cb6db,
+ 0x3b6cb6db,
+ 0x0bacb6db,
+ 0x1bacb6db,
+ 0x2bacb6db,
+ 0x3bacb6db,
+ 0x0becb6db,
+ 0x1becb6db,
+ 0x2becb6db,
+ 0x3becb6db,
+ 0x0b2db6db,
+ 0x1b2db6db,
+ 0x2b2db6db,
+ 0x3b2db6db,
+ 0x0b6db6db,
+ 0x1b6db6db,
+ 0x2b6db6db,
+ 0x3b6db6db,
+ 0x0badb6db,
+ 0x1badb6db,
+ 0x2badb6db,
+ 0x3badb6db,
+ 0x0bedb6db,
+ 0x1bedb6db,
+ 0x2bedb6db,
+ 0x3bedb6db,
+ 0x0b2eb6db,
+ 0x1b2eb6db,
+ 0x2b2eb6db,
+ 0x3b2eb6db,
+ 0x0b6eb6db,
+ 0x1b6eb6db,
+ 0x2b6eb6db,
+ 0x3b6eb6db,
+ 0x0baeb6db,
+ 0x1baeb6db,
+ 0x2baeb6db,
+ 0x3baeb6db,
+}
+
+var kNonZeroRepsDepth = [numCommandSymbols]uint32{
+ 6,
+ 6,
+ 6,
+ 6,
+ 12,
+ 12,
+ 12,
+ 12,
+ 12,
+ 12,
+ 12,
+ 12,
+ 12,
+ 12,
+ 12,
+ 12,
+ 12,
+ 12,
+ 12,
+ 12,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+}
+
+var kStaticCommandCodeBits = [numCommandSymbols]uint16{
+ 0,
+ 256,
+ 128,
+ 384,
+ 64,
+ 320,
+ 192,
+ 448,
+ 32,
+ 288,
+ 160,
+ 416,
+ 96,
+ 352,
+ 224,
+ 480,
+ 16,
+ 272,
+ 144,
+ 400,
+ 80,
+ 336,
+ 208,
+ 464,
+ 48,
+ 304,
+ 176,
+ 432,
+ 112,
+ 368,
+ 240,
+ 496,
+ 8,
+ 264,
+ 136,
+ 392,
+ 72,
+ 328,
+ 200,
+ 456,
+ 40,
+ 296,
+ 168,
+ 424,
+ 104,
+ 360,
+ 232,
+ 488,
+ 24,
+ 280,
+ 152,
+ 408,
+ 88,
+ 344,
+ 216,
+ 472,
+ 56,
+ 312,
+ 184,
+ 440,
+ 120,
+ 376,
+ 248,
+ 504,
+ 4,
+ 260,
+ 132,
+ 388,
+ 68,
+ 324,
+ 196,
+ 452,
+ 36,
+ 292,
+ 164,
+ 420,
+ 100,
+ 356,
+ 228,
+ 484,
+ 20,
+ 276,
+ 148,
+ 404,
+ 84,
+ 340,
+ 212,
+ 468,
+ 52,
+ 308,
+ 180,
+ 436,
+ 116,
+ 372,
+ 244,
+ 500,
+ 12,
+ 268,
+ 140,
+ 396,
+ 76,
+ 332,
+ 204,
+ 460,
+ 44,
+ 300,
+ 172,
+ 428,
+ 108,
+ 364,
+ 236,
+ 492,
+ 28,
+ 284,
+ 156,
+ 412,
+ 92,
+ 348,
+ 220,
+ 476,
+ 60,
+ 316,
+ 188,
+ 444,
+ 124,
+ 380,
+ 252,
+ 508,
+ 2,
+ 258,
+ 130,
+ 386,
+ 66,
+ 322,
+ 194,
+ 450,
+ 34,
+ 290,
+ 162,
+ 418,
+ 98,
+ 354,
+ 226,
+ 482,
+ 18,
+ 274,
+ 146,
+ 402,
+ 82,
+ 338,
+ 210,
+ 466,
+ 50,
+ 306,
+ 178,
+ 434,
+ 114,
+ 370,
+ 242,
+ 498,
+ 10,
+ 266,
+ 138,
+ 394,
+ 74,
+ 330,
+ 202,
+ 458,
+ 42,
+ 298,
+ 170,
+ 426,
+ 106,
+ 362,
+ 234,
+ 490,
+ 26,
+ 282,
+ 154,
+ 410,
+ 90,
+ 346,
+ 218,
+ 474,
+ 58,
+ 314,
+ 186,
+ 442,
+ 122,
+ 378,
+ 250,
+ 506,
+ 6,
+ 262,
+ 134,
+ 390,
+ 70,
+ 326,
+ 198,
+ 454,
+ 38,
+ 294,
+ 166,
+ 422,
+ 102,
+ 358,
+ 230,
+ 486,
+ 22,
+ 278,
+ 150,
+ 406,
+ 86,
+ 342,
+ 214,
+ 470,
+ 54,
+ 310,
+ 182,
+ 438,
+ 118,
+ 374,
+ 246,
+ 502,
+ 14,
+ 270,
+ 142,
+ 398,
+ 78,
+ 334,
+ 206,
+ 462,
+ 46,
+ 302,
+ 174,
+ 430,
+ 110,
+ 366,
+ 238,
+ 494,
+ 30,
+ 286,
+ 158,
+ 414,
+ 94,
+ 350,
+ 222,
+ 478,
+ 62,
+ 318,
+ 190,
+ 446,
+ 126,
+ 382,
+ 254,
+ 510,
+ 1,
+ 257,
+ 129,
+ 385,
+ 65,
+ 321,
+ 193,
+ 449,
+ 33,
+ 289,
+ 161,
+ 417,
+ 97,
+ 353,
+ 225,
+ 481,
+ 17,
+ 273,
+ 145,
+ 401,
+ 81,
+ 337,
+ 209,
+ 465,
+ 49,
+ 305,
+ 177,
+ 433,
+ 113,
+ 369,
+ 241,
+ 497,
+ 9,
+ 265,
+ 137,
+ 393,
+ 73,
+ 329,
+ 201,
+ 457,
+ 41,
+ 297,
+ 169,
+ 425,
+ 105,
+ 361,
+ 233,
+ 489,
+ 25,
+ 281,
+ 153,
+ 409,
+ 89,
+ 345,
+ 217,
+ 473,
+ 57,
+ 313,
+ 185,
+ 441,
+ 121,
+ 377,
+ 249,
+ 505,
+ 5,
+ 261,
+ 133,
+ 389,
+ 69,
+ 325,
+ 197,
+ 453,
+ 37,
+ 293,
+ 165,
+ 421,
+ 101,
+ 357,
+ 229,
+ 485,
+ 21,
+ 277,
+ 149,
+ 405,
+ 85,
+ 341,
+ 213,
+ 469,
+ 53,
+ 309,
+ 181,
+ 437,
+ 117,
+ 373,
+ 245,
+ 501,
+ 13,
+ 269,
+ 141,
+ 397,
+ 77,
+ 333,
+ 205,
+ 461,
+ 45,
+ 301,
+ 173,
+ 429,
+ 109,
+ 365,
+ 237,
+ 493,
+ 29,
+ 285,
+ 157,
+ 413,
+ 93,
+ 349,
+ 221,
+ 477,
+ 61,
+ 317,
+ 189,
+ 445,
+ 125,
+ 381,
+ 253,
+ 509,
+ 3,
+ 259,
+ 131,
+ 387,
+ 67,
+ 323,
+ 195,
+ 451,
+ 35,
+ 291,
+ 163,
+ 419,
+ 99,
+ 355,
+ 227,
+ 483,
+ 19,
+ 275,
+ 147,
+ 403,
+ 83,
+ 339,
+ 211,
+ 467,
+ 51,
+ 307,
+ 179,
+ 435,
+ 115,
+ 371,
+ 243,
+ 499,
+ 11,
+ 267,
+ 139,
+ 395,
+ 75,
+ 331,
+ 203,
+ 459,
+ 43,
+ 299,
+ 171,
+ 427,
+ 107,
+ 363,
+ 235,
+ 491,
+ 27,
+ 283,
+ 155,
+ 411,
+ 91,
+ 347,
+ 219,
+ 475,
+ 59,
+ 315,
+ 187,
+ 443,
+ 123,
+ 379,
+ 251,
+ 507,
+ 7,
+ 1031,
+ 519,
+ 1543,
+ 263,
+ 1287,
+ 775,
+ 1799,
+ 135,
+ 1159,
+ 647,
+ 1671,
+ 391,
+ 1415,
+ 903,
+ 1927,
+ 71,
+ 1095,
+ 583,
+ 1607,
+ 327,
+ 1351,
+ 839,
+ 1863,
+ 199,
+ 1223,
+ 711,
+ 1735,
+ 455,
+ 1479,
+ 967,
+ 1991,
+ 39,
+ 1063,
+ 551,
+ 1575,
+ 295,
+ 1319,
+ 807,
+ 1831,
+ 167,
+ 1191,
+ 679,
+ 1703,
+ 423,
+ 1447,
+ 935,
+ 1959,
+ 103,
+ 1127,
+ 615,
+ 1639,
+ 359,
+ 1383,
+ 871,
+ 1895,
+ 231,
+ 1255,
+ 743,
+ 1767,
+ 487,
+ 1511,
+ 999,
+ 2023,
+ 23,
+ 1047,
+ 535,
+ 1559,
+ 279,
+ 1303,
+ 791,
+ 1815,
+ 151,
+ 1175,
+ 663,
+ 1687,
+ 407,
+ 1431,
+ 919,
+ 1943,
+ 87,
+ 1111,
+ 599,
+ 1623,
+ 343,
+ 1367,
+ 855,
+ 1879,
+ 215,
+ 1239,
+ 727,
+ 1751,
+ 471,
+ 1495,
+ 983,
+ 2007,
+ 55,
+ 1079,
+ 567,
+ 1591,
+ 311,
+ 1335,
+ 823,
+ 1847,
+ 183,
+ 1207,
+ 695,
+ 1719,
+ 439,
+ 1463,
+ 951,
+ 1975,
+ 119,
+ 1143,
+ 631,
+ 1655,
+ 375,
+ 1399,
+ 887,
+ 1911,
+ 247,
+ 1271,
+ 759,
+ 1783,
+ 503,
+ 1527,
+ 1015,
+ 2039,
+ 15,
+ 1039,
+ 527,
+ 1551,
+ 271,
+ 1295,
+ 783,
+ 1807,
+ 143,
+ 1167,
+ 655,
+ 1679,
+ 399,
+ 1423,
+ 911,
+ 1935,
+ 79,
+ 1103,
+ 591,
+ 1615,
+ 335,
+ 1359,
+ 847,
+ 1871,
+ 207,
+ 1231,
+ 719,
+ 1743,
+ 463,
+ 1487,
+ 975,
+ 1999,
+ 47,
+ 1071,
+ 559,
+ 1583,
+ 303,
+ 1327,
+ 815,
+ 1839,
+ 175,
+ 1199,
+ 687,
+ 1711,
+ 431,
+ 1455,
+ 943,
+ 1967,
+ 111,
+ 1135,
+ 623,
+ 1647,
+ 367,
+ 1391,
+ 879,
+ 1903,
+ 239,
+ 1263,
+ 751,
+ 1775,
+ 495,
+ 1519,
+ 1007,
+ 2031,
+ 31,
+ 1055,
+ 543,
+ 1567,
+ 287,
+ 1311,
+ 799,
+ 1823,
+ 159,
+ 1183,
+ 671,
+ 1695,
+ 415,
+ 1439,
+ 927,
+ 1951,
+ 95,
+ 1119,
+ 607,
+ 1631,
+ 351,
+ 1375,
+ 863,
+ 1887,
+ 223,
+ 1247,
+ 735,
+ 1759,
+ 479,
+ 1503,
+ 991,
+ 2015,
+ 63,
+ 1087,
+ 575,
+ 1599,
+ 319,
+ 1343,
+ 831,
+ 1855,
+ 191,
+ 1215,
+ 703,
+ 1727,
+ 447,
+ 1471,
+ 959,
+ 1983,
+ 127,
+ 1151,
+ 639,
+ 1663,
+ 383,
+ 1407,
+ 895,
+ 1919,
+ 255,
+ 1279,
+ 767,
+ 1791,
+ 511,
+ 1535,
+ 1023,
+ 2047,
+}
+
+func storeStaticCommandHuffmanTree(storage_ix *uint, storage []byte) {
+ writeBits(56, 0x92624416307003, storage_ix, storage)
+ writeBits(3, 0x00000000, storage_ix, storage)
+}
+
+var kStaticDistanceCodeBits = [64]uint16{
+ 0,
+ 32,
+ 16,
+ 48,
+ 8,
+ 40,
+ 24,
+ 56,
+ 4,
+ 36,
+ 20,
+ 52,
+ 12,
+ 44,
+ 28,
+ 60,
+ 2,
+ 34,
+ 18,
+ 50,
+ 10,
+ 42,
+ 26,
+ 58,
+ 6,
+ 38,
+ 22,
+ 54,
+ 14,
+ 46,
+ 30,
+ 62,
+ 1,
+ 33,
+ 17,
+ 49,
+ 9,
+ 41,
+ 25,
+ 57,
+ 5,
+ 37,
+ 21,
+ 53,
+ 13,
+ 45,
+ 29,
+ 61,
+ 3,
+ 35,
+ 19,
+ 51,
+ 11,
+ 43,
+ 27,
+ 59,
+ 7,
+ 39,
+ 23,
+ 55,
+ 15,
+ 47,
+ 31,
+ 63,
+}
+
+func storeStaticDistanceHuffmanTree(storage_ix *uint, storage []byte) {
+ writeBits(28, 0x0369DC03, storage_ix, storage)
+}
diff --git a/vendor/github.com/andybalholm/brotli/fast_log.go b/vendor/github.com/andybalholm/brotli/fast_log.go
new file mode 100644
index 0000000..9d6607f
--- /dev/null
+++ b/vendor/github.com/andybalholm/brotli/fast_log.go
@@ -0,0 +1,290 @@
+package brotli
+
+import (
+ "math"
+ "math/bits"
+)
+
+/* Copyright 2013 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Utilities for fast computation of logarithms. */
+
+func log2FloorNonZero(n uint) uint32 {
+ return uint32(bits.Len(n)) - 1
+}
+
+/* A lookup table for small values of log2(int) to be used in entropy
+ computation.
+
+ ", ".join(["%.16ff" % x for x in [0.0]+[log2(x) for x in range(1, 256)]]) */
+var kLog2Table = []float32{
+ 0.0000000000000000,
+ 0.0000000000000000,
+ 1.0000000000000000,
+ 1.5849625007211563,
+ 2.0000000000000000,
+ 2.3219280948873622,
+ 2.5849625007211561,
+ 2.8073549220576042,
+ 3.0000000000000000,
+ 3.1699250014423126,
+ 3.3219280948873626,
+ 3.4594316186372978,
+ 3.5849625007211565,
+ 3.7004397181410922,
+ 3.8073549220576037,
+ 3.9068905956085187,
+ 4.0000000000000000,
+ 4.0874628412503400,
+ 4.1699250014423122,
+ 4.2479275134435852,
+ 4.3219280948873626,
+ 4.3923174227787607,
+ 4.4594316186372973,
+ 4.5235619560570131,
+ 4.5849625007211570,
+ 4.6438561897747244,
+ 4.7004397181410926,
+ 4.7548875021634691,
+ 4.8073549220576037,
+ 4.8579809951275728,
+ 4.9068905956085187,
+ 4.9541963103868758,
+ 5.0000000000000000,
+ 5.0443941193584534,
+ 5.0874628412503400,
+ 5.1292830169449664,
+ 5.1699250014423122,
+ 5.2094533656289501,
+ 5.2479275134435852,
+ 5.2854022188622487,
+ 5.3219280948873626,
+ 5.3575520046180838,
+ 5.3923174227787607,
+ 5.4262647547020979,
+ 5.4594316186372973,
+ 5.4918530963296748,
+ 5.5235619560570131,
+ 5.5545888516776376,
+ 5.5849625007211570,
+ 5.6147098441152083,
+ 5.6438561897747244,
+ 5.6724253419714961,
+ 5.7004397181410926,
+ 5.7279204545631996,
+ 5.7548875021634691,
+ 5.7813597135246599,
+ 5.8073549220576046,
+ 5.8328900141647422,
+ 5.8579809951275719,
+ 5.8826430493618416,
+ 5.9068905956085187,
+ 5.9307373375628867,
+ 5.9541963103868758,
+ 5.9772799234999168,
+ 6.0000000000000000,
+ 6.0223678130284544,
+ 6.0443941193584534,
+ 6.0660891904577721,
+ 6.0874628412503400,
+ 6.1085244567781700,
+ 6.1292830169449672,
+ 6.1497471195046822,
+ 6.1699250014423122,
+ 6.1898245588800176,
+ 6.2094533656289510,
+ 6.2288186904958804,
+ 6.2479275134435861,
+ 6.2667865406949019,
+ 6.2854022188622487,
+ 6.3037807481771031,
+ 6.3219280948873617,
+ 6.3398500028846252,
+ 6.3575520046180847,
+ 6.3750394313469254,
+ 6.3923174227787598,
+ 6.4093909361377026,
+ 6.4262647547020979,
+ 6.4429434958487288,
+ 6.4594316186372982,
+ 6.4757334309663976,
+ 6.4918530963296748,
+ 6.5077946401986964,
+ 6.5235619560570131,
+ 6.5391588111080319,
+ 6.5545888516776376,
+ 6.5698556083309478,
+ 6.5849625007211561,
+ 6.5999128421871278,
+ 6.6147098441152092,
+ 6.6293566200796095,
+ 6.6438561897747253,
+ 6.6582114827517955,
+ 6.6724253419714952,
+ 6.6865005271832185,
+ 6.7004397181410917,
+ 6.7142455176661224,
+ 6.7279204545631988,
+ 6.7414669864011465,
+ 6.7548875021634691,
+ 6.7681843247769260,
+ 6.7813597135246599,
+ 6.7944158663501062,
+ 6.8073549220576037,
+ 6.8201789624151887,
+ 6.8328900141647422,
+ 6.8454900509443757,
+ 6.8579809951275719,
+ 6.8703647195834048,
+ 6.8826430493618416,
+ 6.8948177633079437,
+ 6.9068905956085187,
+ 6.9188632372745955,
+ 6.9307373375628867,
+ 6.9425145053392399,
+ 6.9541963103868758,
+ 6.9657842846620879,
+ 6.9772799234999168,
+ 6.9886846867721664,
+ 7.0000000000000000,
+ 7.0112272554232540,
+ 7.0223678130284544,
+ 7.0334230015374501,
+ 7.0443941193584534,
+ 7.0552824355011898,
+ 7.0660891904577721,
+ 7.0768155970508317,
+ 7.0874628412503400,
+ 7.0980320829605272,
+ 7.1085244567781700,
+ 7.1189410727235076,
+ 7.1292830169449664,
+ 7.1395513523987937,
+ 7.1497471195046822,
+ 7.1598713367783891,
+ 7.1699250014423130,
+ 7.1799090900149345,
+ 7.1898245588800176,
+ 7.1996723448363644,
+ 7.2094533656289492,
+ 7.2191685204621621,
+ 7.2288186904958804,
+ 7.2384047393250794,
+ 7.2479275134435861,
+ 7.2573878426926521,
+ 7.2667865406949019,
+ 7.2761244052742384,
+ 7.2854022188622487,
+ 7.2946207488916270,
+ 7.3037807481771031,
+ 7.3128829552843557,
+ 7.3219280948873617,
+ 7.3309168781146177,
+ 7.3398500028846243,
+ 7.3487281542310781,
+ 7.3575520046180847,
+ 7.3663222142458151,
+ 7.3750394313469254,
+ 7.3837042924740528,
+ 7.3923174227787607,
+ 7.4008794362821844,
+ 7.4093909361377026,
+ 7.4178525148858991,
+ 7.4262647547020979,
+ 7.4346282276367255,
+ 7.4429434958487288,
+ 7.4512111118323299,
+ 7.4594316186372973,
+ 7.4676055500829976,
+ 7.4757334309663976,
+ 7.4838157772642564,
+ 7.4918530963296748,
+ 7.4998458870832057,
+ 7.5077946401986964,
+ 7.5156998382840436,
+ 7.5235619560570131,
+ 7.5313814605163119,
+ 7.5391588111080319,
+ 7.5468944598876373,
+ 7.5545888516776376,
+ 7.5622424242210728,
+ 7.5698556083309478,
+ 7.5774288280357487,
+ 7.5849625007211561,
+ 7.5924570372680806,
+ 7.5999128421871278,
+ 7.6073303137496113,
+ 7.6147098441152075,
+ 7.6220518194563764,
+ 7.6293566200796095,
+ 7.6366246205436488,
+ 7.6438561897747244,
+ 7.6510516911789290,
+ 7.6582114827517955,
+ 7.6653359171851765,
+ 7.6724253419714952,
+ 7.6794800995054464,
+ 7.6865005271832185,
+ 7.6934869574993252,
+ 7.7004397181410926,
+ 7.7073591320808825,
+ 7.7142455176661224,
+ 7.7210991887071856,
+ 7.7279204545631996,
+ 7.7347096202258392,
+ 7.7414669864011465,
+ 7.7481928495894596,
+ 7.7548875021634691,
+ 7.7615512324444795,
+ 7.7681843247769260,
+ 7.7747870596011737,
+ 7.7813597135246608,
+ 7.7879025593914317,
+ 7.7944158663501062,
+ 7.8008998999203047,
+ 7.8073549220576037,
+ 7.8137811912170374,
+ 7.8201789624151887,
+ 7.8265484872909159,
+ 7.8328900141647422,
+ 7.8392037880969445,
+ 7.8454900509443757,
+ 7.8517490414160571,
+ 7.8579809951275719,
+ 7.8641861446542798,
+ 7.8703647195834048,
+ 7.8765169465650002,
+ 7.8826430493618425,
+ 7.8887432488982601,
+ 7.8948177633079446,
+ 7.9008668079807496,
+ 7.9068905956085187,
+ 7.9128893362299619,
+ 7.9188632372745955,
+ 7.9248125036057813,
+ 7.9307373375628867,
+ 7.9366379390025719,
+ 7.9425145053392399,
+ 7.9483672315846778,
+ 7.9541963103868758,
+ 7.9600019320680806,
+ 7.9657842846620870,
+ 7.9715435539507720,
+ 7.9772799234999168,
+ 7.9829935746943104,
+ 7.9886846867721664,
+ 7.9943534368588578,
+}
+
+/* Faster logarithm for small integers, with the property of log2(0) == 0. */
+func fastLog2(v uint) float64 {
+ if v < uint(len(kLog2Table)) {
+ return float64(kLog2Table[v])
+ }
+
+ return math.Log2(float64(v))
+}
diff --git a/vendor/github.com/andybalholm/brotli/find_match_length.go b/vendor/github.com/andybalholm/brotli/find_match_length.go
new file mode 100644
index 0000000..09d2ae6
--- /dev/null
+++ b/vendor/github.com/andybalholm/brotli/find_match_length.go
@@ -0,0 +1,45 @@
+package brotli
+
+import (
+ "encoding/binary"
+ "math/bits"
+ "runtime"
+)
+
+/* Copyright 2010 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Function to find maximal matching prefixes of strings. */
+func findMatchLengthWithLimit(s1 []byte, s2 []byte, limit uint) uint {
+ var matched uint = 0
+ _, _ = s1[limit-1], s2[limit-1] // bounds check
+ switch runtime.GOARCH {
+ case "amd64":
+ // Compare 8 bytes at at time.
+ for matched+8 <= limit {
+ w1 := binary.LittleEndian.Uint64(s1[matched:])
+ w2 := binary.LittleEndian.Uint64(s2[matched:])
+ if w1 != w2 {
+ return matched + uint(bits.TrailingZeros64(w1^w2)>>3)
+ }
+ matched += 8
+ }
+ case "386":
+ // Compare 4 bytes at at time.
+ for matched+4 <= limit {
+ w1 := binary.LittleEndian.Uint32(s1[matched:])
+ w2 := binary.LittleEndian.Uint32(s2[matched:])
+ if w1 != w2 {
+ return matched + uint(bits.TrailingZeros32(w1^w2)>>3)
+ }
+ matched += 4
+ }
+ }
+ for matched < limit && s1[matched] == s2[matched] {
+ matched++
+ }
+ return matched
+}
diff --git a/vendor/github.com/andybalholm/brotli/h10.go b/vendor/github.com/andybalholm/brotli/h10.go
new file mode 100644
index 0000000..5662fbb
--- /dev/null
+++ b/vendor/github.com/andybalholm/brotli/h10.go
@@ -0,0 +1,287 @@
+package brotli
+
+import "encoding/binary"
+
+/* Copyright 2016 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+func (*h10) HashTypeLength() uint {
+ return 4
+}
+
+func (*h10) StoreLookahead() uint {
+ return 128
+}
+
+func hashBytesH10(data []byte) uint32 {
+ var h uint32 = binary.LittleEndian.Uint32(data) * kHashMul32
+
+ /* The higher bits contain more mixture from the multiplication,
+ so we take our results from there. */
+ return h >> (32 - 17)
+}
+
+/* A (forgetful) hash table where each hash bucket contains a binary tree of
+ sequences whose first 4 bytes share the same hash code.
+ Each sequence is 128 long and is identified by its starting
+ position in the input data. The binary tree is sorted by the lexicographic
+ order of the sequences, and it is also a max-heap with respect to the
+ starting positions. */
+type h10 struct {
+ hasherCommon
+ window_mask_ uint
+ buckets_ [1 << 17]uint32
+ invalid_pos_ uint32
+ forest []uint32
+}
+
+func (h *h10) Initialize(params *encoderParams) {
+ h.window_mask_ = (1 << params.lgwin) - 1
+ h.invalid_pos_ = uint32(0 - h.window_mask_)
+ var num_nodes uint = uint(1) << params.lgwin
+ h.forest = make([]uint32, 2*num_nodes)
+}
+
+func (h *h10) Prepare(one_shot bool, input_size uint, data []byte) {
+ var invalid_pos uint32 = h.invalid_pos_
+ var i uint32
+ for i = 0; i < 1<<17; i++ {
+ h.buckets_[i] = invalid_pos
+ }
+}
+
+func leftChildIndexH10(self *h10, pos uint) uint {
+ return 2 * (pos & self.window_mask_)
+}
+
+func rightChildIndexH10(self *h10, pos uint) uint {
+ return 2*(pos&self.window_mask_) + 1
+}
+
+/* Stores the hash of the next 4 bytes and in a single tree-traversal, the
+ hash bucket's binary tree is searched for matches and is re-rooted at the
+ current position.
+
+ If less than 128 data is available, the hash bucket of the
+ current position is searched for matches, but the state of the hash table
+ is not changed, since we can not know the final sorting order of the
+ current (incomplete) sequence.
+
+ This function must be called with increasing cur_ix positions. */
+func storeAndFindMatchesH10(self *h10, data []byte, cur_ix uint, ring_buffer_mask uint, max_length uint, max_backward uint, best_len *uint, matches []backwardMatch) []backwardMatch {
+ var cur_ix_masked uint = cur_ix & ring_buffer_mask
+ var max_comp_len uint = brotli_min_size_t(max_length, 128)
+ var should_reroot_tree bool = (max_length >= 128)
+ var key uint32 = hashBytesH10(data[cur_ix_masked:])
+ var forest []uint32 = self.forest
+ var prev_ix uint = uint(self.buckets_[key])
+ var node_left uint = leftChildIndexH10(self, cur_ix)
+ var node_right uint = rightChildIndexH10(self, cur_ix)
+ var best_len_left uint = 0
+ var best_len_right uint = 0
+ var depth_remaining uint
+ /* The forest index of the rightmost node of the left subtree of the new
+ root, updated as we traverse and re-root the tree of the hash bucket. */
+
+ /* The forest index of the leftmost node of the right subtree of the new
+ root, updated as we traverse and re-root the tree of the hash bucket. */
+
+ /* The match length of the rightmost node of the left subtree of the new
+ root, updated as we traverse and re-root the tree of the hash bucket. */
+
+ /* The match length of the leftmost node of the right subtree of the new
+ root, updated as we traverse and re-root the tree of the hash bucket. */
+ if should_reroot_tree {
+ self.buckets_[key] = uint32(cur_ix)
+ }
+
+ for depth_remaining = 64; ; depth_remaining-- {
+ var backward uint = cur_ix - prev_ix
+ var prev_ix_masked uint = prev_ix & ring_buffer_mask
+ if backward == 0 || backward > max_backward || depth_remaining == 0 {
+ if should_reroot_tree {
+ forest[node_left] = self.invalid_pos_
+ forest[node_right] = self.invalid_pos_
+ }
+
+ break
+ }
+ {
+ var cur_len uint = brotli_min_size_t(best_len_left, best_len_right)
+ var len uint
+ assert(cur_len <= 128)
+ len = cur_len + findMatchLengthWithLimit(data[cur_ix_masked+cur_len:], data[prev_ix_masked+cur_len:], max_length-cur_len)
+ if matches != nil && len > *best_len {
+ *best_len = uint(len)
+ initBackwardMatch(&matches[0], backward, uint(len))
+ matches = matches[1:]
+ }
+
+ if len >= max_comp_len {
+ if should_reroot_tree {
+ forest[node_left] = forest[leftChildIndexH10(self, prev_ix)]
+ forest[node_right] = forest[rightChildIndexH10(self, prev_ix)]
+ }
+
+ break
+ }
+
+ if data[cur_ix_masked+len] > data[prev_ix_masked+len] {
+ best_len_left = uint(len)
+ if should_reroot_tree {
+ forest[node_left] = uint32(prev_ix)
+ }
+
+ node_left = rightChildIndexH10(self, prev_ix)
+ prev_ix = uint(forest[node_left])
+ } else {
+ best_len_right = uint(len)
+ if should_reroot_tree {
+ forest[node_right] = uint32(prev_ix)
+ }
+
+ node_right = leftChildIndexH10(self, prev_ix)
+ prev_ix = uint(forest[node_right])
+ }
+ }
+ }
+
+ return matches
+}
+
+/* Finds all backward matches of &data[cur_ix & ring_buffer_mask] up to the
+ length of max_length and stores the position cur_ix in the hash table.
+
+ Sets *num_matches to the number of matches found, and stores the found
+ matches in matches[0] to matches[*num_matches - 1]. The matches will be
+ sorted by strictly increasing length and (non-strictly) increasing
+ distance. */
+func findAllMatchesH10(handle *h10, dictionary *encoderDictionary, data []byte, ring_buffer_mask uint, cur_ix uint, max_length uint, max_backward uint, gap uint, params *encoderParams, matches []backwardMatch) uint {
+ var orig_matches []backwardMatch = matches
+ var cur_ix_masked uint = cur_ix & ring_buffer_mask
+ var best_len uint = 1
+ var short_match_max_backward uint
+ if params.quality != hqZopflificationQuality {
+ short_match_max_backward = 16
+ } else {
+ short_match_max_backward = 64
+ }
+ var stop uint = cur_ix - short_match_max_backward
+ var dict_matches [maxStaticDictionaryMatchLen + 1]uint32
+ var i uint
+ if cur_ix < short_match_max_backward {
+ stop = 0
+ }
+ for i = cur_ix - 1; i > stop && best_len <= 2; i-- {
+ var prev_ix uint = i
+ var backward uint = cur_ix - prev_ix
+ if backward > max_backward {
+ break
+ }
+
+ prev_ix &= ring_buffer_mask
+ if data[cur_ix_masked] != data[prev_ix] || data[cur_ix_masked+1] != data[prev_ix+1] {
+ continue
+ }
+ {
+ var len uint = findMatchLengthWithLimit(data[prev_ix:], data[cur_ix_masked:], max_length)
+ if len > best_len {
+ best_len = uint(len)
+ initBackwardMatch(&matches[0], backward, uint(len))
+ matches = matches[1:]
+ }
+ }
+ }
+
+ if best_len < max_length {
+ matches = storeAndFindMatchesH10(handle, data, cur_ix, ring_buffer_mask, max_length, max_backward, &best_len, matches)
+ }
+
+ for i = 0; i <= maxStaticDictionaryMatchLen; i++ {
+ dict_matches[i] = kInvalidMatch
+ }
+ {
+ var minlen uint = brotli_max_size_t(4, best_len+1)
+ if findAllStaticDictionaryMatches(dictionary, data[cur_ix_masked:], minlen, max_length, dict_matches[0:]) {
+ var maxlen uint = brotli_min_size_t(maxStaticDictionaryMatchLen, max_length)
+ var l uint
+ for l = minlen; l <= maxlen; l++ {
+ var dict_id uint32 = dict_matches[l]
+ if dict_id < kInvalidMatch {
+ var distance uint = max_backward + gap + uint(dict_id>>5) + 1
+ if distance <= params.dist.max_distance {
+ initDictionaryBackwardMatch(&matches[0], distance, l, uint(dict_id&31))
+ matches = matches[1:]
+ }
+ }
+ }
+ }
+ }
+
+ return uint(-cap(matches) + cap(orig_matches))
+}
+
+/* Stores the hash of the next 4 bytes and re-roots the binary tree at the
+ current sequence, without returning any matches.
+ REQUIRES: ix + 128 <= end-of-current-block */
+func (h *h10) Store(data []byte, mask uint, ix uint) {
+ var max_backward uint = h.window_mask_ - windowGap + 1
+ /* Maximum distance is window size - 16, see section 9.1. of the spec. */
+ storeAndFindMatchesH10(h, data, ix, mask, 128, max_backward, nil, nil)
+}
+
+func (h *h10) StoreRange(data []byte, mask uint, ix_start uint, ix_end uint) {
+ var i uint = ix_start
+ var j uint = ix_start
+ if ix_start+63 <= ix_end {
+ i = ix_end - 63
+ }
+
+ if ix_start+512 <= i {
+ for ; j < i; j += 8 {
+ h.Store(data, mask, j)
+ }
+ }
+
+ for ; i < ix_end; i++ {
+ h.Store(data, mask, i)
+ }
+}
+
+func (h *h10) StitchToPreviousBlock(num_bytes uint, position uint, ringbuffer []byte, ringbuffer_mask uint) {
+ if num_bytes >= h.HashTypeLength()-1 && position >= 128 {
+ var i_start uint = position - 128 + 1
+ var i_end uint = brotli_min_size_t(position, i_start+num_bytes)
+ /* Store the last `128 - 1` positions in the hasher.
+ These could not be calculated before, since they require knowledge
+ of both the previous and the current block. */
+
+ var i uint
+ for i = i_start; i < i_end; i++ {
+ /* Maximum distance is window size - 16, see section 9.1. of the spec.
+ Furthermore, we have to make sure that we don't look further back
+ from the start of the next block than the window size, otherwise we
+ could access already overwritten areas of the ring-buffer. */
+ var max_backward uint = h.window_mask_ - brotli_max_size_t(windowGap-1, position-i)
+
+ /* We know that i + 128 <= position + num_bytes, i.e. the
+ end of the current block and that we have at least
+ 128 tail in the ring-buffer. */
+ storeAndFindMatchesH10(h, ringbuffer, i, ringbuffer_mask, 128, max_backward, nil, nil)
+ }
+ }
+}
+
+/* MAX_NUM_MATCHES == 64 + MAX_TREE_SEARCH_DEPTH */
+const maxNumMatchesH10 = 128
+
+func (*h10) FindLongestMatch(dictionary *encoderDictionary, data []byte, ring_buffer_mask uint, distance_cache []int, cur_ix uint, max_length uint, max_backward uint, gap uint, max_distance uint, out *hasherSearchResult) {
+ panic("unimplemented")
+}
+
+func (*h10) PrepareDistanceCache(distance_cache []int) {
+ panic("unimplemented")
+}
diff --git a/vendor/github.com/andybalholm/brotli/h5.go b/vendor/github.com/andybalholm/brotli/h5.go
new file mode 100644
index 0000000..f391b73
--- /dev/null
+++ b/vendor/github.com/andybalholm/brotli/h5.go
@@ -0,0 +1,214 @@
+package brotli
+
+import "encoding/binary"
+
+/* Copyright 2010 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* A (forgetful) hash table to the data seen by the compressor, to
+ help create backward references to previous data.
+
+ This is a hash map of fixed size (bucket_size_) to a ring buffer of
+ fixed size (block_size_). The ring buffer contains the last block_size_
+ index positions of the given hash key in the compressed data. */
+func (*h5) HashTypeLength() uint {
+ return 4
+}
+
+func (*h5) StoreLookahead() uint {
+ return 4
+}
+
+/* HashBytes is the function that chooses the bucket to place the address in. */
+func hashBytesH5(data []byte, shift int) uint32 {
+ var h uint32 = binary.LittleEndian.Uint32(data) * kHashMul32
+
+ /* The higher bits contain more mixture from the multiplication,
+ so we take our results from there. */
+ return uint32(h >> uint(shift))
+}
+
+type h5 struct {
+ hasherCommon
+ bucket_size_ uint
+ block_size_ uint
+ hash_shift_ int
+ block_mask_ uint32
+ num []uint16
+ buckets []uint32
+}
+
+func (h *h5) Initialize(params *encoderParams) {
+ h.hash_shift_ = 32 - h.params.bucket_bits
+ h.bucket_size_ = uint(1) << uint(h.params.bucket_bits)
+ h.block_size_ = uint(1) << uint(h.params.block_bits)
+ h.block_mask_ = uint32(h.block_size_ - 1)
+ h.num = make([]uint16, h.bucket_size_)
+ h.buckets = make([]uint32, h.block_size_*h.bucket_size_)
+}
+
+func (h *h5) Prepare(one_shot bool, input_size uint, data []byte) {
+ var num []uint16 = h.num
+ var partial_prepare_threshold uint = h.bucket_size_ >> 6
+ /* Partial preparation is 100 times slower (per socket). */
+ if one_shot && input_size <= partial_prepare_threshold {
+ var i uint
+ for i = 0; i < input_size; i++ {
+ var key uint32 = hashBytesH5(data[i:], h.hash_shift_)
+ num[key] = 0
+ }
+ } else {
+ for i := 0; i < int(h.bucket_size_); i++ {
+ num[i] = 0
+ }
+ }
+}
+
+/* Look at 4 bytes at &data[ix & mask].
+ Compute a hash from these, and store the value of ix at that position. */
+func (h *h5) Store(data []byte, mask uint, ix uint) {
+ var num []uint16 = h.num
+ var key uint32 = hashBytesH5(data[ix&mask:], h.hash_shift_)
+ var minor_ix uint = uint(num[key]) & uint(h.block_mask_)
+ var offset uint = minor_ix + uint(key<= h.HashTypeLength()-1 && position >= 3 {
+ /* Prepare the hashes for three last bytes of the last write.
+ These could not be calculated before, since they require knowledge
+ of both the previous and the current block. */
+ h.Store(ringbuffer, ringbuffer_mask, position-3)
+ h.Store(ringbuffer, ringbuffer_mask, position-2)
+ h.Store(ringbuffer, ringbuffer_mask, position-1)
+ }
+}
+
+func (h *h5) PrepareDistanceCache(distance_cache []int) {
+ prepareDistanceCache(distance_cache, h.params.num_last_distances_to_check)
+}
+
+/* Find a longest backward match of &data[cur_ix] up to the length of
+ max_length and stores the position cur_ix in the hash table.
+
+ REQUIRES: PrepareDistanceCacheH5 must be invoked for current distance cache
+ values; if this method is invoked repeatedly with the same distance
+ cache values, it is enough to invoke PrepareDistanceCacheH5 once.
+
+ Does not look for matches longer than max_length.
+ Does not look for matches further away than max_backward.
+ Writes the best match into |out|.
+ |out|->score is updated only if a better match is found. */
+func (h *h5) FindLongestMatch(dictionary *encoderDictionary, data []byte, ring_buffer_mask uint, distance_cache []int, cur_ix uint, max_length uint, max_backward uint, gap uint, max_distance uint, out *hasherSearchResult) {
+ var num []uint16 = h.num
+ var buckets []uint32 = h.buckets
+ var cur_ix_masked uint = cur_ix & ring_buffer_mask
+ var min_score uint = out.score
+ var best_score uint = out.score
+ var best_len uint = out.len
+ var i uint
+ var bucket []uint32
+ /* Don't accept a short copy from far away. */
+ out.len = 0
+
+ out.len_code_delta = 0
+
+ /* Try last distance first. */
+ for i = 0; i < uint(h.params.num_last_distances_to_check); i++ {
+ var backward uint = uint(distance_cache[i])
+ var prev_ix uint = uint(cur_ix - backward)
+ if prev_ix >= cur_ix {
+ continue
+ }
+
+ if backward > max_backward {
+ continue
+ }
+
+ prev_ix &= ring_buffer_mask
+
+ if cur_ix_masked+best_len > ring_buffer_mask || prev_ix+best_len > ring_buffer_mask || data[cur_ix_masked+best_len] != data[prev_ix+best_len] {
+ continue
+ }
+ {
+ var len uint = findMatchLengthWithLimit(data[prev_ix:], data[cur_ix_masked:], max_length)
+ if len >= 3 || (len == 2 && i < 2) {
+ /* Comparing for >= 2 does not change the semantics, but just saves for
+ a few unnecessary binary logarithms in backward reference score,
+ since we are not interested in such short matches. */
+ var score uint = backwardReferenceScoreUsingLastDistance(uint(len))
+ if best_score < score {
+ if i != 0 {
+ score -= backwardReferencePenaltyUsingLastDistance(i)
+ }
+ if best_score < score {
+ best_score = score
+ best_len = uint(len)
+ out.len = best_len
+ out.distance = backward
+ out.score = best_score
+ }
+ }
+ }
+ }
+ }
+ {
+ var key uint32 = hashBytesH5(data[cur_ix_masked:], h.hash_shift_)
+ bucket = buckets[key< h.block_size_ {
+ down = uint(num[key]) - h.block_size_
+ } else {
+ down = 0
+ }
+ for i = uint(num[key]); i > down; {
+ var prev_ix uint
+ i--
+ prev_ix = uint(bucket[uint32(i)&h.block_mask_])
+ var backward uint = cur_ix - prev_ix
+ if backward > max_backward {
+ break
+ }
+
+ prev_ix &= ring_buffer_mask
+ if cur_ix_masked+best_len > ring_buffer_mask || prev_ix+best_len > ring_buffer_mask || data[cur_ix_masked+best_len] != data[prev_ix+best_len] {
+ continue
+ }
+ {
+ var len uint = findMatchLengthWithLimit(data[prev_ix:], data[cur_ix_masked:], max_length)
+ if len >= 4 {
+ /* Comparing for >= 3 does not change the semantics, but just saves
+ for a few unnecessary binary logarithms in backward reference
+ score, since we are not interested in such short matches. */
+ var score uint = backwardReferenceScore(uint(len), backward)
+ if best_score < score {
+ best_score = score
+ best_len = uint(len)
+ out.len = best_len
+ out.distance = backward
+ out.score = best_score
+ }
+ }
+ }
+ }
+
+ bucket[uint32(num[key])&h.block_mask_] = uint32(cur_ix)
+ num[key]++
+ }
+
+ if min_score == out.score {
+ searchInStaticDictionary(dictionary, h, data[cur_ix_masked:], max_length, max_backward+gap, max_distance, out, false)
+ }
+}
diff --git a/vendor/github.com/andybalholm/brotli/h6.go b/vendor/github.com/andybalholm/brotli/h6.go
new file mode 100644
index 0000000..80bb224
--- /dev/null
+++ b/vendor/github.com/andybalholm/brotli/h6.go
@@ -0,0 +1,216 @@
+package brotli
+
+import "encoding/binary"
+
+/* Copyright 2010 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* A (forgetful) hash table to the data seen by the compressor, to
+ help create backward references to previous data.
+
+ This is a hash map of fixed size (bucket_size_) to a ring buffer of
+ fixed size (block_size_). The ring buffer contains the last block_size_
+ index positions of the given hash key in the compressed data. */
+func (*h6) HashTypeLength() uint {
+ return 8
+}
+
+func (*h6) StoreLookahead() uint {
+ return 8
+}
+
+/* HashBytes is the function that chooses the bucket to place the address in. */
+func hashBytesH6(data []byte, mask uint64, shift int) uint32 {
+ var h uint64 = (binary.LittleEndian.Uint64(data) & mask) * kHashMul64Long
+
+ /* The higher bits contain more mixture from the multiplication,
+ so we take our results from there. */
+ return uint32(h >> uint(shift))
+}
+
+type h6 struct {
+ hasherCommon
+ bucket_size_ uint
+ block_size_ uint
+ hash_shift_ int
+ hash_mask_ uint64
+ block_mask_ uint32
+ num []uint16
+ buckets []uint32
+}
+
+func (h *h6) Initialize(params *encoderParams) {
+ h.hash_shift_ = 64 - h.params.bucket_bits
+ h.hash_mask_ = (^(uint64(0))) >> uint(64-8*h.params.hash_len)
+ h.bucket_size_ = uint(1) << uint(h.params.bucket_bits)
+ h.block_size_ = uint(1) << uint(h.params.block_bits)
+ h.block_mask_ = uint32(h.block_size_ - 1)
+ h.num = make([]uint16, h.bucket_size_)
+ h.buckets = make([]uint32, h.block_size_*h.bucket_size_)
+}
+
+func (h *h6) Prepare(one_shot bool, input_size uint, data []byte) {
+ var num []uint16 = h.num
+ var partial_prepare_threshold uint = h.bucket_size_ >> 6
+ /* Partial preparation is 100 times slower (per socket). */
+ if one_shot && input_size <= partial_prepare_threshold {
+ var i uint
+ for i = 0; i < input_size; i++ {
+ var key uint32 = hashBytesH6(data[i:], h.hash_mask_, h.hash_shift_)
+ num[key] = 0
+ }
+ } else {
+ for i := 0; i < int(h.bucket_size_); i++ {
+ num[i] = 0
+ }
+ }
+}
+
+/* Look at 4 bytes at &data[ix & mask].
+ Compute a hash from these, and store the value of ix at that position. */
+func (h *h6) Store(data []byte, mask uint, ix uint) {
+ var num []uint16 = h.num
+ var key uint32 = hashBytesH6(data[ix&mask:], h.hash_mask_, h.hash_shift_)
+ var minor_ix uint = uint(num[key]) & uint(h.block_mask_)
+ var offset uint = minor_ix + uint(key<= h.HashTypeLength()-1 && position >= 3 {
+ /* Prepare the hashes for three last bytes of the last write.
+ These could not be calculated before, since they require knowledge
+ of both the previous and the current block. */
+ h.Store(ringbuffer, ringbuffer_mask, position-3)
+ h.Store(ringbuffer, ringbuffer_mask, position-2)
+ h.Store(ringbuffer, ringbuffer_mask, position-1)
+ }
+}
+
+func (h *h6) PrepareDistanceCache(distance_cache []int) {
+ prepareDistanceCache(distance_cache, h.params.num_last_distances_to_check)
+}
+
+/* Find a longest backward match of &data[cur_ix] up to the length of
+ max_length and stores the position cur_ix in the hash table.
+
+ REQUIRES: PrepareDistanceCacheH6 must be invoked for current distance cache
+ values; if this method is invoked repeatedly with the same distance
+ cache values, it is enough to invoke PrepareDistanceCacheH6 once.
+
+ Does not look for matches longer than max_length.
+ Does not look for matches further away than max_backward.
+ Writes the best match into |out|.
+ |out|->score is updated only if a better match is found. */
+func (h *h6) FindLongestMatch(dictionary *encoderDictionary, data []byte, ring_buffer_mask uint, distance_cache []int, cur_ix uint, max_length uint, max_backward uint, gap uint, max_distance uint, out *hasherSearchResult) {
+ var num []uint16 = h.num
+ var buckets []uint32 = h.buckets
+ var cur_ix_masked uint = cur_ix & ring_buffer_mask
+ var min_score uint = out.score
+ var best_score uint = out.score
+ var best_len uint = out.len
+ var i uint
+ var bucket []uint32
+ /* Don't accept a short copy from far away. */
+ out.len = 0
+
+ out.len_code_delta = 0
+
+ /* Try last distance first. */
+ for i = 0; i < uint(h.params.num_last_distances_to_check); i++ {
+ var backward uint = uint(distance_cache[i])
+ var prev_ix uint = uint(cur_ix - backward)
+ if prev_ix >= cur_ix {
+ continue
+ }
+
+ if backward > max_backward {
+ continue
+ }
+
+ prev_ix &= ring_buffer_mask
+
+ if cur_ix_masked+best_len > ring_buffer_mask || prev_ix+best_len > ring_buffer_mask || data[cur_ix_masked+best_len] != data[prev_ix+best_len] {
+ continue
+ }
+ {
+ var len uint = findMatchLengthWithLimit(data[prev_ix:], data[cur_ix_masked:], max_length)
+ if len >= 3 || (len == 2 && i < 2) {
+ /* Comparing for >= 2 does not change the semantics, but just saves for
+ a few unnecessary binary logarithms in backward reference score,
+ since we are not interested in such short matches. */
+ var score uint = backwardReferenceScoreUsingLastDistance(uint(len))
+ if best_score < score {
+ if i != 0 {
+ score -= backwardReferencePenaltyUsingLastDistance(i)
+ }
+ if best_score < score {
+ best_score = score
+ best_len = uint(len)
+ out.len = best_len
+ out.distance = backward
+ out.score = best_score
+ }
+ }
+ }
+ }
+ }
+ {
+ var key uint32 = hashBytesH6(data[cur_ix_masked:], h.hash_mask_, h.hash_shift_)
+ bucket = buckets[key< h.block_size_ {
+ down = uint(num[key]) - h.block_size_
+ } else {
+ down = 0
+ }
+ for i = uint(num[key]); i > down; {
+ var prev_ix uint
+ i--
+ prev_ix = uint(bucket[uint32(i)&h.block_mask_])
+ var backward uint = cur_ix - prev_ix
+ if backward > max_backward {
+ break
+ }
+
+ prev_ix &= ring_buffer_mask
+ if cur_ix_masked+best_len > ring_buffer_mask || prev_ix+best_len > ring_buffer_mask || data[cur_ix_masked+best_len] != data[prev_ix+best_len] {
+ continue
+ }
+ {
+ var len uint = findMatchLengthWithLimit(data[prev_ix:], data[cur_ix_masked:], max_length)
+ if len >= 4 {
+ /* Comparing for >= 3 does not change the semantics, but just saves
+ for a few unnecessary binary logarithms in backward reference
+ score, since we are not interested in such short matches. */
+ var score uint = backwardReferenceScore(uint(len), backward)
+ if best_score < score {
+ best_score = score
+ best_len = uint(len)
+ out.len = best_len
+ out.distance = backward
+ out.score = best_score
+ }
+ }
+ }
+ }
+
+ bucket[uint32(num[key])&h.block_mask_] = uint32(cur_ix)
+ num[key]++
+ }
+
+ if min_score == out.score {
+ searchInStaticDictionary(dictionary, h, data[cur_ix_masked:], max_length, max_backward+gap, max_distance, out, false)
+ }
+}
diff --git a/vendor/github.com/andybalholm/brotli/hash.go b/vendor/github.com/andybalholm/brotli/hash.go
new file mode 100644
index 0000000..00f812e
--- /dev/null
+++ b/vendor/github.com/andybalholm/brotli/hash.go
@@ -0,0 +1,342 @@
+package brotli
+
+import (
+ "encoding/binary"
+ "fmt"
+)
+
+type hasherCommon struct {
+ params hasherParams
+ is_prepared_ bool
+ dict_num_lookups uint
+ dict_num_matches uint
+}
+
+func (h *hasherCommon) Common() *hasherCommon {
+ return h
+}
+
+type hasherHandle interface {
+ Common() *hasherCommon
+ Initialize(params *encoderParams)
+ Prepare(one_shot bool, input_size uint, data []byte)
+ StitchToPreviousBlock(num_bytes uint, position uint, ringbuffer []byte, ringbuffer_mask uint)
+ HashTypeLength() uint
+ StoreLookahead() uint
+ PrepareDistanceCache(distance_cache []int)
+ FindLongestMatch(dictionary *encoderDictionary, data []byte, ring_buffer_mask uint, distance_cache []int, cur_ix uint, max_length uint, max_backward uint, gap uint, max_distance uint, out *hasherSearchResult)
+ StoreRange(data []byte, mask uint, ix_start uint, ix_end uint)
+ Store(data []byte, mask uint, ix uint)
+}
+
+const kCutoffTransformsCount uint32 = 10
+
+/* 0, 12, 27, 23, 42, 63, 56, 48, 59, 64 */
+/* 0+0, 4+8, 8+19, 12+11, 16+26, 20+43, 24+32, 28+20, 32+27, 36+28 */
+const kCutoffTransforms uint64 = 0x071B520ADA2D3200
+
+type hasherSearchResult struct {
+ len uint
+ distance uint
+ score uint
+ len_code_delta int
+}
+
+/* kHashMul32 multiplier has these properties:
+ * The multiplier must be odd. Otherwise we may lose the highest bit.
+ * No long streaks of ones or zeros.
+ * There is no effort to ensure that it is a prime, the oddity is enough
+ for this use.
+ * The number has been tuned heuristically against compression benchmarks. */
+const kHashMul32 uint32 = 0x1E35A7BD
+
+const kHashMul64 uint64 = 0x1E35A7BD1E35A7BD
+
+const kHashMul64Long uint64 = 0x1FE35A7BD3579BD3
+
+func hash14(data []byte) uint32 {
+ var h uint32 = binary.LittleEndian.Uint32(data) * kHashMul32
+
+ /* The higher bits contain more mixture from the multiplication,
+ so we take our results from there. */
+ return h >> (32 - 14)
+}
+
+func prepareDistanceCache(distance_cache []int, num_distances int) {
+ if num_distances > 4 {
+ var last_distance int = distance_cache[0]
+ distance_cache[4] = last_distance - 1
+ distance_cache[5] = last_distance + 1
+ distance_cache[6] = last_distance - 2
+ distance_cache[7] = last_distance + 2
+ distance_cache[8] = last_distance - 3
+ distance_cache[9] = last_distance + 3
+ if num_distances > 10 {
+ var next_last_distance int = distance_cache[1]
+ distance_cache[10] = next_last_distance - 1
+ distance_cache[11] = next_last_distance + 1
+ distance_cache[12] = next_last_distance - 2
+ distance_cache[13] = next_last_distance + 2
+ distance_cache[14] = next_last_distance - 3
+ distance_cache[15] = next_last_distance + 3
+ }
+ }
+}
+
+const literalByteScore = 135
+
+const distanceBitPenalty = 30
+
+/* Score must be positive after applying maximal penalty. */
+const scoreBase = (distanceBitPenalty * 8 * 8)
+
+/* Usually, we always choose the longest backward reference. This function
+ allows for the exception of that rule.
+
+ If we choose a backward reference that is further away, it will
+ usually be coded with more bits. We approximate this by assuming
+ log2(distance). If the distance can be expressed in terms of the
+ last four distances, we use some heuristic constants to estimate
+ the bits cost. For the first up to four literals we use the bit
+ cost of the literals from the literal cost model, after that we
+ use the average bit cost of the cost model.
+
+ This function is used to sometimes discard a longer backward reference
+ when it is not much longer and the bit cost for encoding it is more
+ than the saved literals.
+
+ backward_reference_offset MUST be positive. */
+func backwardReferenceScore(copy_length uint, backward_reference_offset uint) uint {
+ return scoreBase + literalByteScore*uint(copy_length) - distanceBitPenalty*uint(log2FloorNonZero(backward_reference_offset))
+}
+
+func backwardReferenceScoreUsingLastDistance(copy_length uint) uint {
+ return literalByteScore*uint(copy_length) + scoreBase + 15
+}
+
+func backwardReferencePenaltyUsingLastDistance(distance_short_code uint) uint {
+ return uint(39) + ((0x1CA10 >> (distance_short_code & 0xE)) & 0xE)
+}
+
+func testStaticDictionaryItem(dictionary *encoderDictionary, item uint, data []byte, max_length uint, max_backward uint, max_distance uint, out *hasherSearchResult) bool {
+ var len uint
+ var word_idx uint
+ var offset uint
+ var matchlen uint
+ var backward uint
+ var score uint
+ len = item & 0x1F
+ word_idx = item >> 5
+ offset = uint(dictionary.words.offsets_by_length[len]) + len*word_idx
+ if len > max_length {
+ return false
+ }
+
+ matchlen = findMatchLengthWithLimit(data, dictionary.words.data[offset:], uint(len))
+ if matchlen+uint(dictionary.cutoffTransformsCount) <= len || matchlen == 0 {
+ return false
+ }
+ {
+ var cut uint = len - matchlen
+ var transform_id uint = (cut << 2) + uint((dictionary.cutoffTransforms>>(cut*6))&0x3F)
+ backward = max_backward + 1 + word_idx + (transform_id << dictionary.words.size_bits_by_length[len])
+ }
+
+ if backward > max_distance {
+ return false
+ }
+
+ score = backwardReferenceScore(matchlen, backward)
+ if score < out.score {
+ return false
+ }
+
+ out.len = matchlen
+ out.len_code_delta = int(len) - int(matchlen)
+ out.distance = backward
+ out.score = score
+ return true
+}
+
+func searchInStaticDictionary(dictionary *encoderDictionary, handle hasherHandle, data []byte, max_length uint, max_backward uint, max_distance uint, out *hasherSearchResult, shallow bool) {
+ var key uint
+ var i uint
+ var self *hasherCommon = handle.Common()
+ if self.dict_num_matches < self.dict_num_lookups>>7 {
+ return
+ }
+
+ key = uint(hash14(data) << 1)
+ for i = 0; ; (func() { i++; key++ })() {
+ var tmp uint
+ if shallow {
+ tmp = 1
+ } else {
+ tmp = 2
+ }
+ if i >= tmp {
+ break
+ }
+ var item uint = uint(dictionary.hash_table[key])
+ self.dict_num_lookups++
+ if item != 0 {
+ var item_matches bool = testStaticDictionaryItem(dictionary, item, data, max_length, max_backward, max_distance, out)
+ if item_matches {
+ self.dict_num_matches++
+ }
+ }
+ }
+}
+
+type backwardMatch struct {
+ distance uint32
+ length_and_code uint32
+}
+
+func initBackwardMatch(self *backwardMatch, dist uint, len uint) {
+ self.distance = uint32(dist)
+ self.length_and_code = uint32(len << 5)
+}
+
+func initDictionaryBackwardMatch(self *backwardMatch, dist uint, len uint, len_code uint) {
+ self.distance = uint32(dist)
+ var tmp uint
+ if len == len_code {
+ tmp = 0
+ } else {
+ tmp = len_code
+ }
+ self.length_and_code = uint32(len<<5 | tmp)
+}
+
+func backwardMatchLength(self *backwardMatch) uint {
+ return uint(self.length_and_code >> 5)
+}
+
+func backwardMatchLengthCode(self *backwardMatch) uint {
+ var code uint = uint(self.length_and_code) & 31
+ if code != 0 {
+ return code
+ } else {
+ return backwardMatchLength(self)
+ }
+}
+
+func hasherReset(handle hasherHandle) {
+ if handle == nil {
+ return
+ }
+ handle.Common().is_prepared_ = false
+}
+
+func newHasher(typ int) hasherHandle {
+ switch typ {
+ case 2:
+ return &hashLongestMatchQuickly{
+ bucketBits: 16,
+ bucketSweep: 1,
+ hashLen: 5,
+ useDictionary: true,
+ }
+ case 3:
+ return &hashLongestMatchQuickly{
+ bucketBits: 16,
+ bucketSweep: 2,
+ hashLen: 5,
+ useDictionary: false,
+ }
+ case 4:
+ return &hashLongestMatchQuickly{
+ bucketBits: 17,
+ bucketSweep: 4,
+ hashLen: 5,
+ useDictionary: true,
+ }
+ case 5:
+ return new(h5)
+ case 6:
+ return new(h6)
+ case 10:
+ return new(h10)
+ case 35:
+ return &hashComposite{
+ ha: newHasher(3),
+ hb: &hashRolling{jump: 4},
+ }
+ case 40:
+ return &hashForgetfulChain{
+ bucketBits: 15,
+ numBanks: 1,
+ bankBits: 16,
+ numLastDistancesToCheck: 4,
+ }
+ case 41:
+ return &hashForgetfulChain{
+ bucketBits: 15,
+ numBanks: 1,
+ bankBits: 16,
+ numLastDistancesToCheck: 10,
+ }
+ case 42:
+ return &hashForgetfulChain{
+ bucketBits: 15,
+ numBanks: 512,
+ bankBits: 9,
+ numLastDistancesToCheck: 16,
+ }
+ case 54:
+ return &hashLongestMatchQuickly{
+ bucketBits: 20,
+ bucketSweep: 4,
+ hashLen: 7,
+ useDictionary: false,
+ }
+ case 55:
+ return &hashComposite{
+ ha: newHasher(54),
+ hb: &hashRolling{jump: 4},
+ }
+ case 65:
+ return &hashComposite{
+ ha: newHasher(6),
+ hb: &hashRolling{jump: 1},
+ }
+ }
+
+ panic(fmt.Sprintf("unknown hasher type: %d", typ))
+}
+
+func hasherSetup(handle *hasherHandle, params *encoderParams, data []byte, position uint, input_size uint, is_last bool) {
+ var self hasherHandle = nil
+ var common *hasherCommon = nil
+ var one_shot bool = (position == 0 && is_last)
+ if *handle == nil {
+ chooseHasher(params, ¶ms.hasher)
+ self = newHasher(params.hasher.type_)
+
+ *handle = self
+ common = self.Common()
+ common.params = params.hasher
+ self.Initialize(params)
+ }
+
+ self = *handle
+ common = self.Common()
+ if !common.is_prepared_ {
+ self.Prepare(one_shot, input_size, data)
+
+ if position == 0 {
+ common.dict_num_lookups = 0
+ common.dict_num_matches = 0
+ }
+
+ common.is_prepared_ = true
+ }
+}
+
+func initOrStitchToPreviousBlock(handle *hasherHandle, data []byte, mask uint, params *encoderParams, position uint, input_size uint, is_last bool) {
+ var self hasherHandle
+ hasherSetup(handle, params, data, position, input_size, is_last)
+ self = *handle
+ self.StitchToPreviousBlock(input_size, position, data, mask)
+}
diff --git a/vendor/github.com/andybalholm/brotli/hash_composite.go b/vendor/github.com/andybalholm/brotli/hash_composite.go
new file mode 100644
index 0000000..a65fe2e
--- /dev/null
+++ b/vendor/github.com/andybalholm/brotli/hash_composite.go
@@ -0,0 +1,93 @@
+package brotli
+
+/* Copyright 2018 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+func (h *hashComposite) HashTypeLength() uint {
+ var a uint = h.ha.HashTypeLength()
+ var b uint = h.hb.HashTypeLength()
+ if a > b {
+ return a
+ } else {
+ return b
+ }
+}
+
+func (h *hashComposite) StoreLookahead() uint {
+ var a uint = h.ha.StoreLookahead()
+ var b uint = h.hb.StoreLookahead()
+ if a > b {
+ return a
+ } else {
+ return b
+ }
+}
+
+/* Composite hasher: This hasher allows to combine two other hashers, HASHER_A
+ and HASHER_B. */
+type hashComposite struct {
+ hasherCommon
+ ha hasherHandle
+ hb hasherHandle
+ params *encoderParams
+}
+
+func (h *hashComposite) Initialize(params *encoderParams) {
+ h.params = params
+}
+
+/* TODO: Initialize of the hashers is defered to Prepare (and params
+ remembered here) because we don't get the one_shot and input_size params
+ here that are needed to know the memory size of them. Instead provide
+ those params to all hashers InitializehashComposite */
+func (h *hashComposite) Prepare(one_shot bool, input_size uint, data []byte) {
+ if h.ha == nil {
+ var common_a *hasherCommon
+ var common_b *hasherCommon
+
+ common_a = h.ha.Common()
+ common_a.params = h.params.hasher
+ common_a.is_prepared_ = false
+ common_a.dict_num_lookups = 0
+ common_a.dict_num_matches = 0
+ h.ha.Initialize(h.params)
+
+ common_b = h.hb.Common()
+ common_b.params = h.params.hasher
+ common_b.is_prepared_ = false
+ common_b.dict_num_lookups = 0
+ common_b.dict_num_matches = 0
+ h.hb.Initialize(h.params)
+ }
+
+ h.ha.Prepare(one_shot, input_size, data)
+ h.hb.Prepare(one_shot, input_size, data)
+}
+
+func (h *hashComposite) Store(data []byte, mask uint, ix uint) {
+ h.ha.Store(data, mask, ix)
+ h.hb.Store(data, mask, ix)
+}
+
+func (h *hashComposite) StoreRange(data []byte, mask uint, ix_start uint, ix_end uint) {
+ h.ha.StoreRange(data, mask, ix_start, ix_end)
+ h.hb.StoreRange(data, mask, ix_start, ix_end)
+}
+
+func (h *hashComposite) StitchToPreviousBlock(num_bytes uint, position uint, ringbuffer []byte, ring_buffer_mask uint) {
+ h.ha.StitchToPreviousBlock(num_bytes, position, ringbuffer, ring_buffer_mask)
+ h.hb.StitchToPreviousBlock(num_bytes, position, ringbuffer, ring_buffer_mask)
+}
+
+func (h *hashComposite) PrepareDistanceCache(distance_cache []int) {
+ h.ha.PrepareDistanceCache(distance_cache)
+ h.hb.PrepareDistanceCache(distance_cache)
+}
+
+func (h *hashComposite) FindLongestMatch(dictionary *encoderDictionary, data []byte, ring_buffer_mask uint, distance_cache []int, cur_ix uint, max_length uint, max_backward uint, gap uint, max_distance uint, out *hasherSearchResult) {
+ h.ha.FindLongestMatch(dictionary, data, ring_buffer_mask, distance_cache, cur_ix, max_length, max_backward, gap, max_distance, out)
+ h.hb.FindLongestMatch(dictionary, data, ring_buffer_mask, distance_cache, cur_ix, max_length, max_backward, gap, max_distance, out)
+}
diff --git a/vendor/github.com/andybalholm/brotli/hash_forgetful_chain.go b/vendor/github.com/andybalholm/brotli/hash_forgetful_chain.go
new file mode 100644
index 0000000..306e46d
--- /dev/null
+++ b/vendor/github.com/andybalholm/brotli/hash_forgetful_chain.go
@@ -0,0 +1,252 @@
+package brotli
+
+import "encoding/binary"
+
+/* Copyright 2016 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+func (*hashForgetfulChain) HashTypeLength() uint {
+ return 4
+}
+
+func (*hashForgetfulChain) StoreLookahead() uint {
+ return 4
+}
+
+/* HashBytes is the function that chooses the bucket to place the address in.*/
+func (h *hashForgetfulChain) HashBytes(data []byte) uint {
+ var hash uint32 = binary.LittleEndian.Uint32(data) * kHashMul32
+
+ /* The higher bits contain more mixture from the multiplication,
+ so we take our results from there. */
+ return uint(hash >> (32 - h.bucketBits))
+}
+
+type slot struct {
+ delta uint16
+ next uint16
+}
+
+/* A (forgetful) hash table to the data seen by the compressor, to
+ help create backward references to previous data.
+
+ Hashes are stored in chains which are bucketed to groups. Group of chains
+ share a storage "bank". When more than "bank size" chain nodes are added,
+ oldest nodes are replaced; this way several chains may share a tail. */
+type hashForgetfulChain struct {
+ hasherCommon
+
+ bucketBits uint
+ numBanks uint
+ bankBits uint
+ numLastDistancesToCheck int
+
+ addr []uint32
+ head []uint16
+ tiny_hash [65536]byte
+ banks [][]slot
+ free_slot_idx []uint16
+ max_hops uint
+}
+
+func (h *hashForgetfulChain) Initialize(params *encoderParams) {
+ var q uint
+ if params.quality > 6 {
+ q = 7
+ } else {
+ q = 8
+ }
+ h.max_hops = q << uint(params.quality-4)
+
+ bankSize := 1 << h.bankBits
+ bucketSize := 1 << h.bucketBits
+
+ h.addr = make([]uint32, bucketSize)
+ h.head = make([]uint16, bucketSize)
+ h.banks = make([][]slot, h.numBanks)
+ for i := range h.banks {
+ h.banks[i] = make([]slot, bankSize)
+ }
+ h.free_slot_idx = make([]uint16, h.numBanks)
+}
+
+func (h *hashForgetfulChain) Prepare(one_shot bool, input_size uint, data []byte) {
+ var partial_prepare_threshold uint = (1 << h.bucketBits) >> 6
+ /* Partial preparation is 100 times slower (per socket). */
+ if one_shot && input_size <= partial_prepare_threshold {
+ var i uint
+ for i = 0; i < input_size; i++ {
+ var bucket uint = h.HashBytes(data[i:])
+
+ /* See InitEmpty comment. */
+ h.addr[bucket] = 0xCCCCCCCC
+
+ h.head[bucket] = 0xCCCC
+ }
+ } else {
+ /* Fill |addr| array with 0xCCCCCCCC value. Because of wrapping, position
+ processed by hasher never reaches 3GB + 64M; this makes all new chains
+ to be terminated after the first node. */
+ for i := range h.addr {
+ h.addr[i] = 0xCCCCCCCC
+ }
+
+ for i := range h.head {
+ h.head[i] = 0
+ }
+ }
+
+ h.tiny_hash = [65536]byte{}
+ for i := range h.free_slot_idx {
+ h.free_slot_idx[i] = 0
+ }
+}
+
+/* Look at 4 bytes at &data[ix & mask]. Compute a hash from these, and prepend
+ node to corresponding chain; also update tiny_hash for current position. */
+func (h *hashForgetfulChain) Store(data []byte, mask uint, ix uint) {
+ var key uint = h.HashBytes(data[ix&mask:])
+ var bank uint = key & (h.numBanks - 1)
+ idx := uint(h.free_slot_idx[bank]) & ((1 << h.bankBits) - 1)
+ h.free_slot_idx[bank]++
+ var delta uint = ix - uint(h.addr[key])
+ h.tiny_hash[uint16(ix)] = byte(key)
+ if delta > 0xFFFF {
+ delta = 0xFFFF
+ }
+ h.banks[bank][idx].delta = uint16(delta)
+ h.banks[bank][idx].next = h.head[key]
+ h.addr[key] = uint32(ix)
+ h.head[key] = uint16(idx)
+}
+
+func (h *hashForgetfulChain) StoreRange(data []byte, mask uint, ix_start uint, ix_end uint) {
+ var i uint
+ for i = ix_start; i < ix_end; i++ {
+ h.Store(data, mask, i)
+ }
+}
+
+func (h *hashForgetfulChain) StitchToPreviousBlock(num_bytes uint, position uint, ringbuffer []byte, ring_buffer_mask uint) {
+ if num_bytes >= h.HashTypeLength()-1 && position >= 3 {
+ /* Prepare the hashes for three last bytes of the last write.
+ These could not be calculated before, since they require knowledge
+ of both the previous and the current block. */
+ h.Store(ringbuffer, ring_buffer_mask, position-3)
+ h.Store(ringbuffer, ring_buffer_mask, position-2)
+ h.Store(ringbuffer, ring_buffer_mask, position-1)
+ }
+}
+
+func (h *hashForgetfulChain) PrepareDistanceCache(distance_cache []int) {
+ prepareDistanceCache(distance_cache, h.numLastDistancesToCheck)
+}
+
+/* Find a longest backward match of &data[cur_ix] up to the length of
+ max_length and stores the position cur_ix in the hash table.
+
+ REQUIRES: PrepareDistanceCachehashForgetfulChain must be invoked for current distance cache
+ values; if this method is invoked repeatedly with the same distance
+ cache values, it is enough to invoke PrepareDistanceCachehashForgetfulChain once.
+
+ Does not look for matches longer than max_length.
+ Does not look for matches further away than max_backward.
+ Writes the best match into |out|.
+ |out|->score is updated only if a better match is found. */
+func (h *hashForgetfulChain) FindLongestMatch(dictionary *encoderDictionary, data []byte, ring_buffer_mask uint, distance_cache []int, cur_ix uint, max_length uint, max_backward uint, gap uint, max_distance uint, out *hasherSearchResult) {
+ var cur_ix_masked uint = cur_ix & ring_buffer_mask
+ var min_score uint = out.score
+ var best_score uint = out.score
+ var best_len uint = out.len
+ var key uint = h.HashBytes(data[cur_ix_masked:])
+ var tiny_hash byte = byte(key)
+ /* Don't accept a short copy from far away. */
+ out.len = 0
+
+ out.len_code_delta = 0
+
+ /* Try last distance first. */
+ for i := 0; i < h.numLastDistancesToCheck; i++ {
+ var backward uint = uint(distance_cache[i])
+ var prev_ix uint = (cur_ix - backward)
+
+ /* For distance code 0 we want to consider 2-byte matches. */
+ if i > 0 && h.tiny_hash[uint16(prev_ix)] != tiny_hash {
+ continue
+ }
+ if prev_ix >= cur_ix || backward > max_backward {
+ continue
+ }
+
+ prev_ix &= ring_buffer_mask
+ {
+ var len uint = findMatchLengthWithLimit(data[prev_ix:], data[cur_ix_masked:], max_length)
+ if len >= 2 {
+ var score uint = backwardReferenceScoreUsingLastDistance(uint(len))
+ if best_score < score {
+ if i != 0 {
+ score -= backwardReferencePenaltyUsingLastDistance(uint(i))
+ }
+ if best_score < score {
+ best_score = score
+ best_len = uint(len)
+ out.len = best_len
+ out.distance = backward
+ out.score = best_score
+ }
+ }
+ }
+ }
+ }
+ {
+ var bank uint = key & (h.numBanks - 1)
+ var backward uint = 0
+ var hops uint = h.max_hops
+ var delta uint = cur_ix - uint(h.addr[key])
+ var slot uint = uint(h.head[key])
+ for {
+ tmp6 := hops
+ hops--
+ if tmp6 == 0 {
+ break
+ }
+ var prev_ix uint
+ var last uint = slot
+ backward += delta
+ if backward > max_backward {
+ break
+ }
+ prev_ix = (cur_ix - backward) & ring_buffer_mask
+ slot = uint(h.banks[bank][last].next)
+ delta = uint(h.banks[bank][last].delta)
+ if cur_ix_masked+best_len > ring_buffer_mask || prev_ix+best_len > ring_buffer_mask || data[cur_ix_masked+best_len] != data[prev_ix+best_len] {
+ continue
+ }
+ {
+ var len uint = findMatchLengthWithLimit(data[prev_ix:], data[cur_ix_masked:], max_length)
+ if len >= 4 {
+ /* Comparing for >= 3 does not change the semantics, but just saves
+ for a few unnecessary binary logarithms in backward reference
+ score, since we are not interested in such short matches. */
+ var score uint = backwardReferenceScore(uint(len), backward)
+ if best_score < score {
+ best_score = score
+ best_len = uint(len)
+ out.len = best_len
+ out.distance = backward
+ out.score = best_score
+ }
+ }
+ }
+ }
+
+ h.Store(data, ring_buffer_mask, cur_ix)
+ }
+
+ if out.score == min_score {
+ searchInStaticDictionary(dictionary, h, data[cur_ix_masked:], max_length, max_backward+gap, max_distance, out, false)
+ }
+}
diff --git a/vendor/github.com/andybalholm/brotli/hash_longest_match_quickly.go b/vendor/github.com/andybalholm/brotli/hash_longest_match_quickly.go
new file mode 100644
index 0000000..9375dc1
--- /dev/null
+++ b/vendor/github.com/andybalholm/brotli/hash_longest_match_quickly.go
@@ -0,0 +1,214 @@
+package brotli
+
+import "encoding/binary"
+
+/* Copyright 2010 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* For BUCKET_SWEEP == 1, enabling the dictionary lookup makes compression
+ a little faster (0.5% - 1%) and it compresses 0.15% better on small text
+ and HTML inputs. */
+
+func (*hashLongestMatchQuickly) HashTypeLength() uint {
+ return 8
+}
+
+func (*hashLongestMatchQuickly) StoreLookahead() uint {
+ return 8
+}
+
+/* HashBytes is the function that chooses the bucket to place
+ the address in. The HashLongestMatch and hashLongestMatchQuickly
+ classes have separate, different implementations of hashing. */
+func (h *hashLongestMatchQuickly) HashBytes(data []byte) uint32 {
+ var hash uint64 = ((binary.LittleEndian.Uint64(data) << (64 - 8*h.hashLen)) * kHashMul64)
+
+ /* The higher bits contain more mixture from the multiplication,
+ so we take our results from there. */
+ return uint32(hash >> (64 - h.bucketBits))
+}
+
+/* A (forgetful) hash table to the data seen by the compressor, to
+ help create backward references to previous data.
+
+ This is a hash map of fixed size (1 << 16). Starting from the
+ given index, 1 buckets are used to store values of a key. */
+type hashLongestMatchQuickly struct {
+ hasherCommon
+
+ bucketBits uint
+ bucketSweep int
+ hashLen uint
+ useDictionary bool
+
+ buckets []uint32
+}
+
+func (h *hashLongestMatchQuickly) Initialize(params *encoderParams) {
+ h.buckets = make([]uint32, 1<> 7
+ /* Partial preparation is 100 times slower (per socket). */
+ if one_shot && input_size <= partial_prepare_threshold {
+ var i uint
+ for i = 0; i < input_size; i++ {
+ var key uint32 = h.HashBytes(data[i:])
+ for j := 0; j < h.bucketSweep; j++ {
+ h.buckets[key+uint32(j)] = 0
+ }
+ }
+ } else {
+ /* It is not strictly necessary to fill this buffer here, but
+ not filling will make the results of the compression stochastic
+ (but correct). This is because random data would cause the
+ system to find accidentally good backward references here and there. */
+ for i := range h.buckets {
+ h.buckets[i] = 0
+ }
+ }
+}
+
+/* Look at 5 bytes at &data[ix & mask].
+ Compute a hash from these, and store the value somewhere within
+ [ix .. ix+3]. */
+func (h *hashLongestMatchQuickly) Store(data []byte, mask uint, ix uint) {
+ var key uint32 = h.HashBytes(data[ix&mask:])
+ var off uint32 = uint32(ix>>3) % uint32(h.bucketSweep)
+ /* Wiggle the value with the bucket sweep range. */
+ h.buckets[key+off] = uint32(ix)
+}
+
+func (h *hashLongestMatchQuickly) StoreRange(data []byte, mask uint, ix_start uint, ix_end uint) {
+ var i uint
+ for i = ix_start; i < ix_end; i++ {
+ h.Store(data, mask, i)
+ }
+}
+
+func (h *hashLongestMatchQuickly) StitchToPreviousBlock(num_bytes uint, position uint, ringbuffer []byte, ringbuffer_mask uint) {
+ if num_bytes >= h.HashTypeLength()-1 && position >= 3 {
+ /* Prepare the hashes for three last bytes of the last write.
+ These could not be calculated before, since they require knowledge
+ of both the previous and the current block. */
+ h.Store(ringbuffer, ringbuffer_mask, position-3)
+ h.Store(ringbuffer, ringbuffer_mask, position-2)
+ h.Store(ringbuffer, ringbuffer_mask, position-1)
+ }
+}
+
+func (*hashLongestMatchQuickly) PrepareDistanceCache(distance_cache []int) {
+}
+
+/* Find a longest backward match of &data[cur_ix & ring_buffer_mask]
+ up to the length of max_length and stores the position cur_ix in the
+ hash table.
+
+ Does not look for matches longer than max_length.
+ Does not look for matches further away than max_backward.
+ Writes the best match into |out|.
+ |out|->score is updated only if a better match is found. */
+func (h *hashLongestMatchQuickly) FindLongestMatch(dictionary *encoderDictionary, data []byte, ring_buffer_mask uint, distance_cache []int, cur_ix uint, max_length uint, max_backward uint, gap uint, max_distance uint, out *hasherSearchResult) {
+ var best_len_in uint = out.len
+ var cur_ix_masked uint = cur_ix & ring_buffer_mask
+ var key uint32 = h.HashBytes(data[cur_ix_masked:])
+ var compare_char int = int(data[cur_ix_masked+best_len_in])
+ var min_score uint = out.score
+ var best_score uint = out.score
+ var best_len uint = best_len_in
+ var cached_backward uint = uint(distance_cache[0])
+ var prev_ix uint = cur_ix - cached_backward
+ var bucket []uint32
+ out.len_code_delta = 0
+ if prev_ix < cur_ix {
+ prev_ix &= uint(uint32(ring_buffer_mask))
+ if compare_char == int(data[prev_ix+best_len]) {
+ var len uint = findMatchLengthWithLimit(data[prev_ix:], data[cur_ix_masked:], max_length)
+ if len >= 4 {
+ var score uint = backwardReferenceScoreUsingLastDistance(uint(len))
+ if best_score < score {
+ best_score = score
+ best_len = uint(len)
+ out.len = uint(len)
+ out.distance = cached_backward
+ out.score = best_score
+ compare_char = int(data[cur_ix_masked+best_len])
+ if h.bucketSweep == 1 {
+ h.buckets[key] = uint32(cur_ix)
+ return
+ }
+ }
+ }
+ }
+ }
+
+ if h.bucketSweep == 1 {
+ var backward uint
+ var len uint
+
+ /* Only one to look for, don't bother to prepare for a loop. */
+ prev_ix = uint(h.buckets[key])
+
+ h.buckets[key] = uint32(cur_ix)
+ backward = cur_ix - prev_ix
+ prev_ix &= uint(uint32(ring_buffer_mask))
+ if compare_char != int(data[prev_ix+best_len_in]) {
+ return
+ }
+
+ if backward == 0 || backward > max_backward {
+ return
+ }
+
+ len = findMatchLengthWithLimit(data[prev_ix:], data[cur_ix_masked:], max_length)
+ if len >= 4 {
+ var score uint = backwardReferenceScore(uint(len), backward)
+ if best_score < score {
+ out.len = uint(len)
+ out.distance = backward
+ out.score = score
+ return
+ }
+ }
+ } else {
+ bucket = h.buckets[key:]
+ var i int
+ prev_ix = uint(bucket[0])
+ bucket = bucket[1:]
+ for i = 0; i < h.bucketSweep; (func() { i++; tmp3 := bucket; bucket = bucket[1:]; prev_ix = uint(tmp3[0]) })() {
+ var backward uint = cur_ix - prev_ix
+ var len uint
+ prev_ix &= uint(uint32(ring_buffer_mask))
+ if compare_char != int(data[prev_ix+best_len]) {
+ continue
+ }
+
+ if backward == 0 || backward > max_backward {
+ continue
+ }
+
+ len = findMatchLengthWithLimit(data[prev_ix:], data[cur_ix_masked:], max_length)
+ if len >= 4 {
+ var score uint = backwardReferenceScore(uint(len), backward)
+ if best_score < score {
+ best_score = score
+ best_len = uint(len)
+ out.len = best_len
+ out.distance = backward
+ out.score = score
+ compare_char = int(data[cur_ix_masked+best_len])
+ }
+ }
+ }
+ }
+
+ if h.useDictionary && min_score == out.score {
+ searchInStaticDictionary(dictionary, h, data[cur_ix_masked:], max_length, max_backward+gap, max_distance, out, true)
+ }
+
+ h.buckets[key+uint32((cur_ix>>3)%uint(h.bucketSweep))] = uint32(cur_ix)
+}
diff --git a/vendor/github.com/andybalholm/brotli/hash_rolling.go b/vendor/github.com/andybalholm/brotli/hash_rolling.go
new file mode 100644
index 0000000..6630fc0
--- /dev/null
+++ b/vendor/github.com/andybalholm/brotli/hash_rolling.go
@@ -0,0 +1,168 @@
+package brotli
+
+/* Copyright 2018 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* NOTE: this hasher does not search in the dictionary. It is used as
+ backup-hasher, the main hasher already searches in it. */
+
+const kRollingHashMul32 uint32 = 69069
+
+const kInvalidPosHashRolling uint32 = 0xffffffff
+
+/* This hasher uses a longer forward length, but returning a higher value here
+ will hurt compression by the main hasher when combined with a composite
+ hasher. The hasher tests for forward itself instead. */
+func (*hashRolling) HashTypeLength() uint {
+ return 4
+}
+
+func (*hashRolling) StoreLookahead() uint {
+ return 4
+}
+
+/* Computes a code from a single byte. A lookup table of 256 values could be
+ used, but simply adding 1 works about as good. */
+func (*hashRolling) HashByte(b byte) uint32 {
+ return uint32(b) + 1
+}
+
+func (h *hashRolling) HashRollingFunctionInitial(state uint32, add byte, factor uint32) uint32 {
+ return uint32(factor*state + h.HashByte(add))
+}
+
+func (h *hashRolling) HashRollingFunction(state uint32, add byte, rem byte, factor uint32, factor_remove uint32) uint32 {
+ return uint32(factor*state + h.HashByte(add) - factor_remove*h.HashByte(rem))
+}
+
+/* Rolling hash for long distance long string matches. Stores one position
+ per bucket, bucket key is computed over a long region. */
+type hashRolling struct {
+ hasherCommon
+
+ jump int
+
+ state uint32
+ table []uint32
+ next_ix uint
+ factor uint32
+ factor_remove uint32
+}
+
+func (h *hashRolling) Initialize(params *encoderParams) {
+ h.state = 0
+ h.next_ix = 0
+
+ h.factor = kRollingHashMul32
+
+ /* Compute the factor of the oldest byte to remove: factor**steps modulo
+ 0xffffffff (the multiplications rely on 32-bit overflow) */
+ h.factor_remove = 1
+
+ for i := 0; i < 32; i += h.jump {
+ h.factor_remove *= h.factor
+ }
+
+ h.table = make([]uint32, 16777216)
+ for i := 0; i < 16777216; i++ {
+ h.table[i] = kInvalidPosHashRolling
+ }
+}
+
+func (h *hashRolling) Prepare(one_shot bool, input_size uint, data []byte) {
+ /* Too small size, cannot use this hasher. */
+ if input_size < 32 {
+ return
+ }
+ h.state = 0
+ for i := 0; i < 32; i += h.jump {
+ h.state = h.HashRollingFunctionInitial(h.state, data[i], h.factor)
+ }
+}
+
+func (*hashRolling) Store(data []byte, mask uint, ix uint) {
+}
+
+func (*hashRolling) StoreRange(data []byte, mask uint, ix_start uint, ix_end uint) {
+}
+
+func (h *hashRolling) StitchToPreviousBlock(num_bytes uint, position uint, ringbuffer []byte, ring_buffer_mask uint) {
+ var position_masked uint
+ /* In this case we must re-initialize the hasher from scratch from the
+ current position. */
+
+ var available uint = num_bytes
+ if position&uint(h.jump-1) != 0 {
+ var diff uint = uint(h.jump) - (position & uint(h.jump-1))
+ if diff > available {
+ available = 0
+ } else {
+ available = available - diff
+ }
+ position += diff
+ }
+
+ position_masked = position & ring_buffer_mask
+
+ /* wrapping around ringbuffer not handled. */
+ if available > ring_buffer_mask-position_masked {
+ available = ring_buffer_mask - position_masked
+ }
+
+ h.Prepare(false, available, ringbuffer[position&ring_buffer_mask:])
+ h.next_ix = position
+}
+
+func (*hashRolling) PrepareDistanceCache(distance_cache []int) {
+}
+
+func (h *hashRolling) FindLongestMatch(dictionary *encoderDictionary, data []byte, ring_buffer_mask uint, distance_cache []int, cur_ix uint, max_length uint, max_backward uint, gap uint, max_distance uint, out *hasherSearchResult) {
+ var cur_ix_masked uint = cur_ix & ring_buffer_mask
+ var pos uint = h.next_ix
+
+ if cur_ix&uint(h.jump-1) != 0 {
+ return
+ }
+
+ /* Not enough lookahead */
+ if max_length < 32 {
+ return
+ }
+
+ for pos = h.next_ix; pos <= cur_ix; pos += uint(h.jump) {
+ var code uint32 = h.state & ((16777216 * 64) - 1)
+ var rem byte = data[pos&ring_buffer_mask]
+ var add byte = data[(pos+32)&ring_buffer_mask]
+ var found_ix uint = uint(kInvalidPosHashRolling)
+
+ h.state = h.HashRollingFunction(h.state, add, rem, h.factor, h.factor_remove)
+
+ if code < 16777216 {
+ found_ix = uint(h.table[code])
+ h.table[code] = uint32(pos)
+ if pos == cur_ix && uint32(found_ix) != kInvalidPosHashRolling {
+ /* The cast to 32-bit makes backward distances up to 4GB work even
+ if cur_ix is above 4GB, despite using 32-bit values in the table. */
+ var backward uint = uint(uint32(cur_ix - found_ix))
+ if backward <= max_backward {
+ var found_ix_masked uint = found_ix & ring_buffer_mask
+ var len uint = findMatchLengthWithLimit(data[found_ix_masked:], data[cur_ix_masked:], max_length)
+ if len >= 4 && len > out.len {
+ var score uint = backwardReferenceScore(uint(len), backward)
+ if score > out.score {
+ out.len = uint(len)
+ out.distance = backward
+ out.score = score
+ out.len_code_delta = 0
+ }
+ }
+ }
+ }
+ }
+ }
+
+ h.next_ix = cur_ix + uint(h.jump)
+}
diff --git a/vendor/github.com/andybalholm/brotli/histogram.go b/vendor/github.com/andybalholm/brotli/histogram.go
new file mode 100644
index 0000000..0346622
--- /dev/null
+++ b/vendor/github.com/andybalholm/brotli/histogram.go
@@ -0,0 +1,226 @@
+package brotli
+
+import "math"
+
+/* The distance symbols effectively used by "Large Window Brotli" (32-bit). */
+const numHistogramDistanceSymbols = 544
+
+type histogramLiteral struct {
+ data_ [numLiteralSymbols]uint32
+ total_count_ uint
+ bit_cost_ float64
+}
+
+func histogramClearLiteral(self *histogramLiteral) {
+ self.data_ = [numLiteralSymbols]uint32{}
+ self.total_count_ = 0
+ self.bit_cost_ = math.MaxFloat64
+}
+
+func clearHistogramsLiteral(array []histogramLiteral, length uint) {
+ var i uint
+ for i = 0; i < length; i++ {
+ histogramClearLiteral(&array[i:][0])
+ }
+}
+
+func histogramAddLiteral(self *histogramLiteral, val uint) {
+ self.data_[val]++
+ self.total_count_++
+}
+
+func histogramAddVectorLiteral(self *histogramLiteral, p []byte, n uint) {
+ self.total_count_ += n
+ n += 1
+ for {
+ n--
+ if n == 0 {
+ break
+ }
+ self.data_[p[0]]++
+ p = p[1:]
+ }
+}
+
+func histogramAddHistogramLiteral(self *histogramLiteral, v *histogramLiteral) {
+ var i uint
+ self.total_count_ += v.total_count_
+ for i = 0; i < numLiteralSymbols; i++ {
+ self.data_[i] += v.data_[i]
+ }
+}
+
+func histogramDataSizeLiteral() uint {
+ return numLiteralSymbols
+}
+
+type histogramCommand struct {
+ data_ [numCommandSymbols]uint32
+ total_count_ uint
+ bit_cost_ float64
+}
+
+func histogramClearCommand(self *histogramCommand) {
+ self.data_ = [numCommandSymbols]uint32{}
+ self.total_count_ = 0
+ self.bit_cost_ = math.MaxFloat64
+}
+
+func clearHistogramsCommand(array []histogramCommand, length uint) {
+ var i uint
+ for i = 0; i < length; i++ {
+ histogramClearCommand(&array[i:][0])
+ }
+}
+
+func histogramAddCommand(self *histogramCommand, val uint) {
+ self.data_[val]++
+ self.total_count_++
+}
+
+func histogramAddVectorCommand(self *histogramCommand, p []uint16, n uint) {
+ self.total_count_ += n
+ n += 1
+ for {
+ n--
+ if n == 0 {
+ break
+ }
+ self.data_[p[0]]++
+ p = p[1:]
+ }
+}
+
+func histogramAddHistogramCommand(self *histogramCommand, v *histogramCommand) {
+ var i uint
+ self.total_count_ += v.total_count_
+ for i = 0; i < numCommandSymbols; i++ {
+ self.data_[i] += v.data_[i]
+ }
+}
+
+func histogramDataSizeCommand() uint {
+ return numCommandSymbols
+}
+
+type histogramDistance struct {
+ data_ [numDistanceSymbols]uint32
+ total_count_ uint
+ bit_cost_ float64
+}
+
+func histogramClearDistance(self *histogramDistance) {
+ self.data_ = [numDistanceSymbols]uint32{}
+ self.total_count_ = 0
+ self.bit_cost_ = math.MaxFloat64
+}
+
+func clearHistogramsDistance(array []histogramDistance, length uint) {
+ var i uint
+ for i = 0; i < length; i++ {
+ histogramClearDistance(&array[i:][0])
+ }
+}
+
+func histogramAddDistance(self *histogramDistance, val uint) {
+ self.data_[val]++
+ self.total_count_++
+}
+
+func histogramAddVectorDistance(self *histogramDistance, p []uint16, n uint) {
+ self.total_count_ += n
+ n += 1
+ for {
+ n--
+ if n == 0 {
+ break
+ }
+ self.data_[p[0]]++
+ p = p[1:]
+ }
+}
+
+func histogramAddHistogramDistance(self *histogramDistance, v *histogramDistance) {
+ var i uint
+ self.total_count_ += v.total_count_
+ for i = 0; i < numDistanceSymbols; i++ {
+ self.data_[i] += v.data_[i]
+ }
+}
+
+func histogramDataSizeDistance() uint {
+ return numDistanceSymbols
+}
+
+type blockSplitIterator struct {
+ split_ *blockSplit
+ idx_ uint
+ type_ uint
+ length_ uint
+}
+
+func initBlockSplitIterator(self *blockSplitIterator, split *blockSplit) {
+ self.split_ = split
+ self.idx_ = 0
+ self.type_ = 0
+ if len(split.lengths) > 0 {
+ self.length_ = uint(split.lengths[0])
+ } else {
+ self.length_ = 0
+ }
+}
+
+func blockSplitIteratorNext(self *blockSplitIterator) {
+ if self.length_ == 0 {
+ self.idx_++
+ self.type_ = uint(self.split_.types[self.idx_])
+ self.length_ = uint(self.split_.lengths[self.idx_])
+ }
+
+ self.length_--
+}
+
+func buildHistogramsWithContext(cmds []command, literal_split *blockSplit, insert_and_copy_split *blockSplit, dist_split *blockSplit, ringbuffer []byte, start_pos uint, mask uint, prev_byte byte, prev_byte2 byte, context_modes []int, literal_histograms []histogramLiteral, insert_and_copy_histograms []histogramCommand, copy_dist_histograms []histogramDistance) {
+ var pos uint = start_pos
+ var literal_it blockSplitIterator
+ var insert_and_copy_it blockSplitIterator
+ var dist_it blockSplitIterator
+
+ initBlockSplitIterator(&literal_it, literal_split)
+ initBlockSplitIterator(&insert_and_copy_it, insert_and_copy_split)
+ initBlockSplitIterator(&dist_it, dist_split)
+ for i := range cmds {
+ var cmd *command = &cmds[i]
+ var j uint
+ blockSplitIteratorNext(&insert_and_copy_it)
+ histogramAddCommand(&insert_and_copy_histograms[insert_and_copy_it.type_], uint(cmd.cmd_prefix_))
+
+ /* TODO: unwrap iterator blocks. */
+ for j = uint(cmd.insert_len_); j != 0; j-- {
+ var context uint
+ blockSplitIteratorNext(&literal_it)
+ context = literal_it.type_
+ if context_modes != nil {
+ var lut contextLUT = getContextLUT(context_modes[context])
+ context = (context << literalContextBits) + uint(getContext(prev_byte, prev_byte2, lut))
+ }
+
+ histogramAddLiteral(&literal_histograms[context], uint(ringbuffer[pos&mask]))
+ prev_byte2 = prev_byte
+ prev_byte = ringbuffer[pos&mask]
+ pos++
+ }
+
+ pos += uint(commandCopyLen(cmd))
+ if commandCopyLen(cmd) != 0 {
+ prev_byte2 = ringbuffer[(pos-2)&mask]
+ prev_byte = ringbuffer[(pos-1)&mask]
+ if cmd.cmd_prefix_ >= 128 {
+ var context uint
+ blockSplitIteratorNext(&dist_it)
+ context = uint(uint32(dist_it.type_< bestQ &&
+ (spec.Value == "*" || spec.Value == offer) {
+ bestQ = spec.Q
+ bestOffer = offer
+ }
+ }
+ }
+ if bestQ == 0 {
+ bestOffer = ""
+ }
+ return bestOffer
+}
+
+// acceptSpec describes an Accept* header.
+type acceptSpec struct {
+ Value string
+ Q float64
+}
+
+// parseAccept parses Accept* headers.
+func parseAccept(header http.Header, key string) (specs []acceptSpec) {
+loop:
+ for _, s := range header[key] {
+ for {
+ var spec acceptSpec
+ spec.Value, s = expectTokenSlash(s)
+ if spec.Value == "" {
+ continue loop
+ }
+ spec.Q = 1.0
+ s = skipSpace(s)
+ if strings.HasPrefix(s, ";") {
+ s = skipSpace(s[1:])
+ if !strings.HasPrefix(s, "q=") {
+ continue loop
+ }
+ spec.Q, s = expectQuality(s[2:])
+ if spec.Q < 0.0 {
+ continue loop
+ }
+ }
+ specs = append(specs, spec)
+ s = skipSpace(s)
+ if !strings.HasPrefix(s, ",") {
+ continue loop
+ }
+ s = skipSpace(s[1:])
+ }
+ }
+ return
+}
+
+func skipSpace(s string) (rest string) {
+ i := 0
+ for ; i < len(s); i++ {
+ if octetTypes[s[i]]&isSpace == 0 {
+ break
+ }
+ }
+ return s[i:]
+}
+
+func expectTokenSlash(s string) (token, rest string) {
+ i := 0
+ for ; i < len(s); i++ {
+ b := s[i]
+ if (octetTypes[b]&isToken == 0) && b != '/' {
+ break
+ }
+ }
+ return s[:i], s[i:]
+}
+
+func expectQuality(s string) (q float64, rest string) {
+ switch {
+ case len(s) == 0:
+ return -1, ""
+ case s[0] == '0':
+ q = 0
+ case s[0] == '1':
+ q = 1
+ default:
+ return -1, ""
+ }
+ s = s[1:]
+ if !strings.HasPrefix(s, ".") {
+ return q, s
+ }
+ s = s[1:]
+ i := 0
+ n := 0
+ d := 1
+ for ; i < len(s); i++ {
+ b := s[i]
+ if b < '0' || b > '9' {
+ break
+ }
+ n = n*10 + int(b) - '0'
+ d *= 10
+ }
+ return q + float64(n)/float64(d), s[i:]
+}
+
+// Octet types from RFC 2616.
+var octetTypes [256]octetType
+
+type octetType byte
+
+const (
+ isToken octetType = 1 << iota
+ isSpace
+)
+
+func init() {
+ // OCTET =
+ // CHAR =
+ // CTL =
+ // CR =
+ // LF =
+ // SP =
+ // HT =
+ // <"> =
+ // CRLF = CR LF
+ // LWS = [CRLF] 1*( SP | HT )
+ // TEXT =
+ // separators = "(" | ")" | "<" | ">" | "@" | "," | ";" | ":" | "\" | <">
+ // | "/" | "[" | "]" | "?" | "=" | "{" | "}" | SP | HT
+ // token = 1*
+ // qdtext = >
+
+ for c := 0; c < 256; c++ {
+ var t octetType
+ isCtl := c <= 31 || c == 127
+ isChar := 0 <= c && c <= 127
+ isSeparator := strings.ContainsRune(" \t\"(),/:;<=>?@[]\\{}", rune(c))
+ if strings.ContainsRune(" \t\r\n", rune(c)) {
+ t |= isSpace
+ }
+ if isChar && !isCtl && !isSeparator {
+ t |= isToken
+ }
+ octetTypes[c] = t
+ }
+}
diff --git a/vendor/github.com/andybalholm/brotli/huffman.go b/vendor/github.com/andybalholm/brotli/huffman.go
new file mode 100644
index 0000000..182f3d2
--- /dev/null
+++ b/vendor/github.com/andybalholm/brotli/huffman.go
@@ -0,0 +1,653 @@
+package brotli
+
+/* Copyright 2013 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Utilities for building Huffman decoding tables. */
+
+const huffmanMaxCodeLength = 15
+
+/* Maximum possible Huffman table size for an alphabet size of (index * 32),
+ max code length 15 and root table bits 8. */
+var kMaxHuffmanTableSize = []uint16{
+ 256,
+ 402,
+ 436,
+ 468,
+ 500,
+ 534,
+ 566,
+ 598,
+ 630,
+ 662,
+ 694,
+ 726,
+ 758,
+ 790,
+ 822,
+ 854,
+ 886,
+ 920,
+ 952,
+ 984,
+ 1016,
+ 1048,
+ 1080,
+ 1112,
+ 1144,
+ 1176,
+ 1208,
+ 1240,
+ 1272,
+ 1304,
+ 1336,
+ 1368,
+ 1400,
+ 1432,
+ 1464,
+ 1496,
+ 1528,
+}
+
+/* BROTLI_NUM_BLOCK_LEN_SYMBOLS == 26 */
+const huffmanMaxSize26 = 396
+
+/* BROTLI_MAX_BLOCK_TYPE_SYMBOLS == 258 */
+const huffmanMaxSize258 = 632
+
+/* BROTLI_MAX_CONTEXT_MAP_SYMBOLS == 272 */
+const huffmanMaxSize272 = 646
+
+const huffmanMaxCodeLengthCodeLength = 5
+
+/* Do not create this struct directly - use the ConstructHuffmanCode
+ * constructor below! */
+type huffmanCode struct {
+ bits byte
+ value uint16
+}
+
+func constructHuffmanCode(bits byte, value uint16) huffmanCode {
+ var h huffmanCode
+ h.bits = bits
+ h.value = value
+ return h
+}
+
+/* Builds Huffman lookup table assuming code lengths are in symbol order. */
+
+/* Builds Huffman lookup table assuming code lengths are in symbol order.
+ Returns size of resulting table. */
+
+/* Builds a simple Huffman table. The |num_symbols| parameter is to be
+ interpreted as follows: 0 means 1 symbol, 1 means 2 symbols,
+ 2 means 3 symbols, 3 means 4 symbols with lengths [2, 2, 2, 2],
+ 4 means 4 symbols with lengths [1, 2, 3, 3]. */
+
+/* Contains a collection of Huffman trees with the same alphabet size. */
+/* max_symbol is needed due to simple codes since log2(alphabet_size) could be
+ greater than log2(max_symbol). */
+type huffmanTreeGroup struct {
+ htrees [][]huffmanCode
+ codes []huffmanCode
+ alphabet_size uint16
+ max_symbol uint16
+ num_htrees uint16
+}
+
+const reverseBitsMax = 8
+
+const reverseBitsBase = 0
+
+var kReverseBits = [1 << reverseBitsMax]byte{
+ 0x00,
+ 0x80,
+ 0x40,
+ 0xC0,
+ 0x20,
+ 0xA0,
+ 0x60,
+ 0xE0,
+ 0x10,
+ 0x90,
+ 0x50,
+ 0xD0,
+ 0x30,
+ 0xB0,
+ 0x70,
+ 0xF0,
+ 0x08,
+ 0x88,
+ 0x48,
+ 0xC8,
+ 0x28,
+ 0xA8,
+ 0x68,
+ 0xE8,
+ 0x18,
+ 0x98,
+ 0x58,
+ 0xD8,
+ 0x38,
+ 0xB8,
+ 0x78,
+ 0xF8,
+ 0x04,
+ 0x84,
+ 0x44,
+ 0xC4,
+ 0x24,
+ 0xA4,
+ 0x64,
+ 0xE4,
+ 0x14,
+ 0x94,
+ 0x54,
+ 0xD4,
+ 0x34,
+ 0xB4,
+ 0x74,
+ 0xF4,
+ 0x0C,
+ 0x8C,
+ 0x4C,
+ 0xCC,
+ 0x2C,
+ 0xAC,
+ 0x6C,
+ 0xEC,
+ 0x1C,
+ 0x9C,
+ 0x5C,
+ 0xDC,
+ 0x3C,
+ 0xBC,
+ 0x7C,
+ 0xFC,
+ 0x02,
+ 0x82,
+ 0x42,
+ 0xC2,
+ 0x22,
+ 0xA2,
+ 0x62,
+ 0xE2,
+ 0x12,
+ 0x92,
+ 0x52,
+ 0xD2,
+ 0x32,
+ 0xB2,
+ 0x72,
+ 0xF2,
+ 0x0A,
+ 0x8A,
+ 0x4A,
+ 0xCA,
+ 0x2A,
+ 0xAA,
+ 0x6A,
+ 0xEA,
+ 0x1A,
+ 0x9A,
+ 0x5A,
+ 0xDA,
+ 0x3A,
+ 0xBA,
+ 0x7A,
+ 0xFA,
+ 0x06,
+ 0x86,
+ 0x46,
+ 0xC6,
+ 0x26,
+ 0xA6,
+ 0x66,
+ 0xE6,
+ 0x16,
+ 0x96,
+ 0x56,
+ 0xD6,
+ 0x36,
+ 0xB6,
+ 0x76,
+ 0xF6,
+ 0x0E,
+ 0x8E,
+ 0x4E,
+ 0xCE,
+ 0x2E,
+ 0xAE,
+ 0x6E,
+ 0xEE,
+ 0x1E,
+ 0x9E,
+ 0x5E,
+ 0xDE,
+ 0x3E,
+ 0xBE,
+ 0x7E,
+ 0xFE,
+ 0x01,
+ 0x81,
+ 0x41,
+ 0xC1,
+ 0x21,
+ 0xA1,
+ 0x61,
+ 0xE1,
+ 0x11,
+ 0x91,
+ 0x51,
+ 0xD1,
+ 0x31,
+ 0xB1,
+ 0x71,
+ 0xF1,
+ 0x09,
+ 0x89,
+ 0x49,
+ 0xC9,
+ 0x29,
+ 0xA9,
+ 0x69,
+ 0xE9,
+ 0x19,
+ 0x99,
+ 0x59,
+ 0xD9,
+ 0x39,
+ 0xB9,
+ 0x79,
+ 0xF9,
+ 0x05,
+ 0x85,
+ 0x45,
+ 0xC5,
+ 0x25,
+ 0xA5,
+ 0x65,
+ 0xE5,
+ 0x15,
+ 0x95,
+ 0x55,
+ 0xD5,
+ 0x35,
+ 0xB5,
+ 0x75,
+ 0xF5,
+ 0x0D,
+ 0x8D,
+ 0x4D,
+ 0xCD,
+ 0x2D,
+ 0xAD,
+ 0x6D,
+ 0xED,
+ 0x1D,
+ 0x9D,
+ 0x5D,
+ 0xDD,
+ 0x3D,
+ 0xBD,
+ 0x7D,
+ 0xFD,
+ 0x03,
+ 0x83,
+ 0x43,
+ 0xC3,
+ 0x23,
+ 0xA3,
+ 0x63,
+ 0xE3,
+ 0x13,
+ 0x93,
+ 0x53,
+ 0xD3,
+ 0x33,
+ 0xB3,
+ 0x73,
+ 0xF3,
+ 0x0B,
+ 0x8B,
+ 0x4B,
+ 0xCB,
+ 0x2B,
+ 0xAB,
+ 0x6B,
+ 0xEB,
+ 0x1B,
+ 0x9B,
+ 0x5B,
+ 0xDB,
+ 0x3B,
+ 0xBB,
+ 0x7B,
+ 0xFB,
+ 0x07,
+ 0x87,
+ 0x47,
+ 0xC7,
+ 0x27,
+ 0xA7,
+ 0x67,
+ 0xE7,
+ 0x17,
+ 0x97,
+ 0x57,
+ 0xD7,
+ 0x37,
+ 0xB7,
+ 0x77,
+ 0xF7,
+ 0x0F,
+ 0x8F,
+ 0x4F,
+ 0xCF,
+ 0x2F,
+ 0xAF,
+ 0x6F,
+ 0xEF,
+ 0x1F,
+ 0x9F,
+ 0x5F,
+ 0xDF,
+ 0x3F,
+ 0xBF,
+ 0x7F,
+ 0xFF,
+}
+
+const reverseBitsLowest = (uint64(1) << (reverseBitsMax - 1 + reverseBitsBase))
+
+/* Returns reverse(num >> BROTLI_REVERSE_BITS_BASE, BROTLI_REVERSE_BITS_MAX),
+ where reverse(value, len) is the bit-wise reversal of the len least
+ significant bits of value. */
+func reverseBits8(num uint64) uint64 {
+ return uint64(kReverseBits[num])
+}
+
+/* Stores code in table[0], table[step], table[2*step], ..., table[end] */
+/* Assumes that end is an integer multiple of step */
+func replicateValue(table []huffmanCode, step int, end int, code huffmanCode) {
+ for {
+ end -= step
+ table[end] = code
+ if end <= 0 {
+ break
+ }
+ }
+}
+
+/* Returns the table width of the next 2nd level table. |count| is the histogram
+ of bit lengths for the remaining symbols, |len| is the code length of the
+ next processed symbol. */
+func nextTableBitSize(count []uint16, len int, root_bits int) int {
+ var left int = 1 << uint(len-root_bits)
+ for len < huffmanMaxCodeLength {
+ left -= int(count[len])
+ if left <= 0 {
+ break
+ }
+ len++
+ left <<= 1
+ }
+
+ return len - root_bits
+}
+
+func buildCodeLengthsHuffmanTable(table []huffmanCode, code_lengths []byte, count []uint16) {
+ var code huffmanCode /* current table entry */ /* symbol index in original or sorted table */ /* prefix code */ /* prefix code addend */ /* step size to replicate values in current table */ /* size of current table */ /* symbols sorted by code length */
+ var symbol int
+ var key uint64
+ var key_step uint64
+ var step int
+ var table_size int
+ var sorted [codeLengthCodes]int
+ var offset [huffmanMaxCodeLengthCodeLength + 1]int
+ var bits int
+ var bits_count int
+ /* offsets in sorted table for each length */
+ assert(huffmanMaxCodeLengthCodeLength <= reverseBitsMax)
+
+ /* Generate offsets into sorted symbol table by code length. */
+ symbol = -1
+
+ bits = 1
+ var i int
+ for i = 0; i < huffmanMaxCodeLengthCodeLength; i++ {
+ symbol += int(count[bits])
+ offset[bits] = symbol
+ bits++
+ }
+
+ /* Symbols with code length 0 are placed after all other symbols. */
+ offset[0] = codeLengthCodes - 1
+
+ /* Sort symbols by length, by symbol order within each length. */
+ symbol = codeLengthCodes
+
+ for {
+ var i int
+ for i = 0; i < 6; i++ {
+ symbol--
+ sorted[offset[code_lengths[symbol]]] = symbol
+ offset[code_lengths[symbol]]--
+ }
+ if symbol == 0 {
+ break
+ }
+ }
+
+ table_size = 1 << huffmanMaxCodeLengthCodeLength
+
+ /* Special case: all symbols but one have 0 code length. */
+ if offset[0] == 0 {
+ code = constructHuffmanCode(0, uint16(sorted[0]))
+ for key = 0; key < uint64(table_size); key++ {
+ table[key] = code
+ }
+
+ return
+ }
+
+ /* Fill in table. */
+ key = 0
+
+ key_step = reverseBitsLowest
+ symbol = 0
+ bits = 1
+ step = 2
+ for {
+ for bits_count = int(count[bits]); bits_count != 0; bits_count-- {
+ code = constructHuffmanCode(byte(bits), uint16(sorted[symbol]))
+ symbol++
+ replicateValue(table[reverseBits8(key):], step, table_size, code)
+ key += key_step
+ }
+
+ step <<= 1
+ key_step >>= 1
+ bits++
+ if bits > huffmanMaxCodeLengthCodeLength {
+ break
+ }
+ }
+}
+
+func buildHuffmanTable(root_table []huffmanCode, root_bits int, symbol_lists symbolList, count []uint16) uint32 {
+ var code huffmanCode /* current table entry */ /* next available space in table */ /* current code length */ /* symbol index in original or sorted table */ /* prefix code */ /* prefix code addend */ /* 2nd level table prefix code */ /* 2nd level table prefix code addend */ /* step size to replicate values in current table */ /* key length of current table */ /* size of current table */ /* sum of root table size and 2nd level table sizes */
+ var table []huffmanCode
+ var len int
+ var symbol int
+ var key uint64
+ var key_step uint64
+ var sub_key uint64
+ var sub_key_step uint64
+ var step int
+ var table_bits int
+ var table_size int
+ var total_size int
+ var max_length int = -1
+ var bits int
+ var bits_count int
+
+ assert(root_bits <= reverseBitsMax)
+ assert(huffmanMaxCodeLength-root_bits <= reverseBitsMax)
+
+ for symbolListGet(symbol_lists, max_length) == 0xFFFF {
+ max_length--
+ }
+ max_length += huffmanMaxCodeLength + 1
+
+ table = root_table
+ table_bits = root_bits
+ table_size = 1 << uint(table_bits)
+ total_size = table_size
+
+ /* Fill in the root table. Reduce the table size to if possible,
+ and create the repetitions by memcpy. */
+ if table_bits > max_length {
+ table_bits = max_length
+ table_size = 1 << uint(table_bits)
+ }
+
+ key = 0
+ key_step = reverseBitsLowest
+ bits = 1
+ step = 2
+ for {
+ symbol = bits - (huffmanMaxCodeLength + 1)
+ for bits_count = int(count[bits]); bits_count != 0; bits_count-- {
+ symbol = int(symbolListGet(symbol_lists, symbol))
+ code = constructHuffmanCode(byte(bits), uint16(symbol))
+ replicateValue(table[reverseBits8(key):], step, table_size, code)
+ key += key_step
+ }
+
+ step <<= 1
+ key_step >>= 1
+ bits++
+ if bits > table_bits {
+ break
+ }
+ }
+
+ /* If root_bits != table_bits then replicate to fill the remaining slots. */
+ for total_size != table_size {
+ copy(table[table_size:], table[:uint(table_size)])
+ table_size <<= 1
+ }
+
+ /* Fill in 2nd level tables and add pointers to root table. */
+ key_step = reverseBitsLowest >> uint(root_bits-1)
+
+ sub_key = reverseBitsLowest << 1
+ sub_key_step = reverseBitsLowest
+ len = root_bits + 1
+ step = 2
+ for ; len <= max_length; len++ {
+ symbol = len - (huffmanMaxCodeLength + 1)
+ for ; count[len] != 0; count[len]-- {
+ if sub_key == reverseBitsLowest<<1 {
+ table = table[table_size:]
+ table_bits = nextTableBitSize(count, int(len), root_bits)
+ table_size = 1 << uint(table_bits)
+ total_size += table_size
+ sub_key = reverseBits8(key)
+ key += key_step
+ root_table[sub_key] = constructHuffmanCode(byte(table_bits+root_bits), uint16(uint64(uint(-cap(table)+cap(root_table)))-sub_key))
+ sub_key = 0
+ }
+
+ symbol = int(symbolListGet(symbol_lists, symbol))
+ code = constructHuffmanCode(byte(len-root_bits), uint16(symbol))
+ replicateValue(table[reverseBits8(sub_key):], step, table_size, code)
+ sub_key += sub_key_step
+ }
+
+ step <<= 1
+ sub_key_step >>= 1
+ }
+
+ return uint32(total_size)
+}
+
+func buildSimpleHuffmanTable(table []huffmanCode, root_bits int, val []uint16, num_symbols uint32) uint32 {
+ var table_size uint32 = 1
+ var goal_size uint32 = 1 << uint(root_bits)
+ switch num_symbols {
+ case 0:
+ table[0] = constructHuffmanCode(0, val[0])
+
+ case 1:
+ if val[1] > val[0] {
+ table[0] = constructHuffmanCode(1, val[0])
+ table[1] = constructHuffmanCode(1, val[1])
+ } else {
+ table[0] = constructHuffmanCode(1, val[1])
+ table[1] = constructHuffmanCode(1, val[0])
+ }
+
+ table_size = 2
+
+ case 2:
+ table[0] = constructHuffmanCode(1, val[0])
+ table[2] = constructHuffmanCode(1, val[0])
+ if val[2] > val[1] {
+ table[1] = constructHuffmanCode(2, val[1])
+ table[3] = constructHuffmanCode(2, val[2])
+ } else {
+ table[1] = constructHuffmanCode(2, val[2])
+ table[3] = constructHuffmanCode(2, val[1])
+ }
+
+ table_size = 4
+
+ case 3:
+ var i int
+ var k int
+ for i = 0; i < 3; i++ {
+ for k = i + 1; k < 4; k++ {
+ if val[k] < val[i] {
+ var t uint16 = val[k]
+ val[k] = val[i]
+ val[i] = t
+ }
+ }
+ }
+
+ table[0] = constructHuffmanCode(2, val[0])
+ table[2] = constructHuffmanCode(2, val[1])
+ table[1] = constructHuffmanCode(2, val[2])
+ table[3] = constructHuffmanCode(2, val[3])
+ table_size = 4
+
+ case 4:
+ if val[3] < val[2] {
+ var t uint16 = val[3]
+ val[3] = val[2]
+ val[2] = t
+ }
+
+ table[0] = constructHuffmanCode(1, val[0])
+ table[1] = constructHuffmanCode(2, val[1])
+ table[2] = constructHuffmanCode(1, val[0])
+ table[3] = constructHuffmanCode(3, val[2])
+ table[4] = constructHuffmanCode(1, val[0])
+ table[5] = constructHuffmanCode(2, val[1])
+ table[6] = constructHuffmanCode(1, val[0])
+ table[7] = constructHuffmanCode(3, val[3])
+ table_size = 8
+ }
+
+ for table_size != goal_size {
+ copy(table[table_size:], table[:uint(table_size)])
+ table_size <<= 1
+ }
+
+ return goal_size
+}
diff --git a/vendor/github.com/andybalholm/brotli/literal_cost.go b/vendor/github.com/andybalholm/brotli/literal_cost.go
new file mode 100644
index 0000000..5a9ace9
--- /dev/null
+++ b/vendor/github.com/andybalholm/brotli/literal_cost.go
@@ -0,0 +1,182 @@
+package brotli
+
+func utf8Position(last uint, c uint, clamp uint) uint {
+ if c < 128 {
+ return 0 /* Next one is the 'Byte 1' again. */
+ } else if c >= 192 { /* Next one is the 'Byte 2' of utf-8 encoding. */
+ return brotli_min_size_t(1, clamp)
+ } else {
+ /* Let's decide over the last byte if this ends the sequence. */
+ if last < 0xE0 {
+ return 0 /* Completed two or three byte coding. */ /* Next one is the 'Byte 3' of utf-8 encoding. */
+ } else {
+ return brotli_min_size_t(2, clamp)
+ }
+ }
+}
+
+func decideMultiByteStatsLevel(pos uint, len uint, mask uint, data []byte) uint {
+ var counts = [3]uint{0} /* should be 2, but 1 compresses better. */
+ var max_utf8 uint = 1
+ var last_c uint = 0
+ var i uint
+ for i = 0; i < len; i++ {
+ var c uint = uint(data[(pos+i)&mask])
+ counts[utf8Position(last_c, c, 2)]++
+ last_c = c
+ }
+
+ if counts[2] < 500 {
+ max_utf8 = 1
+ }
+
+ if counts[1]+counts[2] < 25 {
+ max_utf8 = 0
+ }
+
+ return max_utf8
+}
+
+func estimateBitCostsForLiteralsUTF8(pos uint, len uint, mask uint, data []byte, cost []float32) {
+ var max_utf8 uint = decideMultiByteStatsLevel(pos, uint(len), mask, data)
+ /* Bootstrap histograms. */
+ var histogram = [3][256]uint{[256]uint{0}}
+ var window_half uint = 495
+ var in_window uint = brotli_min_size_t(window_half, uint(len))
+ var in_window_utf8 = [3]uint{0}
+ /* max_utf8 is 0 (normal ASCII single byte modeling),
+ 1 (for 2-byte UTF-8 modeling), or 2 (for 3-byte UTF-8 modeling). */
+
+ var i uint
+ {
+ var last_c uint = 0
+ var utf8_pos uint = 0
+ for i = 0; i < in_window; i++ {
+ var c uint = uint(data[(pos+i)&mask])
+ histogram[utf8_pos][c]++
+ in_window_utf8[utf8_pos]++
+ utf8_pos = utf8Position(last_c, c, max_utf8)
+ last_c = c
+ }
+ }
+
+ /* Compute bit costs with sliding window. */
+ for i = 0; i < len; i++ {
+ if i >= window_half {
+ var c uint
+ var last_c uint
+ if i < window_half+1 {
+ c = 0
+ } else {
+ c = uint(data[(pos+i-window_half-1)&mask])
+ }
+ if i < window_half+2 {
+ last_c = 0
+ } else {
+ last_c = uint(data[(pos+i-window_half-2)&mask])
+ }
+ /* Remove a byte in the past. */
+
+ var utf8_pos2 uint = utf8Position(last_c, c, max_utf8)
+ histogram[utf8_pos2][data[(pos+i-window_half)&mask]]--
+ in_window_utf8[utf8_pos2]--
+ }
+
+ if i+window_half < len {
+ var c uint = uint(data[(pos+i+window_half-1)&mask])
+ var last_c uint = uint(data[(pos+i+window_half-2)&mask])
+ /* Add a byte in the future. */
+
+ var utf8_pos2 uint = utf8Position(last_c, c, max_utf8)
+ histogram[utf8_pos2][data[(pos+i+window_half)&mask]]++
+ in_window_utf8[utf8_pos2]++
+ }
+ {
+ var c uint
+ var last_c uint
+ if i < 1 {
+ c = 0
+ } else {
+ c = uint(data[(pos+i-1)&mask])
+ }
+ if i < 2 {
+ last_c = 0
+ } else {
+ last_c = uint(data[(pos+i-2)&mask])
+ }
+ var utf8_pos uint = utf8Position(last_c, c, max_utf8)
+ var masked_pos uint = (pos + i) & mask
+ var histo uint = histogram[utf8_pos][data[masked_pos]]
+ var lit_cost float64
+ if histo == 0 {
+ histo = 1
+ }
+
+ lit_cost = fastLog2(in_window_utf8[utf8_pos]) - fastLog2(histo)
+ lit_cost += 0.02905
+ if lit_cost < 1.0 {
+ lit_cost *= 0.5
+ lit_cost += 0.5
+ }
+
+ /* Make the first bytes more expensive -- seems to help, not sure why.
+ Perhaps because the entropy source is changing its properties
+ rapidly in the beginning of the file, perhaps because the beginning
+ of the data is a statistical "anomaly". */
+ if i < 2000 {
+ lit_cost += 0.7 - (float64(2000-i) / 2000.0 * 0.35)
+ }
+
+ cost[i] = float32(lit_cost)
+ }
+ }
+}
+
+func estimateBitCostsForLiterals(pos uint, len uint, mask uint, data []byte, cost []float32) {
+ if isMostlyUTF8(data, pos, mask, uint(len), kMinUTF8Ratio) {
+ estimateBitCostsForLiteralsUTF8(pos, uint(len), mask, data, cost)
+ return
+ } else {
+ var histogram = [256]uint{0}
+ var window_half uint = 2000
+ var in_window uint = brotli_min_size_t(window_half, uint(len))
+ var i uint
+ /* Bootstrap histogram. */
+ for i = 0; i < in_window; i++ {
+ histogram[data[(pos+i)&mask]]++
+ }
+
+ /* Compute bit costs with sliding window. */
+ for i = 0; i < len; i++ {
+ var histo uint
+ if i >= window_half {
+ /* Remove a byte in the past. */
+ histogram[data[(pos+i-window_half)&mask]]--
+
+ in_window--
+ }
+
+ if i+window_half < len {
+ /* Add a byte in the future. */
+ histogram[data[(pos+i+window_half)&mask]]++
+
+ in_window++
+ }
+
+ histo = histogram[data[(pos+i)&mask]]
+ if histo == 0 {
+ histo = 1
+ }
+ {
+ var lit_cost float64 = fastLog2(in_window) - fastLog2(histo)
+ lit_cost += 0.029
+ if lit_cost < 1.0 {
+ lit_cost *= 0.5
+ lit_cost += 0.5
+ }
+
+ cost[i] = float32(lit_cost)
+ }
+ }
+ }
+}
diff --git a/vendor/github.com/andybalholm/brotli/memory.go b/vendor/github.com/andybalholm/brotli/memory.go
new file mode 100644
index 0000000..a07c705
--- /dev/null
+++ b/vendor/github.com/andybalholm/brotli/memory.go
@@ -0,0 +1,66 @@
+package brotli
+
+/* Copyright 2016 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/*
+Dynamically grows array capacity to at least the requested size
+T: data type
+A: array
+C: capacity
+R: requested size
+*/
+func brotli_ensure_capacity_uint8_t(a *[]byte, c *uint, r uint) {
+ if *c < r {
+ var new_size uint = *c
+ if new_size == 0 {
+ new_size = r
+ }
+
+ for new_size < r {
+ new_size *= 2
+ }
+
+ if cap(*a) < int(new_size) {
+ var new_array []byte = make([]byte, new_size)
+ if *c != 0 {
+ copy(new_array, (*a)[:*c])
+ }
+
+ *a = new_array
+ } else {
+ *a = (*a)[:new_size]
+ }
+
+ *c = new_size
+ }
+}
+
+func brotli_ensure_capacity_uint32_t(a *[]uint32, c *uint, r uint) {
+ var new_array []uint32
+ if *c < r {
+ var new_size uint = *c
+ if new_size == 0 {
+ new_size = r
+ }
+
+ for new_size < r {
+ new_size *= 2
+ }
+
+ if cap(*a) < int(new_size) {
+ new_array = make([]uint32, new_size)
+ if *c != 0 {
+ copy(new_array, (*a)[:*c])
+ }
+
+ *a = new_array
+ } else {
+ *a = (*a)[:new_size]
+ }
+ *c = new_size
+ }
+}
diff --git a/vendor/github.com/andybalholm/brotli/metablock.go b/vendor/github.com/andybalholm/brotli/metablock.go
new file mode 100644
index 0000000..3014df8
--- /dev/null
+++ b/vendor/github.com/andybalholm/brotli/metablock.go
@@ -0,0 +1,574 @@
+package brotli
+
+import (
+ "sync"
+)
+
+/* Copyright 2014 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Algorithms for distributing the literals and commands of a metablock between
+ block types and contexts. */
+
+type metaBlockSplit struct {
+ literal_split blockSplit
+ command_split blockSplit
+ distance_split blockSplit
+ literal_context_map []uint32
+ literal_context_map_size uint
+ distance_context_map []uint32
+ distance_context_map_size uint
+ literal_histograms []histogramLiteral
+ literal_histograms_size uint
+ command_histograms []histogramCommand
+ command_histograms_size uint
+ distance_histograms []histogramDistance
+ distance_histograms_size uint
+}
+
+var metaBlockPool sync.Pool
+
+func getMetaBlockSplit() *metaBlockSplit {
+ mb, _ := metaBlockPool.Get().(*metaBlockSplit)
+
+ if mb == nil {
+ mb = &metaBlockSplit{}
+ } else {
+ initBlockSplit(&mb.literal_split)
+ initBlockSplit(&mb.command_split)
+ initBlockSplit(&mb.distance_split)
+ mb.literal_context_map = mb.literal_context_map[:0]
+ mb.literal_context_map_size = 0
+ mb.distance_context_map = mb.distance_context_map[:0]
+ mb.distance_context_map_size = 0
+ mb.literal_histograms = mb.literal_histograms[:0]
+ mb.command_histograms = mb.command_histograms[:0]
+ mb.distance_histograms = mb.distance_histograms[:0]
+ }
+ return mb
+}
+
+func freeMetaBlockSplit(mb *metaBlockSplit) {
+ metaBlockPool.Put(mb)
+}
+
+func initDistanceParams(params *encoderParams, npostfix uint32, ndirect uint32) {
+ var dist_params *distanceParams = ¶ms.dist
+ var alphabet_size uint32
+ var max_distance uint32
+
+ dist_params.distance_postfix_bits = npostfix
+ dist_params.num_direct_distance_codes = ndirect
+
+ alphabet_size = uint32(distanceAlphabetSize(uint(npostfix), uint(ndirect), maxDistanceBits))
+ max_distance = ndirect + (1 << (maxDistanceBits + npostfix + 2)) - (1 << (npostfix + 2))
+
+ if params.large_window {
+ var bound = [maxNpostfix + 1]uint32{0, 4, 12, 28}
+ var postfix uint32 = 1 << npostfix
+ alphabet_size = uint32(distanceAlphabetSize(uint(npostfix), uint(ndirect), largeMaxDistanceBits))
+
+ /* The maximum distance is set so that no distance symbol used can encode
+ a distance larger than BROTLI_MAX_ALLOWED_DISTANCE with all
+ its extra bits set. */
+ if ndirect < bound[npostfix] {
+ max_distance = maxAllowedDistance - (bound[npostfix] - ndirect)
+ } else if ndirect >= bound[npostfix]+postfix {
+ max_distance = (3 << 29) - 4 + (ndirect - bound[npostfix])
+ } else {
+ max_distance = maxAllowedDistance
+ }
+ }
+
+ dist_params.alphabet_size = alphabet_size
+ dist_params.max_distance = uint(max_distance)
+}
+
+func recomputeDistancePrefixes(cmds []command, orig_params *distanceParams, new_params *distanceParams) {
+ if orig_params.distance_postfix_bits == new_params.distance_postfix_bits && orig_params.num_direct_distance_codes == new_params.num_direct_distance_codes {
+ return
+ }
+
+ for i := range cmds {
+ var cmd *command = &cmds[i]
+ if commandCopyLen(cmd) != 0 && cmd.cmd_prefix_ >= 128 {
+ prefixEncodeCopyDistance(uint(commandRestoreDistanceCode(cmd, orig_params)), uint(new_params.num_direct_distance_codes), uint(new_params.distance_postfix_bits), &cmd.dist_prefix_, &cmd.dist_extra_)
+ }
+ }
+}
+
+func computeDistanceCost(cmds []command, orig_params *distanceParams, new_params *distanceParams, cost *float64) bool {
+ var equal_params bool = false
+ var dist_prefix uint16
+ var dist_extra uint32
+ var extra_bits float64 = 0.0
+ var histo histogramDistance
+ histogramClearDistance(&histo)
+
+ if orig_params.distance_postfix_bits == new_params.distance_postfix_bits && orig_params.num_direct_distance_codes == new_params.num_direct_distance_codes {
+ equal_params = true
+ }
+
+ for i := range cmds {
+ cmd := &cmds[i]
+ if commandCopyLen(cmd) != 0 && cmd.cmd_prefix_ >= 128 {
+ if equal_params {
+ dist_prefix = cmd.dist_prefix_
+ } else {
+ var distance uint32 = commandRestoreDistanceCode(cmd, orig_params)
+ if distance > uint32(new_params.max_distance) {
+ return false
+ }
+
+ prefixEncodeCopyDistance(uint(distance), uint(new_params.num_direct_distance_codes), uint(new_params.distance_postfix_bits), &dist_prefix, &dist_extra)
+ }
+
+ histogramAddDistance(&histo, uint(dist_prefix)&0x3FF)
+ extra_bits += float64(dist_prefix >> 10)
+ }
+ }
+
+ *cost = populationCostDistance(&histo) + extra_bits
+ return true
+}
+
+var buildMetaBlock_kMaxNumberOfHistograms uint = 256
+
+func buildMetaBlock(ringbuffer []byte, pos uint, mask uint, params *encoderParams, prev_byte byte, prev_byte2 byte, cmds []command, literal_context_mode int, mb *metaBlockSplit) {
+ var distance_histograms []histogramDistance
+ var literal_histograms []histogramLiteral
+ var literal_context_modes []int = nil
+ var literal_histograms_size uint
+ var distance_histograms_size uint
+ var i uint
+ var literal_context_multiplier uint = 1
+ var npostfix uint32
+ var ndirect_msb uint32 = 0
+ var check_orig bool = true
+ var best_dist_cost float64 = 1e99
+ var orig_params encoderParams = *params
+ /* Histogram ids need to fit in one byte. */
+
+ var new_params encoderParams = *params
+
+ for npostfix = 0; npostfix <= maxNpostfix; npostfix++ {
+ for ; ndirect_msb < 16; ndirect_msb++ {
+ var ndirect uint32 = ndirect_msb << npostfix
+ var skip bool
+ var dist_cost float64
+ initDistanceParams(&new_params, npostfix, ndirect)
+ if npostfix == orig_params.dist.distance_postfix_bits && ndirect == orig_params.dist.num_direct_distance_codes {
+ check_orig = false
+ }
+
+ skip = !computeDistanceCost(cmds, &orig_params.dist, &new_params.dist, &dist_cost)
+ if skip || (dist_cost > best_dist_cost) {
+ break
+ }
+
+ best_dist_cost = dist_cost
+ params.dist = new_params.dist
+ }
+
+ if ndirect_msb > 0 {
+ ndirect_msb--
+ }
+ ndirect_msb /= 2
+ }
+
+ if check_orig {
+ var dist_cost float64
+ computeDistanceCost(cmds, &orig_params.dist, &orig_params.dist, &dist_cost)
+ if dist_cost < best_dist_cost {
+ /* NB: currently unused; uncomment when more param tuning is added. */
+ /* best_dist_cost = dist_cost; */
+ params.dist = orig_params.dist
+ }
+ }
+
+ recomputeDistancePrefixes(cmds, &orig_params.dist, ¶ms.dist)
+
+ splitBlock(cmds, ringbuffer, pos, mask, params, &mb.literal_split, &mb.command_split, &mb.distance_split)
+
+ if !params.disable_literal_context_modeling {
+ literal_context_multiplier = 1 << literalContextBits
+ literal_context_modes = make([]int, (mb.literal_split.num_types))
+ for i = 0; i < mb.literal_split.num_types; i++ {
+ literal_context_modes[i] = literal_context_mode
+ }
+ }
+
+ literal_histograms_size = mb.literal_split.num_types * literal_context_multiplier
+ literal_histograms = make([]histogramLiteral, literal_histograms_size)
+ clearHistogramsLiteral(literal_histograms, literal_histograms_size)
+
+ distance_histograms_size = mb.distance_split.num_types << distanceContextBits
+ distance_histograms = make([]histogramDistance, distance_histograms_size)
+ clearHistogramsDistance(distance_histograms, distance_histograms_size)
+
+ mb.command_histograms_size = mb.command_split.num_types
+ if cap(mb.command_histograms) < int(mb.command_histograms_size) {
+ mb.command_histograms = make([]histogramCommand, (mb.command_histograms_size))
+ } else {
+ mb.command_histograms = mb.command_histograms[:mb.command_histograms_size]
+ }
+ clearHistogramsCommand(mb.command_histograms, mb.command_histograms_size)
+
+ buildHistogramsWithContext(cmds, &mb.literal_split, &mb.command_split, &mb.distance_split, ringbuffer, pos, mask, prev_byte, prev_byte2, literal_context_modes, literal_histograms, mb.command_histograms, distance_histograms)
+ literal_context_modes = nil
+
+ mb.literal_context_map_size = mb.literal_split.num_types << literalContextBits
+ if cap(mb.literal_context_map) < int(mb.literal_context_map_size) {
+ mb.literal_context_map = make([]uint32, (mb.literal_context_map_size))
+ } else {
+ mb.literal_context_map = mb.literal_context_map[:mb.literal_context_map_size]
+ }
+
+ mb.literal_histograms_size = mb.literal_context_map_size
+ if cap(mb.literal_histograms) < int(mb.literal_histograms_size) {
+ mb.literal_histograms = make([]histogramLiteral, (mb.literal_histograms_size))
+ } else {
+ mb.literal_histograms = mb.literal_histograms[:mb.literal_histograms_size]
+ }
+
+ clusterHistogramsLiteral(literal_histograms, literal_histograms_size, buildMetaBlock_kMaxNumberOfHistograms, mb.literal_histograms, &mb.literal_histograms_size, mb.literal_context_map)
+ literal_histograms = nil
+
+ if params.disable_literal_context_modeling {
+ /* Distribute assignment to all contexts. */
+ for i = mb.literal_split.num_types; i != 0; {
+ var j uint = 0
+ i--
+ for ; j < 1< 0 {
+ var entropy [maxStaticContexts]float64
+ var combined_histo []histogramLiteral = make([]histogramLiteral, (2 * num_contexts))
+ var combined_entropy [2 * maxStaticContexts]float64
+ var diff = [2]float64{0.0}
+ /* Try merging the set of histograms for the current block type with the
+ respective set of histograms for the last and second last block types.
+ Decide over the split based on the total reduction of entropy across
+ all contexts. */
+
+ var i uint
+ for i = 0; i < num_contexts; i++ {
+ var curr_histo_ix uint = self.curr_histogram_ix_ + i
+ var j uint
+ entropy[i] = bitsEntropy(histograms[curr_histo_ix].data_[:], self.alphabet_size_)
+ for j = 0; j < 2; j++ {
+ var jx uint = j*num_contexts + i
+ var last_histogram_ix uint = self.last_histogram_ix_[j] + i
+ combined_histo[jx] = histograms[curr_histo_ix]
+ histogramAddHistogramLiteral(&combined_histo[jx], &histograms[last_histogram_ix])
+ combined_entropy[jx] = bitsEntropy(combined_histo[jx].data_[0:], self.alphabet_size_)
+ diff[j] += combined_entropy[jx] - entropy[i] - last_entropy[jx]
+ }
+ }
+
+ if split.num_types < self.max_block_types_ && diff[0] > self.split_threshold_ && diff[1] > self.split_threshold_ {
+ /* Create new block. */
+ split.lengths[self.num_blocks_] = uint32(self.block_size_)
+
+ split.types[self.num_blocks_] = byte(split.num_types)
+ self.last_histogram_ix_[1] = self.last_histogram_ix_[0]
+ self.last_histogram_ix_[0] = split.num_types * num_contexts
+ for i = 0; i < num_contexts; i++ {
+ last_entropy[num_contexts+i] = last_entropy[i]
+ last_entropy[i] = entropy[i]
+ }
+
+ self.num_blocks_++
+ split.num_types++
+ self.curr_histogram_ix_ += num_contexts
+ if self.curr_histogram_ix_ < *self.histograms_size_ {
+ clearHistogramsLiteral(self.histograms_[self.curr_histogram_ix_:], self.num_contexts_)
+ }
+
+ self.block_size_ = 0
+ self.merge_last_count_ = 0
+ self.target_block_size_ = self.min_block_size_
+ } else if diff[1] < diff[0]-20.0 {
+ split.lengths[self.num_blocks_] = uint32(self.block_size_)
+ split.types[self.num_blocks_] = split.types[self.num_blocks_-2]
+ /* Combine this block with second last block. */
+
+ var tmp uint = self.last_histogram_ix_[0]
+ self.last_histogram_ix_[0] = self.last_histogram_ix_[1]
+ self.last_histogram_ix_[1] = tmp
+ for i = 0; i < num_contexts; i++ {
+ histograms[self.last_histogram_ix_[0]+i] = combined_histo[num_contexts+i]
+ last_entropy[num_contexts+i] = last_entropy[i]
+ last_entropy[i] = combined_entropy[num_contexts+i]
+ histogramClearLiteral(&histograms[self.curr_histogram_ix_+i])
+ }
+
+ self.num_blocks_++
+ self.block_size_ = 0
+ self.merge_last_count_ = 0
+ self.target_block_size_ = self.min_block_size_
+ } else {
+ /* Combine this block with last block. */
+ split.lengths[self.num_blocks_-1] += uint32(self.block_size_)
+
+ for i = 0; i < num_contexts; i++ {
+ histograms[self.last_histogram_ix_[0]+i] = combined_histo[i]
+ last_entropy[i] = combined_entropy[i]
+ if split.num_types == 1 {
+ last_entropy[num_contexts+i] = last_entropy[i]
+ }
+
+ histogramClearLiteral(&histograms[self.curr_histogram_ix_+i])
+ }
+
+ self.block_size_ = 0
+ self.merge_last_count_++
+ if self.merge_last_count_ > 1 {
+ self.target_block_size_ += self.min_block_size_
+ }
+ }
+
+ combined_histo = nil
+ }
+
+ if is_final {
+ *self.histograms_size_ = split.num_types * num_contexts
+ split.num_blocks = self.num_blocks_
+ }
+}
+
+/* Adds the next symbol to the current block type and context. When the
+ current block reaches the target size, decides on merging the block. */
+func contextBlockSplitterAddSymbol(self *contextBlockSplitter, symbol uint, context uint) {
+ histogramAddLiteral(&self.histograms_[self.curr_histogram_ix_+context], symbol)
+ self.block_size_++
+ if self.block_size_ == self.target_block_size_ {
+ contextBlockSplitterFinishBlock(self, false) /* is_final = */
+ }
+}
+
+func mapStaticContexts(num_contexts uint, static_context_map []uint32, mb *metaBlockSplit) {
+ var i uint
+ mb.literal_context_map_size = mb.literal_split.num_types << literalContextBits
+ if cap(mb.literal_context_map) < int(mb.literal_context_map_size) {
+ mb.literal_context_map = make([]uint32, (mb.literal_context_map_size))
+ } else {
+ mb.literal_context_map = mb.literal_context_map[:mb.literal_context_map_size]
+ }
+
+ for i = 0; i < mb.literal_split.num_types; i++ {
+ var offset uint32 = uint32(i * num_contexts)
+ var j uint
+ for j = 0; j < 1<= 128 {
+ blockSplitterAddSymbolDistance(&dist_blocks, uint(cmd.dist_prefix_)&0x3FF)
+ }
+ }
+ }
+
+ if num_contexts == 1 {
+ blockSplitterFinishBlockLiteral(&lit_blocks.plain, true) /* is_final = */
+ } else {
+ contextBlockSplitterFinishBlock(&lit_blocks.ctx, true) /* is_final = */
+ }
+
+ blockSplitterFinishBlockCommand(&cmd_blocks, true) /* is_final = */
+ blockSplitterFinishBlockDistance(&dist_blocks, true) /* is_final = */
+
+ if num_contexts > 1 {
+ mapStaticContexts(num_contexts, static_context_map, mb)
+ }
+}
+
+func buildMetaBlockGreedy(ringbuffer []byte, pos uint, mask uint, prev_byte byte, prev_byte2 byte, literal_context_lut contextLUT, num_contexts uint, static_context_map []uint32, commands []command, mb *metaBlockSplit) {
+ if num_contexts == 1 {
+ buildMetaBlockGreedyInternal(ringbuffer, pos, mask, prev_byte, prev_byte2, literal_context_lut, 1, nil, commands, mb)
+ } else {
+ buildMetaBlockGreedyInternal(ringbuffer, pos, mask, prev_byte, prev_byte2, literal_context_lut, num_contexts, static_context_map, commands, mb)
+ }
+}
+
+func optimizeHistograms(num_distance_codes uint32, mb *metaBlockSplit) {
+ var good_for_rle [numCommandSymbols]byte
+ var i uint
+ for i = 0; i < mb.literal_histograms_size; i++ {
+ optimizeHuffmanCountsForRLE(256, mb.literal_histograms[i].data_[:], good_for_rle[:])
+ }
+
+ for i = 0; i < mb.command_histograms_size; i++ {
+ optimizeHuffmanCountsForRLE(numCommandSymbols, mb.command_histograms[i].data_[:], good_for_rle[:])
+ }
+
+ for i = 0; i < mb.distance_histograms_size; i++ {
+ optimizeHuffmanCountsForRLE(uint(num_distance_codes), mb.distance_histograms[i].data_[:], good_for_rle[:])
+ }
+}
diff --git a/vendor/github.com/andybalholm/brotli/metablock_command.go b/vendor/github.com/andybalholm/brotli/metablock_command.go
new file mode 100644
index 0000000..14c7b77
--- /dev/null
+++ b/vendor/github.com/andybalholm/brotli/metablock_command.go
@@ -0,0 +1,165 @@
+package brotli
+
+/* Copyright 2015 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Greedy block splitter for one block category (literal, command or distance).
+ */
+type blockSplitterCommand struct {
+ alphabet_size_ uint
+ min_block_size_ uint
+ split_threshold_ float64
+ num_blocks_ uint
+ split_ *blockSplit
+ histograms_ []histogramCommand
+ histograms_size_ *uint
+ target_block_size_ uint
+ block_size_ uint
+ curr_histogram_ix_ uint
+ last_histogram_ix_ [2]uint
+ last_entropy_ [2]float64
+ merge_last_count_ uint
+}
+
+func initBlockSplitterCommand(self *blockSplitterCommand, alphabet_size uint, min_block_size uint, split_threshold float64, num_symbols uint, split *blockSplit, histograms *[]histogramCommand, histograms_size *uint) {
+ var max_num_blocks uint = num_symbols/min_block_size + 1
+ var max_num_types uint = brotli_min_size_t(max_num_blocks, maxNumberOfBlockTypes+1)
+ /* We have to allocate one more histogram than the maximum number of block
+ types for the current histogram when the meta-block is too big. */
+ self.alphabet_size_ = alphabet_size
+
+ self.min_block_size_ = min_block_size
+ self.split_threshold_ = split_threshold
+ self.num_blocks_ = 0
+ self.split_ = split
+ self.histograms_size_ = histograms_size
+ self.target_block_size_ = min_block_size
+ self.block_size_ = 0
+ self.curr_histogram_ix_ = 0
+ self.merge_last_count_ = 0
+ brotli_ensure_capacity_uint8_t(&split.types, &split.types_alloc_size, max_num_blocks)
+ brotli_ensure_capacity_uint32_t(&split.lengths, &split.lengths_alloc_size, max_num_blocks)
+ self.split_.num_blocks = max_num_blocks
+ *histograms_size = max_num_types
+ if histograms == nil || cap(*histograms) < int(*histograms_size) {
+ *histograms = make([]histogramCommand, (*histograms_size))
+ } else {
+ *histograms = (*histograms)[:*histograms_size]
+ }
+ self.histograms_ = *histograms
+
+ /* Clear only current histogram. */
+ histogramClearCommand(&self.histograms_[0])
+
+ self.last_histogram_ix_[1] = 0
+ self.last_histogram_ix_[0] = self.last_histogram_ix_[1]
+}
+
+/* Does either of three things:
+ (1) emits the current block with a new block type;
+ (2) emits the current block with the type of the second last block;
+ (3) merges the current block with the last block. */
+func blockSplitterFinishBlockCommand(self *blockSplitterCommand, is_final bool) {
+ var split *blockSplit = self.split_
+ var last_entropy []float64 = self.last_entropy_[:]
+ var histograms []histogramCommand = self.histograms_
+ self.block_size_ = brotli_max_size_t(self.block_size_, self.min_block_size_)
+ if self.num_blocks_ == 0 {
+ /* Create first block. */
+ split.lengths[0] = uint32(self.block_size_)
+
+ split.types[0] = 0
+ last_entropy[0] = bitsEntropy(histograms[0].data_[:], self.alphabet_size_)
+ last_entropy[1] = last_entropy[0]
+ self.num_blocks_++
+ split.num_types++
+ self.curr_histogram_ix_++
+ if self.curr_histogram_ix_ < *self.histograms_size_ {
+ histogramClearCommand(&histograms[self.curr_histogram_ix_])
+ }
+ self.block_size_ = 0
+ } else if self.block_size_ > 0 {
+ var entropy float64 = bitsEntropy(histograms[self.curr_histogram_ix_].data_[:], self.alphabet_size_)
+ var combined_histo [2]histogramCommand
+ var combined_entropy [2]float64
+ var diff [2]float64
+ var j uint
+ for j = 0; j < 2; j++ {
+ var last_histogram_ix uint = self.last_histogram_ix_[j]
+ combined_histo[j] = histograms[self.curr_histogram_ix_]
+ histogramAddHistogramCommand(&combined_histo[j], &histograms[last_histogram_ix])
+ combined_entropy[j] = bitsEntropy(combined_histo[j].data_[0:], self.alphabet_size_)
+ diff[j] = combined_entropy[j] - entropy - last_entropy[j]
+ }
+
+ if split.num_types < maxNumberOfBlockTypes && diff[0] > self.split_threshold_ && diff[1] > self.split_threshold_ {
+ /* Create new block. */
+ split.lengths[self.num_blocks_] = uint32(self.block_size_)
+
+ split.types[self.num_blocks_] = byte(split.num_types)
+ self.last_histogram_ix_[1] = self.last_histogram_ix_[0]
+ self.last_histogram_ix_[0] = uint(byte(split.num_types))
+ last_entropy[1] = last_entropy[0]
+ last_entropy[0] = entropy
+ self.num_blocks_++
+ split.num_types++
+ self.curr_histogram_ix_++
+ if self.curr_histogram_ix_ < *self.histograms_size_ {
+ histogramClearCommand(&histograms[self.curr_histogram_ix_])
+ }
+ self.block_size_ = 0
+ self.merge_last_count_ = 0
+ self.target_block_size_ = self.min_block_size_
+ } else if diff[1] < diff[0]-20.0 {
+ split.lengths[self.num_blocks_] = uint32(self.block_size_)
+ split.types[self.num_blocks_] = split.types[self.num_blocks_-2]
+ /* Combine this block with second last block. */
+
+ var tmp uint = self.last_histogram_ix_[0]
+ self.last_histogram_ix_[0] = self.last_histogram_ix_[1]
+ self.last_histogram_ix_[1] = tmp
+ histograms[self.last_histogram_ix_[0]] = combined_histo[1]
+ last_entropy[1] = last_entropy[0]
+ last_entropy[0] = combined_entropy[1]
+ self.num_blocks_++
+ self.block_size_ = 0
+ histogramClearCommand(&histograms[self.curr_histogram_ix_])
+ self.merge_last_count_ = 0
+ self.target_block_size_ = self.min_block_size_
+ } else {
+ /* Combine this block with last block. */
+ split.lengths[self.num_blocks_-1] += uint32(self.block_size_)
+
+ histograms[self.last_histogram_ix_[0]] = combined_histo[0]
+ last_entropy[0] = combined_entropy[0]
+ if split.num_types == 1 {
+ last_entropy[1] = last_entropy[0]
+ }
+
+ self.block_size_ = 0
+ histogramClearCommand(&histograms[self.curr_histogram_ix_])
+ self.merge_last_count_++
+ if self.merge_last_count_ > 1 {
+ self.target_block_size_ += self.min_block_size_
+ }
+ }
+ }
+
+ if is_final {
+ *self.histograms_size_ = split.num_types
+ split.num_blocks = self.num_blocks_
+ }
+}
+
+/* Adds the next symbol to the current histogram. When the current histogram
+ reaches the target size, decides on merging the block. */
+func blockSplitterAddSymbolCommand(self *blockSplitterCommand, symbol uint) {
+ histogramAddCommand(&self.histograms_[self.curr_histogram_ix_], symbol)
+ self.block_size_++
+ if self.block_size_ == self.target_block_size_ {
+ blockSplitterFinishBlockCommand(self, false) /* is_final = */
+ }
+}
diff --git a/vendor/github.com/andybalholm/brotli/metablock_distance.go b/vendor/github.com/andybalholm/brotli/metablock_distance.go
new file mode 100644
index 0000000..5110a81
--- /dev/null
+++ b/vendor/github.com/andybalholm/brotli/metablock_distance.go
@@ -0,0 +1,165 @@
+package brotli
+
+/* Copyright 2015 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Greedy block splitter for one block category (literal, command or distance).
+ */
+type blockSplitterDistance struct {
+ alphabet_size_ uint
+ min_block_size_ uint
+ split_threshold_ float64
+ num_blocks_ uint
+ split_ *blockSplit
+ histograms_ []histogramDistance
+ histograms_size_ *uint
+ target_block_size_ uint
+ block_size_ uint
+ curr_histogram_ix_ uint
+ last_histogram_ix_ [2]uint
+ last_entropy_ [2]float64
+ merge_last_count_ uint
+}
+
+func initBlockSplitterDistance(self *blockSplitterDistance, alphabet_size uint, min_block_size uint, split_threshold float64, num_symbols uint, split *blockSplit, histograms *[]histogramDistance, histograms_size *uint) {
+ var max_num_blocks uint = num_symbols/min_block_size + 1
+ var max_num_types uint = brotli_min_size_t(max_num_blocks, maxNumberOfBlockTypes+1)
+ /* We have to allocate one more histogram than the maximum number of block
+ types for the current histogram when the meta-block is too big. */
+ self.alphabet_size_ = alphabet_size
+
+ self.min_block_size_ = min_block_size
+ self.split_threshold_ = split_threshold
+ self.num_blocks_ = 0
+ self.split_ = split
+ self.histograms_size_ = histograms_size
+ self.target_block_size_ = min_block_size
+ self.block_size_ = 0
+ self.curr_histogram_ix_ = 0
+ self.merge_last_count_ = 0
+ brotli_ensure_capacity_uint8_t(&split.types, &split.types_alloc_size, max_num_blocks)
+ brotli_ensure_capacity_uint32_t(&split.lengths, &split.lengths_alloc_size, max_num_blocks)
+ self.split_.num_blocks = max_num_blocks
+ *histograms_size = max_num_types
+ if histograms == nil || cap(*histograms) < int(*histograms_size) {
+ *histograms = make([]histogramDistance, *histograms_size)
+ } else {
+ *histograms = (*histograms)[:*histograms_size]
+ }
+ self.histograms_ = *histograms
+
+ /* Clear only current histogram. */
+ histogramClearDistance(&self.histograms_[0])
+
+ self.last_histogram_ix_[1] = 0
+ self.last_histogram_ix_[0] = self.last_histogram_ix_[1]
+}
+
+/* Does either of three things:
+ (1) emits the current block with a new block type;
+ (2) emits the current block with the type of the second last block;
+ (3) merges the current block with the last block. */
+func blockSplitterFinishBlockDistance(self *blockSplitterDistance, is_final bool) {
+ var split *blockSplit = self.split_
+ var last_entropy []float64 = self.last_entropy_[:]
+ var histograms []histogramDistance = self.histograms_
+ self.block_size_ = brotli_max_size_t(self.block_size_, self.min_block_size_)
+ if self.num_blocks_ == 0 {
+ /* Create first block. */
+ split.lengths[0] = uint32(self.block_size_)
+
+ split.types[0] = 0
+ last_entropy[0] = bitsEntropy(histograms[0].data_[:], self.alphabet_size_)
+ last_entropy[1] = last_entropy[0]
+ self.num_blocks_++
+ split.num_types++
+ self.curr_histogram_ix_++
+ if self.curr_histogram_ix_ < *self.histograms_size_ {
+ histogramClearDistance(&histograms[self.curr_histogram_ix_])
+ }
+ self.block_size_ = 0
+ } else if self.block_size_ > 0 {
+ var entropy float64 = bitsEntropy(histograms[self.curr_histogram_ix_].data_[:], self.alphabet_size_)
+ var combined_histo [2]histogramDistance
+ var combined_entropy [2]float64
+ var diff [2]float64
+ var j uint
+ for j = 0; j < 2; j++ {
+ var last_histogram_ix uint = self.last_histogram_ix_[j]
+ combined_histo[j] = histograms[self.curr_histogram_ix_]
+ histogramAddHistogramDistance(&combined_histo[j], &histograms[last_histogram_ix])
+ combined_entropy[j] = bitsEntropy(combined_histo[j].data_[0:], self.alphabet_size_)
+ diff[j] = combined_entropy[j] - entropy - last_entropy[j]
+ }
+
+ if split.num_types < maxNumberOfBlockTypes && diff[0] > self.split_threshold_ && diff[1] > self.split_threshold_ {
+ /* Create new block. */
+ split.lengths[self.num_blocks_] = uint32(self.block_size_)
+
+ split.types[self.num_blocks_] = byte(split.num_types)
+ self.last_histogram_ix_[1] = self.last_histogram_ix_[0]
+ self.last_histogram_ix_[0] = uint(byte(split.num_types))
+ last_entropy[1] = last_entropy[0]
+ last_entropy[0] = entropy
+ self.num_blocks_++
+ split.num_types++
+ self.curr_histogram_ix_++
+ if self.curr_histogram_ix_ < *self.histograms_size_ {
+ histogramClearDistance(&histograms[self.curr_histogram_ix_])
+ }
+ self.block_size_ = 0
+ self.merge_last_count_ = 0
+ self.target_block_size_ = self.min_block_size_
+ } else if diff[1] < diff[0]-20.0 {
+ split.lengths[self.num_blocks_] = uint32(self.block_size_)
+ split.types[self.num_blocks_] = split.types[self.num_blocks_-2]
+ /* Combine this block with second last block. */
+
+ var tmp uint = self.last_histogram_ix_[0]
+ self.last_histogram_ix_[0] = self.last_histogram_ix_[1]
+ self.last_histogram_ix_[1] = tmp
+ histograms[self.last_histogram_ix_[0]] = combined_histo[1]
+ last_entropy[1] = last_entropy[0]
+ last_entropy[0] = combined_entropy[1]
+ self.num_blocks_++
+ self.block_size_ = 0
+ histogramClearDistance(&histograms[self.curr_histogram_ix_])
+ self.merge_last_count_ = 0
+ self.target_block_size_ = self.min_block_size_
+ } else {
+ /* Combine this block with last block. */
+ split.lengths[self.num_blocks_-1] += uint32(self.block_size_)
+
+ histograms[self.last_histogram_ix_[0]] = combined_histo[0]
+ last_entropy[0] = combined_entropy[0]
+ if split.num_types == 1 {
+ last_entropy[1] = last_entropy[0]
+ }
+
+ self.block_size_ = 0
+ histogramClearDistance(&histograms[self.curr_histogram_ix_])
+ self.merge_last_count_++
+ if self.merge_last_count_ > 1 {
+ self.target_block_size_ += self.min_block_size_
+ }
+ }
+ }
+
+ if is_final {
+ *self.histograms_size_ = split.num_types
+ split.num_blocks = self.num_blocks_
+ }
+}
+
+/* Adds the next symbol to the current histogram. When the current histogram
+ reaches the target size, decides on merging the block. */
+func blockSplitterAddSymbolDistance(self *blockSplitterDistance, symbol uint) {
+ histogramAddDistance(&self.histograms_[self.curr_histogram_ix_], symbol)
+ self.block_size_++
+ if self.block_size_ == self.target_block_size_ {
+ blockSplitterFinishBlockDistance(self, false) /* is_final = */
+ }
+}
diff --git a/vendor/github.com/andybalholm/brotli/metablock_literal.go b/vendor/github.com/andybalholm/brotli/metablock_literal.go
new file mode 100644
index 0000000..307f8da
--- /dev/null
+++ b/vendor/github.com/andybalholm/brotli/metablock_literal.go
@@ -0,0 +1,165 @@
+package brotli
+
+/* Copyright 2015 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Greedy block splitter for one block category (literal, command or distance).
+ */
+type blockSplitterLiteral struct {
+ alphabet_size_ uint
+ min_block_size_ uint
+ split_threshold_ float64
+ num_blocks_ uint
+ split_ *blockSplit
+ histograms_ []histogramLiteral
+ histograms_size_ *uint
+ target_block_size_ uint
+ block_size_ uint
+ curr_histogram_ix_ uint
+ last_histogram_ix_ [2]uint
+ last_entropy_ [2]float64
+ merge_last_count_ uint
+}
+
+func initBlockSplitterLiteral(self *blockSplitterLiteral, alphabet_size uint, min_block_size uint, split_threshold float64, num_symbols uint, split *blockSplit, histograms *[]histogramLiteral, histograms_size *uint) {
+ var max_num_blocks uint = num_symbols/min_block_size + 1
+ var max_num_types uint = brotli_min_size_t(max_num_blocks, maxNumberOfBlockTypes+1)
+ /* We have to allocate one more histogram than the maximum number of block
+ types for the current histogram when the meta-block is too big. */
+ self.alphabet_size_ = alphabet_size
+
+ self.min_block_size_ = min_block_size
+ self.split_threshold_ = split_threshold
+ self.num_blocks_ = 0
+ self.split_ = split
+ self.histograms_size_ = histograms_size
+ self.target_block_size_ = min_block_size
+ self.block_size_ = 0
+ self.curr_histogram_ix_ = 0
+ self.merge_last_count_ = 0
+ brotli_ensure_capacity_uint8_t(&split.types, &split.types_alloc_size, max_num_blocks)
+ brotli_ensure_capacity_uint32_t(&split.lengths, &split.lengths_alloc_size, max_num_blocks)
+ self.split_.num_blocks = max_num_blocks
+ *histograms_size = max_num_types
+ if histograms == nil || cap(*histograms) < int(*histograms_size) {
+ *histograms = make([]histogramLiteral, *histograms_size)
+ } else {
+ *histograms = (*histograms)[:*histograms_size]
+ }
+ self.histograms_ = *histograms
+
+ /* Clear only current histogram. */
+ histogramClearLiteral(&self.histograms_[0])
+
+ self.last_histogram_ix_[1] = 0
+ self.last_histogram_ix_[0] = self.last_histogram_ix_[1]
+}
+
+/* Does either of three things:
+ (1) emits the current block with a new block type;
+ (2) emits the current block with the type of the second last block;
+ (3) merges the current block with the last block. */
+func blockSplitterFinishBlockLiteral(self *blockSplitterLiteral, is_final bool) {
+ var split *blockSplit = self.split_
+ var last_entropy []float64 = self.last_entropy_[:]
+ var histograms []histogramLiteral = self.histograms_
+ self.block_size_ = brotli_max_size_t(self.block_size_, self.min_block_size_)
+ if self.num_blocks_ == 0 {
+ /* Create first block. */
+ split.lengths[0] = uint32(self.block_size_)
+
+ split.types[0] = 0
+ last_entropy[0] = bitsEntropy(histograms[0].data_[:], self.alphabet_size_)
+ last_entropy[1] = last_entropy[0]
+ self.num_blocks_++
+ split.num_types++
+ self.curr_histogram_ix_++
+ if self.curr_histogram_ix_ < *self.histograms_size_ {
+ histogramClearLiteral(&histograms[self.curr_histogram_ix_])
+ }
+ self.block_size_ = 0
+ } else if self.block_size_ > 0 {
+ var entropy float64 = bitsEntropy(histograms[self.curr_histogram_ix_].data_[:], self.alphabet_size_)
+ var combined_histo [2]histogramLiteral
+ var combined_entropy [2]float64
+ var diff [2]float64
+ var j uint
+ for j = 0; j < 2; j++ {
+ var last_histogram_ix uint = self.last_histogram_ix_[j]
+ combined_histo[j] = histograms[self.curr_histogram_ix_]
+ histogramAddHistogramLiteral(&combined_histo[j], &histograms[last_histogram_ix])
+ combined_entropy[j] = bitsEntropy(combined_histo[j].data_[0:], self.alphabet_size_)
+ diff[j] = combined_entropy[j] - entropy - last_entropy[j]
+ }
+
+ if split.num_types < maxNumberOfBlockTypes && diff[0] > self.split_threshold_ && diff[1] > self.split_threshold_ {
+ /* Create new block. */
+ split.lengths[self.num_blocks_] = uint32(self.block_size_)
+
+ split.types[self.num_blocks_] = byte(split.num_types)
+ self.last_histogram_ix_[1] = self.last_histogram_ix_[0]
+ self.last_histogram_ix_[0] = uint(byte(split.num_types))
+ last_entropy[1] = last_entropy[0]
+ last_entropy[0] = entropy
+ self.num_blocks_++
+ split.num_types++
+ self.curr_histogram_ix_++
+ if self.curr_histogram_ix_ < *self.histograms_size_ {
+ histogramClearLiteral(&histograms[self.curr_histogram_ix_])
+ }
+ self.block_size_ = 0
+ self.merge_last_count_ = 0
+ self.target_block_size_ = self.min_block_size_
+ } else if diff[1] < diff[0]-20.0 {
+ split.lengths[self.num_blocks_] = uint32(self.block_size_)
+ split.types[self.num_blocks_] = split.types[self.num_blocks_-2]
+ /* Combine this block with second last block. */
+
+ var tmp uint = self.last_histogram_ix_[0]
+ self.last_histogram_ix_[0] = self.last_histogram_ix_[1]
+ self.last_histogram_ix_[1] = tmp
+ histograms[self.last_histogram_ix_[0]] = combined_histo[1]
+ last_entropy[1] = last_entropy[0]
+ last_entropy[0] = combined_entropy[1]
+ self.num_blocks_++
+ self.block_size_ = 0
+ histogramClearLiteral(&histograms[self.curr_histogram_ix_])
+ self.merge_last_count_ = 0
+ self.target_block_size_ = self.min_block_size_
+ } else {
+ /* Combine this block with last block. */
+ split.lengths[self.num_blocks_-1] += uint32(self.block_size_)
+
+ histograms[self.last_histogram_ix_[0]] = combined_histo[0]
+ last_entropy[0] = combined_entropy[0]
+ if split.num_types == 1 {
+ last_entropy[1] = last_entropy[0]
+ }
+
+ self.block_size_ = 0
+ histogramClearLiteral(&histograms[self.curr_histogram_ix_])
+ self.merge_last_count_++
+ if self.merge_last_count_ > 1 {
+ self.target_block_size_ += self.min_block_size_
+ }
+ }
+ }
+
+ if is_final {
+ *self.histograms_size_ = split.num_types
+ split.num_blocks = self.num_blocks_
+ }
+}
+
+/* Adds the next symbol to the current histogram. When the current histogram
+ reaches the target size, decides on merging the block. */
+func blockSplitterAddSymbolLiteral(self *blockSplitterLiteral, symbol uint) {
+ histogramAddLiteral(&self.histograms_[self.curr_histogram_ix_], symbol)
+ self.block_size_++
+ if self.block_size_ == self.target_block_size_ {
+ blockSplitterFinishBlockLiteral(self, false) /* is_final = */
+ }
+}
diff --git a/vendor/github.com/andybalholm/brotli/params.go b/vendor/github.com/andybalholm/brotli/params.go
new file mode 100644
index 0000000..0a4c687
--- /dev/null
+++ b/vendor/github.com/andybalholm/brotli/params.go
@@ -0,0 +1,37 @@
+package brotli
+
+/* Copyright 2017 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Parameters for the Brotli encoder with chosen quality levels. */
+type hasherParams struct {
+ type_ int
+ bucket_bits int
+ block_bits int
+ hash_len int
+ num_last_distances_to_check int
+}
+
+type distanceParams struct {
+ distance_postfix_bits uint32
+ num_direct_distance_codes uint32
+ alphabet_size uint32
+ max_distance uint
+}
+
+/* Encoding parameters */
+type encoderParams struct {
+ mode int
+ quality int
+ lgwin uint
+ lgblock int
+ size_hint uint
+ disable_literal_context_modeling bool
+ large_window bool
+ hasher hasherParams
+ dist distanceParams
+ dictionary encoderDictionary
+}
diff --git a/vendor/github.com/andybalholm/brotli/platform.go b/vendor/github.com/andybalholm/brotli/platform.go
new file mode 100644
index 0000000..4ebfb15
--- /dev/null
+++ b/vendor/github.com/andybalholm/brotli/platform.go
@@ -0,0 +1,103 @@
+package brotli
+
+/* Copyright 2013 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+func brotli_min_double(a float64, b float64) float64 {
+ if a < b {
+ return a
+ } else {
+ return b
+ }
+}
+
+func brotli_max_double(a float64, b float64) float64 {
+ if a > b {
+ return a
+ } else {
+ return b
+ }
+}
+
+func brotli_min_float(a float32, b float32) float32 {
+ if a < b {
+ return a
+ } else {
+ return b
+ }
+}
+
+func brotli_max_float(a float32, b float32) float32 {
+ if a > b {
+ return a
+ } else {
+ return b
+ }
+}
+
+func brotli_min_int(a int, b int) int {
+ if a < b {
+ return a
+ } else {
+ return b
+ }
+}
+
+func brotli_max_int(a int, b int) int {
+ if a > b {
+ return a
+ } else {
+ return b
+ }
+}
+
+func brotli_min_size_t(a uint, b uint) uint {
+ if a < b {
+ return a
+ } else {
+ return b
+ }
+}
+
+func brotli_max_size_t(a uint, b uint) uint {
+ if a > b {
+ return a
+ } else {
+ return b
+ }
+}
+
+func brotli_min_uint32_t(a uint32, b uint32) uint32 {
+ if a < b {
+ return a
+ } else {
+ return b
+ }
+}
+
+func brotli_max_uint32_t(a uint32, b uint32) uint32 {
+ if a > b {
+ return a
+ } else {
+ return b
+ }
+}
+
+func brotli_min_uint8_t(a byte, b byte) byte {
+ if a < b {
+ return a
+ } else {
+ return b
+ }
+}
+
+func brotli_max_uint8_t(a byte, b byte) byte {
+ if a > b {
+ return a
+ } else {
+ return b
+ }
+}
diff --git a/vendor/github.com/andybalholm/brotli/prefix.go b/vendor/github.com/andybalholm/brotli/prefix.go
new file mode 100644
index 0000000..484df0d
--- /dev/null
+++ b/vendor/github.com/andybalholm/brotli/prefix.go
@@ -0,0 +1,30 @@
+package brotli
+
+/* Copyright 2013 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Functions for encoding of integers into prefix codes the amount of extra
+ bits, and the actual values of the extra bits. */
+
+/* Here distance_code is an intermediate code, i.e. one of the special codes or
+ the actual distance increased by BROTLI_NUM_DISTANCE_SHORT_CODES - 1. */
+func prefixEncodeCopyDistance(distance_code uint, num_direct_codes uint, postfix_bits uint, code *uint16, extra_bits *uint32) {
+ if distance_code < numDistanceShortCodes+num_direct_codes {
+ *code = uint16(distance_code)
+ *extra_bits = 0
+ return
+ } else {
+ var dist uint = (uint(1) << (postfix_bits + 2)) + (distance_code - numDistanceShortCodes - num_direct_codes)
+ var bucket uint = uint(log2FloorNonZero(dist) - 1)
+ var postfix_mask uint = (1 << postfix_bits) - 1
+ var postfix uint = dist & postfix_mask
+ var prefix uint = (dist >> bucket) & 1
+ var offset uint = (2 + prefix) << bucket
+ var nbits uint = bucket - postfix_bits
+ *code = uint16(nbits<<10 | (numDistanceShortCodes + num_direct_codes + ((2*(nbits-1) + prefix) << postfix_bits) + postfix))
+ *extra_bits = uint32((dist - offset) >> postfix_bits)
+ }
+}
diff --git a/vendor/github.com/andybalholm/brotli/prefix_dec.go b/vendor/github.com/andybalholm/brotli/prefix_dec.go
new file mode 100644
index 0000000..183f0d5
--- /dev/null
+++ b/vendor/github.com/andybalholm/brotli/prefix_dec.go
@@ -0,0 +1,723 @@
+package brotli
+
+/* Copyright 2013 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+type cmdLutElement struct {
+ insert_len_extra_bits byte
+ copy_len_extra_bits byte
+ distance_code int8
+ context byte
+ insert_len_offset uint16
+ copy_len_offset uint16
+}
+
+var kCmdLut = [numCommandSymbols]cmdLutElement{
+ cmdLutElement{0x00, 0x00, 0, 0x00, 0x0000, 0x0002},
+ cmdLutElement{0x00, 0x00, 0, 0x01, 0x0000, 0x0003},
+ cmdLutElement{0x00, 0x00, 0, 0x02, 0x0000, 0x0004},
+ cmdLutElement{0x00, 0x00, 0, 0x03, 0x0000, 0x0005},
+ cmdLutElement{0x00, 0x00, 0, 0x03, 0x0000, 0x0006},
+ cmdLutElement{0x00, 0x00, 0, 0x03, 0x0000, 0x0007},
+ cmdLutElement{0x00, 0x00, 0, 0x03, 0x0000, 0x0008},
+ cmdLutElement{0x00, 0x00, 0, 0x03, 0x0000, 0x0009},
+ cmdLutElement{0x00, 0x00, 0, 0x00, 0x0001, 0x0002},
+ cmdLutElement{0x00, 0x00, 0, 0x01, 0x0001, 0x0003},
+ cmdLutElement{0x00, 0x00, 0, 0x02, 0x0001, 0x0004},
+ cmdLutElement{0x00, 0x00, 0, 0x03, 0x0001, 0x0005},
+ cmdLutElement{0x00, 0x00, 0, 0x03, 0x0001, 0x0006},
+ cmdLutElement{0x00, 0x00, 0, 0x03, 0x0001, 0x0007},
+ cmdLutElement{0x00, 0x00, 0, 0x03, 0x0001, 0x0008},
+ cmdLutElement{0x00, 0x00, 0, 0x03, 0x0001, 0x0009},
+ cmdLutElement{0x00, 0x00, 0, 0x00, 0x0002, 0x0002},
+ cmdLutElement{0x00, 0x00, 0, 0x01, 0x0002, 0x0003},
+ cmdLutElement{0x00, 0x00, 0, 0x02, 0x0002, 0x0004},
+ cmdLutElement{0x00, 0x00, 0, 0x03, 0x0002, 0x0005},
+ cmdLutElement{0x00, 0x00, 0, 0x03, 0x0002, 0x0006},
+ cmdLutElement{0x00, 0x00, 0, 0x03, 0x0002, 0x0007},
+ cmdLutElement{0x00, 0x00, 0, 0x03, 0x0002, 0x0008},
+ cmdLutElement{0x00, 0x00, 0, 0x03, 0x0002, 0x0009},
+ cmdLutElement{0x00, 0x00, 0, 0x00, 0x0003, 0x0002},
+ cmdLutElement{0x00, 0x00, 0, 0x01, 0x0003, 0x0003},
+ cmdLutElement{0x00, 0x00, 0, 0x02, 0x0003, 0x0004},
+ cmdLutElement{0x00, 0x00, 0, 0x03, 0x0003, 0x0005},
+ cmdLutElement{0x00, 0x00, 0, 0x03, 0x0003, 0x0006},
+ cmdLutElement{0x00, 0x00, 0, 0x03, 0x0003, 0x0007},
+ cmdLutElement{0x00, 0x00, 0, 0x03, 0x0003, 0x0008},
+ cmdLutElement{0x00, 0x00, 0, 0x03, 0x0003, 0x0009},
+ cmdLutElement{0x00, 0x00, 0, 0x00, 0x0004, 0x0002},
+ cmdLutElement{0x00, 0x00, 0, 0x01, 0x0004, 0x0003},
+ cmdLutElement{0x00, 0x00, 0, 0x02, 0x0004, 0x0004},
+ cmdLutElement{0x00, 0x00, 0, 0x03, 0x0004, 0x0005},
+ cmdLutElement{0x00, 0x00, 0, 0x03, 0x0004, 0x0006},
+ cmdLutElement{0x00, 0x00, 0, 0x03, 0x0004, 0x0007},
+ cmdLutElement{0x00, 0x00, 0, 0x03, 0x0004, 0x0008},
+ cmdLutElement{0x00, 0x00, 0, 0x03, 0x0004, 0x0009},
+ cmdLutElement{0x00, 0x00, 0, 0x00, 0x0005, 0x0002},
+ cmdLutElement{0x00, 0x00, 0, 0x01, 0x0005, 0x0003},
+ cmdLutElement{0x00, 0x00, 0, 0x02, 0x0005, 0x0004},
+ cmdLutElement{0x00, 0x00, 0, 0x03, 0x0005, 0x0005},
+ cmdLutElement{0x00, 0x00, 0, 0x03, 0x0005, 0x0006},
+ cmdLutElement{0x00, 0x00, 0, 0x03, 0x0005, 0x0007},
+ cmdLutElement{0x00, 0x00, 0, 0x03, 0x0005, 0x0008},
+ cmdLutElement{0x00, 0x00, 0, 0x03, 0x0005, 0x0009},
+ cmdLutElement{0x01, 0x00, 0, 0x00, 0x0006, 0x0002},
+ cmdLutElement{0x01, 0x00, 0, 0x01, 0x0006, 0x0003},
+ cmdLutElement{0x01, 0x00, 0, 0x02, 0x0006, 0x0004},
+ cmdLutElement{0x01, 0x00, 0, 0x03, 0x0006, 0x0005},
+ cmdLutElement{0x01, 0x00, 0, 0x03, 0x0006, 0x0006},
+ cmdLutElement{0x01, 0x00, 0, 0x03, 0x0006, 0x0007},
+ cmdLutElement{0x01, 0x00, 0, 0x03, 0x0006, 0x0008},
+ cmdLutElement{0x01, 0x00, 0, 0x03, 0x0006, 0x0009},
+ cmdLutElement{0x01, 0x00, 0, 0x00, 0x0008, 0x0002},
+ cmdLutElement{0x01, 0x00, 0, 0x01, 0x0008, 0x0003},
+ cmdLutElement{0x01, 0x00, 0, 0x02, 0x0008, 0x0004},
+ cmdLutElement{0x01, 0x00, 0, 0x03, 0x0008, 0x0005},
+ cmdLutElement{0x01, 0x00, 0, 0x03, 0x0008, 0x0006},
+ cmdLutElement{0x01, 0x00, 0, 0x03, 0x0008, 0x0007},
+ cmdLutElement{0x01, 0x00, 0, 0x03, 0x0008, 0x0008},
+ cmdLutElement{0x01, 0x00, 0, 0x03, 0x0008, 0x0009},
+ cmdLutElement{0x00, 0x01, 0, 0x03, 0x0000, 0x000a},
+ cmdLutElement{0x00, 0x01, 0, 0x03, 0x0000, 0x000c},
+ cmdLutElement{0x00, 0x02, 0, 0x03, 0x0000, 0x000e},
+ cmdLutElement{0x00, 0x02, 0, 0x03, 0x0000, 0x0012},
+ cmdLutElement{0x00, 0x03, 0, 0x03, 0x0000, 0x0016},
+ cmdLutElement{0x00, 0x03, 0, 0x03, 0x0000, 0x001e},
+ cmdLutElement{0x00, 0x04, 0, 0x03, 0x0000, 0x0026},
+ cmdLutElement{0x00, 0x04, 0, 0x03, 0x0000, 0x0036},
+ cmdLutElement{0x00, 0x01, 0, 0x03, 0x0001, 0x000a},
+ cmdLutElement{0x00, 0x01, 0, 0x03, 0x0001, 0x000c},
+ cmdLutElement{0x00, 0x02, 0, 0x03, 0x0001, 0x000e},
+ cmdLutElement{0x00, 0x02, 0, 0x03, 0x0001, 0x0012},
+ cmdLutElement{0x00, 0x03, 0, 0x03, 0x0001, 0x0016},
+ cmdLutElement{0x00, 0x03, 0, 0x03, 0x0001, 0x001e},
+ cmdLutElement{0x00, 0x04, 0, 0x03, 0x0001, 0x0026},
+ cmdLutElement{0x00, 0x04, 0, 0x03, 0x0001, 0x0036},
+ cmdLutElement{0x00, 0x01, 0, 0x03, 0x0002, 0x000a},
+ cmdLutElement{0x00, 0x01, 0, 0x03, 0x0002, 0x000c},
+ cmdLutElement{0x00, 0x02, 0, 0x03, 0x0002, 0x000e},
+ cmdLutElement{0x00, 0x02, 0, 0x03, 0x0002, 0x0012},
+ cmdLutElement{0x00, 0x03, 0, 0x03, 0x0002, 0x0016},
+ cmdLutElement{0x00, 0x03, 0, 0x03, 0x0002, 0x001e},
+ cmdLutElement{0x00, 0x04, 0, 0x03, 0x0002, 0x0026},
+ cmdLutElement{0x00, 0x04, 0, 0x03, 0x0002, 0x0036},
+ cmdLutElement{0x00, 0x01, 0, 0x03, 0x0003, 0x000a},
+ cmdLutElement{0x00, 0x01, 0, 0x03, 0x0003, 0x000c},
+ cmdLutElement{0x00, 0x02, 0, 0x03, 0x0003, 0x000e},
+ cmdLutElement{0x00, 0x02, 0, 0x03, 0x0003, 0x0012},
+ cmdLutElement{0x00, 0x03, 0, 0x03, 0x0003, 0x0016},
+ cmdLutElement{0x00, 0x03, 0, 0x03, 0x0003, 0x001e},
+ cmdLutElement{0x00, 0x04, 0, 0x03, 0x0003, 0x0026},
+ cmdLutElement{0x00, 0x04, 0, 0x03, 0x0003, 0x0036},
+ cmdLutElement{0x00, 0x01, 0, 0x03, 0x0004, 0x000a},
+ cmdLutElement{0x00, 0x01, 0, 0x03, 0x0004, 0x000c},
+ cmdLutElement{0x00, 0x02, 0, 0x03, 0x0004, 0x000e},
+ cmdLutElement{0x00, 0x02, 0, 0x03, 0x0004, 0x0012},
+ cmdLutElement{0x00, 0x03, 0, 0x03, 0x0004, 0x0016},
+ cmdLutElement{0x00, 0x03, 0, 0x03, 0x0004, 0x001e},
+ cmdLutElement{0x00, 0x04, 0, 0x03, 0x0004, 0x0026},
+ cmdLutElement{0x00, 0x04, 0, 0x03, 0x0004, 0x0036},
+ cmdLutElement{0x00, 0x01, 0, 0x03, 0x0005, 0x000a},
+ cmdLutElement{0x00, 0x01, 0, 0x03, 0x0005, 0x000c},
+ cmdLutElement{0x00, 0x02, 0, 0x03, 0x0005, 0x000e},
+ cmdLutElement{0x00, 0x02, 0, 0x03, 0x0005, 0x0012},
+ cmdLutElement{0x00, 0x03, 0, 0x03, 0x0005, 0x0016},
+ cmdLutElement{0x00, 0x03, 0, 0x03, 0x0005, 0x001e},
+ cmdLutElement{0x00, 0x04, 0, 0x03, 0x0005, 0x0026},
+ cmdLutElement{0x00, 0x04, 0, 0x03, 0x0005, 0x0036},
+ cmdLutElement{0x01, 0x01, 0, 0x03, 0x0006, 0x000a},
+ cmdLutElement{0x01, 0x01, 0, 0x03, 0x0006, 0x000c},
+ cmdLutElement{0x01, 0x02, 0, 0x03, 0x0006, 0x000e},
+ cmdLutElement{0x01, 0x02, 0, 0x03, 0x0006, 0x0012},
+ cmdLutElement{0x01, 0x03, 0, 0x03, 0x0006, 0x0016},
+ cmdLutElement{0x01, 0x03, 0, 0x03, 0x0006, 0x001e},
+ cmdLutElement{0x01, 0x04, 0, 0x03, 0x0006, 0x0026},
+ cmdLutElement{0x01, 0x04, 0, 0x03, 0x0006, 0x0036},
+ cmdLutElement{0x01, 0x01, 0, 0x03, 0x0008, 0x000a},
+ cmdLutElement{0x01, 0x01, 0, 0x03, 0x0008, 0x000c},
+ cmdLutElement{0x01, 0x02, 0, 0x03, 0x0008, 0x000e},
+ cmdLutElement{0x01, 0x02, 0, 0x03, 0x0008, 0x0012},
+ cmdLutElement{0x01, 0x03, 0, 0x03, 0x0008, 0x0016},
+ cmdLutElement{0x01, 0x03, 0, 0x03, 0x0008, 0x001e},
+ cmdLutElement{0x01, 0x04, 0, 0x03, 0x0008, 0x0026},
+ cmdLutElement{0x01, 0x04, 0, 0x03, 0x0008, 0x0036},
+ cmdLutElement{0x00, 0x00, -1, 0x00, 0x0000, 0x0002},
+ cmdLutElement{0x00, 0x00, -1, 0x01, 0x0000, 0x0003},
+ cmdLutElement{0x00, 0x00, -1, 0x02, 0x0000, 0x0004},
+ cmdLutElement{0x00, 0x00, -1, 0x03, 0x0000, 0x0005},
+ cmdLutElement{0x00, 0x00, -1, 0x03, 0x0000, 0x0006},
+ cmdLutElement{0x00, 0x00, -1, 0x03, 0x0000, 0x0007},
+ cmdLutElement{0x00, 0x00, -1, 0x03, 0x0000, 0x0008},
+ cmdLutElement{0x00, 0x00, -1, 0x03, 0x0000, 0x0009},
+ cmdLutElement{0x00, 0x00, -1, 0x00, 0x0001, 0x0002},
+ cmdLutElement{0x00, 0x00, -1, 0x01, 0x0001, 0x0003},
+ cmdLutElement{0x00, 0x00, -1, 0x02, 0x0001, 0x0004},
+ cmdLutElement{0x00, 0x00, -1, 0x03, 0x0001, 0x0005},
+ cmdLutElement{0x00, 0x00, -1, 0x03, 0x0001, 0x0006},
+ cmdLutElement{0x00, 0x00, -1, 0x03, 0x0001, 0x0007},
+ cmdLutElement{0x00, 0x00, -1, 0x03, 0x0001, 0x0008},
+ cmdLutElement{0x00, 0x00, -1, 0x03, 0x0001, 0x0009},
+ cmdLutElement{0x00, 0x00, -1, 0x00, 0x0002, 0x0002},
+ cmdLutElement{0x00, 0x00, -1, 0x01, 0x0002, 0x0003},
+ cmdLutElement{0x00, 0x00, -1, 0x02, 0x0002, 0x0004},
+ cmdLutElement{0x00, 0x00, -1, 0x03, 0x0002, 0x0005},
+ cmdLutElement{0x00, 0x00, -1, 0x03, 0x0002, 0x0006},
+ cmdLutElement{0x00, 0x00, -1, 0x03, 0x0002, 0x0007},
+ cmdLutElement{0x00, 0x00, -1, 0x03, 0x0002, 0x0008},
+ cmdLutElement{0x00, 0x00, -1, 0x03, 0x0002, 0x0009},
+ cmdLutElement{0x00, 0x00, -1, 0x00, 0x0003, 0x0002},
+ cmdLutElement{0x00, 0x00, -1, 0x01, 0x0003, 0x0003},
+ cmdLutElement{0x00, 0x00, -1, 0x02, 0x0003, 0x0004},
+ cmdLutElement{0x00, 0x00, -1, 0x03, 0x0003, 0x0005},
+ cmdLutElement{0x00, 0x00, -1, 0x03, 0x0003, 0x0006},
+ cmdLutElement{0x00, 0x00, -1, 0x03, 0x0003, 0x0007},
+ cmdLutElement{0x00, 0x00, -1, 0x03, 0x0003, 0x0008},
+ cmdLutElement{0x00, 0x00, -1, 0x03, 0x0003, 0x0009},
+ cmdLutElement{0x00, 0x00, -1, 0x00, 0x0004, 0x0002},
+ cmdLutElement{0x00, 0x00, -1, 0x01, 0x0004, 0x0003},
+ cmdLutElement{0x00, 0x00, -1, 0x02, 0x0004, 0x0004},
+ cmdLutElement{0x00, 0x00, -1, 0x03, 0x0004, 0x0005},
+ cmdLutElement{0x00, 0x00, -1, 0x03, 0x0004, 0x0006},
+ cmdLutElement{0x00, 0x00, -1, 0x03, 0x0004, 0x0007},
+ cmdLutElement{0x00, 0x00, -1, 0x03, 0x0004, 0x0008},
+ cmdLutElement{0x00, 0x00, -1, 0x03, 0x0004, 0x0009},
+ cmdLutElement{0x00, 0x00, -1, 0x00, 0x0005, 0x0002},
+ cmdLutElement{0x00, 0x00, -1, 0x01, 0x0005, 0x0003},
+ cmdLutElement{0x00, 0x00, -1, 0x02, 0x0005, 0x0004},
+ cmdLutElement{0x00, 0x00, -1, 0x03, 0x0005, 0x0005},
+ cmdLutElement{0x00, 0x00, -1, 0x03, 0x0005, 0x0006},
+ cmdLutElement{0x00, 0x00, -1, 0x03, 0x0005, 0x0007},
+ cmdLutElement{0x00, 0x00, -1, 0x03, 0x0005, 0x0008},
+ cmdLutElement{0x00, 0x00, -1, 0x03, 0x0005, 0x0009},
+ cmdLutElement{0x01, 0x00, -1, 0x00, 0x0006, 0x0002},
+ cmdLutElement{0x01, 0x00, -1, 0x01, 0x0006, 0x0003},
+ cmdLutElement{0x01, 0x00, -1, 0x02, 0x0006, 0x0004},
+ cmdLutElement{0x01, 0x00, -1, 0x03, 0x0006, 0x0005},
+ cmdLutElement{0x01, 0x00, -1, 0x03, 0x0006, 0x0006},
+ cmdLutElement{0x01, 0x00, -1, 0x03, 0x0006, 0x0007},
+ cmdLutElement{0x01, 0x00, -1, 0x03, 0x0006, 0x0008},
+ cmdLutElement{0x01, 0x00, -1, 0x03, 0x0006, 0x0009},
+ cmdLutElement{0x01, 0x00, -1, 0x00, 0x0008, 0x0002},
+ cmdLutElement{0x01, 0x00, -1, 0x01, 0x0008, 0x0003},
+ cmdLutElement{0x01, 0x00, -1, 0x02, 0x0008, 0x0004},
+ cmdLutElement{0x01, 0x00, -1, 0x03, 0x0008, 0x0005},
+ cmdLutElement{0x01, 0x00, -1, 0x03, 0x0008, 0x0006},
+ cmdLutElement{0x01, 0x00, -1, 0x03, 0x0008, 0x0007},
+ cmdLutElement{0x01, 0x00, -1, 0x03, 0x0008, 0x0008},
+ cmdLutElement{0x01, 0x00, -1, 0x03, 0x0008, 0x0009},
+ cmdLutElement{0x00, 0x01, -1, 0x03, 0x0000, 0x000a},
+ cmdLutElement{0x00, 0x01, -1, 0x03, 0x0000, 0x000c},
+ cmdLutElement{0x00, 0x02, -1, 0x03, 0x0000, 0x000e},
+ cmdLutElement{0x00, 0x02, -1, 0x03, 0x0000, 0x0012},
+ cmdLutElement{0x00, 0x03, -1, 0x03, 0x0000, 0x0016},
+ cmdLutElement{0x00, 0x03, -1, 0x03, 0x0000, 0x001e},
+ cmdLutElement{0x00, 0x04, -1, 0x03, 0x0000, 0x0026},
+ cmdLutElement{0x00, 0x04, -1, 0x03, 0x0000, 0x0036},
+ cmdLutElement{0x00, 0x01, -1, 0x03, 0x0001, 0x000a},
+ cmdLutElement{0x00, 0x01, -1, 0x03, 0x0001, 0x000c},
+ cmdLutElement{0x00, 0x02, -1, 0x03, 0x0001, 0x000e},
+ cmdLutElement{0x00, 0x02, -1, 0x03, 0x0001, 0x0012},
+ cmdLutElement{0x00, 0x03, -1, 0x03, 0x0001, 0x0016},
+ cmdLutElement{0x00, 0x03, -1, 0x03, 0x0001, 0x001e},
+ cmdLutElement{0x00, 0x04, -1, 0x03, 0x0001, 0x0026},
+ cmdLutElement{0x00, 0x04, -1, 0x03, 0x0001, 0x0036},
+ cmdLutElement{0x00, 0x01, -1, 0x03, 0x0002, 0x000a},
+ cmdLutElement{0x00, 0x01, -1, 0x03, 0x0002, 0x000c},
+ cmdLutElement{0x00, 0x02, -1, 0x03, 0x0002, 0x000e},
+ cmdLutElement{0x00, 0x02, -1, 0x03, 0x0002, 0x0012},
+ cmdLutElement{0x00, 0x03, -1, 0x03, 0x0002, 0x0016},
+ cmdLutElement{0x00, 0x03, -1, 0x03, 0x0002, 0x001e},
+ cmdLutElement{0x00, 0x04, -1, 0x03, 0x0002, 0x0026},
+ cmdLutElement{0x00, 0x04, -1, 0x03, 0x0002, 0x0036},
+ cmdLutElement{0x00, 0x01, -1, 0x03, 0x0003, 0x000a},
+ cmdLutElement{0x00, 0x01, -1, 0x03, 0x0003, 0x000c},
+ cmdLutElement{0x00, 0x02, -1, 0x03, 0x0003, 0x000e},
+ cmdLutElement{0x00, 0x02, -1, 0x03, 0x0003, 0x0012},
+ cmdLutElement{0x00, 0x03, -1, 0x03, 0x0003, 0x0016},
+ cmdLutElement{0x00, 0x03, -1, 0x03, 0x0003, 0x001e},
+ cmdLutElement{0x00, 0x04, -1, 0x03, 0x0003, 0x0026},
+ cmdLutElement{0x00, 0x04, -1, 0x03, 0x0003, 0x0036},
+ cmdLutElement{0x00, 0x01, -1, 0x03, 0x0004, 0x000a},
+ cmdLutElement{0x00, 0x01, -1, 0x03, 0x0004, 0x000c},
+ cmdLutElement{0x00, 0x02, -1, 0x03, 0x0004, 0x000e},
+ cmdLutElement{0x00, 0x02, -1, 0x03, 0x0004, 0x0012},
+ cmdLutElement{0x00, 0x03, -1, 0x03, 0x0004, 0x0016},
+ cmdLutElement{0x00, 0x03, -1, 0x03, 0x0004, 0x001e},
+ cmdLutElement{0x00, 0x04, -1, 0x03, 0x0004, 0x0026},
+ cmdLutElement{0x00, 0x04, -1, 0x03, 0x0004, 0x0036},
+ cmdLutElement{0x00, 0x01, -1, 0x03, 0x0005, 0x000a},
+ cmdLutElement{0x00, 0x01, -1, 0x03, 0x0005, 0x000c},
+ cmdLutElement{0x00, 0x02, -1, 0x03, 0x0005, 0x000e},
+ cmdLutElement{0x00, 0x02, -1, 0x03, 0x0005, 0x0012},
+ cmdLutElement{0x00, 0x03, -1, 0x03, 0x0005, 0x0016},
+ cmdLutElement{0x00, 0x03, -1, 0x03, 0x0005, 0x001e},
+ cmdLutElement{0x00, 0x04, -1, 0x03, 0x0005, 0x0026},
+ cmdLutElement{0x00, 0x04, -1, 0x03, 0x0005, 0x0036},
+ cmdLutElement{0x01, 0x01, -1, 0x03, 0x0006, 0x000a},
+ cmdLutElement{0x01, 0x01, -1, 0x03, 0x0006, 0x000c},
+ cmdLutElement{0x01, 0x02, -1, 0x03, 0x0006, 0x000e},
+ cmdLutElement{0x01, 0x02, -1, 0x03, 0x0006, 0x0012},
+ cmdLutElement{0x01, 0x03, -1, 0x03, 0x0006, 0x0016},
+ cmdLutElement{0x01, 0x03, -1, 0x03, 0x0006, 0x001e},
+ cmdLutElement{0x01, 0x04, -1, 0x03, 0x0006, 0x0026},
+ cmdLutElement{0x01, 0x04, -1, 0x03, 0x0006, 0x0036},
+ cmdLutElement{0x01, 0x01, -1, 0x03, 0x0008, 0x000a},
+ cmdLutElement{0x01, 0x01, -1, 0x03, 0x0008, 0x000c},
+ cmdLutElement{0x01, 0x02, -1, 0x03, 0x0008, 0x000e},
+ cmdLutElement{0x01, 0x02, -1, 0x03, 0x0008, 0x0012},
+ cmdLutElement{0x01, 0x03, -1, 0x03, 0x0008, 0x0016},
+ cmdLutElement{0x01, 0x03, -1, 0x03, 0x0008, 0x001e},
+ cmdLutElement{0x01, 0x04, -1, 0x03, 0x0008, 0x0026},
+ cmdLutElement{0x01, 0x04, -1, 0x03, 0x0008, 0x0036},
+ cmdLutElement{0x02, 0x00, -1, 0x00, 0x000a, 0x0002},
+ cmdLutElement{0x02, 0x00, -1, 0x01, 0x000a, 0x0003},
+ cmdLutElement{0x02, 0x00, -1, 0x02, 0x000a, 0x0004},
+ cmdLutElement{0x02, 0x00, -1, 0x03, 0x000a, 0x0005},
+ cmdLutElement{0x02, 0x00, -1, 0x03, 0x000a, 0x0006},
+ cmdLutElement{0x02, 0x00, -1, 0x03, 0x000a, 0x0007},
+ cmdLutElement{0x02, 0x00, -1, 0x03, 0x000a, 0x0008},
+ cmdLutElement{0x02, 0x00, -1, 0x03, 0x000a, 0x0009},
+ cmdLutElement{0x02, 0x00, -1, 0x00, 0x000e, 0x0002},
+ cmdLutElement{0x02, 0x00, -1, 0x01, 0x000e, 0x0003},
+ cmdLutElement{0x02, 0x00, -1, 0x02, 0x000e, 0x0004},
+ cmdLutElement{0x02, 0x00, -1, 0x03, 0x000e, 0x0005},
+ cmdLutElement{0x02, 0x00, -1, 0x03, 0x000e, 0x0006},
+ cmdLutElement{0x02, 0x00, -1, 0x03, 0x000e, 0x0007},
+ cmdLutElement{0x02, 0x00, -1, 0x03, 0x000e, 0x0008},
+ cmdLutElement{0x02, 0x00, -1, 0x03, 0x000e, 0x0009},
+ cmdLutElement{0x03, 0x00, -1, 0x00, 0x0012, 0x0002},
+ cmdLutElement{0x03, 0x00, -1, 0x01, 0x0012, 0x0003},
+ cmdLutElement{0x03, 0x00, -1, 0x02, 0x0012, 0x0004},
+ cmdLutElement{0x03, 0x00, -1, 0x03, 0x0012, 0x0005},
+ cmdLutElement{0x03, 0x00, -1, 0x03, 0x0012, 0x0006},
+ cmdLutElement{0x03, 0x00, -1, 0x03, 0x0012, 0x0007},
+ cmdLutElement{0x03, 0x00, -1, 0x03, 0x0012, 0x0008},
+ cmdLutElement{0x03, 0x00, -1, 0x03, 0x0012, 0x0009},
+ cmdLutElement{0x03, 0x00, -1, 0x00, 0x001a, 0x0002},
+ cmdLutElement{0x03, 0x00, -1, 0x01, 0x001a, 0x0003},
+ cmdLutElement{0x03, 0x00, -1, 0x02, 0x001a, 0x0004},
+ cmdLutElement{0x03, 0x00, -1, 0x03, 0x001a, 0x0005},
+ cmdLutElement{0x03, 0x00, -1, 0x03, 0x001a, 0x0006},
+ cmdLutElement{0x03, 0x00, -1, 0x03, 0x001a, 0x0007},
+ cmdLutElement{0x03, 0x00, -1, 0x03, 0x001a, 0x0008},
+ cmdLutElement{0x03, 0x00, -1, 0x03, 0x001a, 0x0009},
+ cmdLutElement{0x04, 0x00, -1, 0x00, 0x0022, 0x0002},
+ cmdLutElement{0x04, 0x00, -1, 0x01, 0x0022, 0x0003},
+ cmdLutElement{0x04, 0x00, -1, 0x02, 0x0022, 0x0004},
+ cmdLutElement{0x04, 0x00, -1, 0x03, 0x0022, 0x0005},
+ cmdLutElement{0x04, 0x00, -1, 0x03, 0x0022, 0x0006},
+ cmdLutElement{0x04, 0x00, -1, 0x03, 0x0022, 0x0007},
+ cmdLutElement{0x04, 0x00, -1, 0x03, 0x0022, 0x0008},
+ cmdLutElement{0x04, 0x00, -1, 0x03, 0x0022, 0x0009},
+ cmdLutElement{0x04, 0x00, -1, 0x00, 0x0032, 0x0002},
+ cmdLutElement{0x04, 0x00, -1, 0x01, 0x0032, 0x0003},
+ cmdLutElement{0x04, 0x00, -1, 0x02, 0x0032, 0x0004},
+ cmdLutElement{0x04, 0x00, -1, 0x03, 0x0032, 0x0005},
+ cmdLutElement{0x04, 0x00, -1, 0x03, 0x0032, 0x0006},
+ cmdLutElement{0x04, 0x00, -1, 0x03, 0x0032, 0x0007},
+ cmdLutElement{0x04, 0x00, -1, 0x03, 0x0032, 0x0008},
+ cmdLutElement{0x04, 0x00, -1, 0x03, 0x0032, 0x0009},
+ cmdLutElement{0x05, 0x00, -1, 0x00, 0x0042, 0x0002},
+ cmdLutElement{0x05, 0x00, -1, 0x01, 0x0042, 0x0003},
+ cmdLutElement{0x05, 0x00, -1, 0x02, 0x0042, 0x0004},
+ cmdLutElement{0x05, 0x00, -1, 0x03, 0x0042, 0x0005},
+ cmdLutElement{0x05, 0x00, -1, 0x03, 0x0042, 0x0006},
+ cmdLutElement{0x05, 0x00, -1, 0x03, 0x0042, 0x0007},
+ cmdLutElement{0x05, 0x00, -1, 0x03, 0x0042, 0x0008},
+ cmdLutElement{0x05, 0x00, -1, 0x03, 0x0042, 0x0009},
+ cmdLutElement{0x05, 0x00, -1, 0x00, 0x0062, 0x0002},
+ cmdLutElement{0x05, 0x00, -1, 0x01, 0x0062, 0x0003},
+ cmdLutElement{0x05, 0x00, -1, 0x02, 0x0062, 0x0004},
+ cmdLutElement{0x05, 0x00, -1, 0x03, 0x0062, 0x0005},
+ cmdLutElement{0x05, 0x00, -1, 0x03, 0x0062, 0x0006},
+ cmdLutElement{0x05, 0x00, -1, 0x03, 0x0062, 0x0007},
+ cmdLutElement{0x05, 0x00, -1, 0x03, 0x0062, 0x0008},
+ cmdLutElement{0x05, 0x00, -1, 0x03, 0x0062, 0x0009},
+ cmdLutElement{0x02, 0x01, -1, 0x03, 0x000a, 0x000a},
+ cmdLutElement{0x02, 0x01, -1, 0x03, 0x000a, 0x000c},
+ cmdLutElement{0x02, 0x02, -1, 0x03, 0x000a, 0x000e},
+ cmdLutElement{0x02, 0x02, -1, 0x03, 0x000a, 0x0012},
+ cmdLutElement{0x02, 0x03, -1, 0x03, 0x000a, 0x0016},
+ cmdLutElement{0x02, 0x03, -1, 0x03, 0x000a, 0x001e},
+ cmdLutElement{0x02, 0x04, -1, 0x03, 0x000a, 0x0026},
+ cmdLutElement{0x02, 0x04, -1, 0x03, 0x000a, 0x0036},
+ cmdLutElement{0x02, 0x01, -1, 0x03, 0x000e, 0x000a},
+ cmdLutElement{0x02, 0x01, -1, 0x03, 0x000e, 0x000c},
+ cmdLutElement{0x02, 0x02, -1, 0x03, 0x000e, 0x000e},
+ cmdLutElement{0x02, 0x02, -1, 0x03, 0x000e, 0x0012},
+ cmdLutElement{0x02, 0x03, -1, 0x03, 0x000e, 0x0016},
+ cmdLutElement{0x02, 0x03, -1, 0x03, 0x000e, 0x001e},
+ cmdLutElement{0x02, 0x04, -1, 0x03, 0x000e, 0x0026},
+ cmdLutElement{0x02, 0x04, -1, 0x03, 0x000e, 0x0036},
+ cmdLutElement{0x03, 0x01, -1, 0x03, 0x0012, 0x000a},
+ cmdLutElement{0x03, 0x01, -1, 0x03, 0x0012, 0x000c},
+ cmdLutElement{0x03, 0x02, -1, 0x03, 0x0012, 0x000e},
+ cmdLutElement{0x03, 0x02, -1, 0x03, 0x0012, 0x0012},
+ cmdLutElement{0x03, 0x03, -1, 0x03, 0x0012, 0x0016},
+ cmdLutElement{0x03, 0x03, -1, 0x03, 0x0012, 0x001e},
+ cmdLutElement{0x03, 0x04, -1, 0x03, 0x0012, 0x0026},
+ cmdLutElement{0x03, 0x04, -1, 0x03, 0x0012, 0x0036},
+ cmdLutElement{0x03, 0x01, -1, 0x03, 0x001a, 0x000a},
+ cmdLutElement{0x03, 0x01, -1, 0x03, 0x001a, 0x000c},
+ cmdLutElement{0x03, 0x02, -1, 0x03, 0x001a, 0x000e},
+ cmdLutElement{0x03, 0x02, -1, 0x03, 0x001a, 0x0012},
+ cmdLutElement{0x03, 0x03, -1, 0x03, 0x001a, 0x0016},
+ cmdLutElement{0x03, 0x03, -1, 0x03, 0x001a, 0x001e},
+ cmdLutElement{0x03, 0x04, -1, 0x03, 0x001a, 0x0026},
+ cmdLutElement{0x03, 0x04, -1, 0x03, 0x001a, 0x0036},
+ cmdLutElement{0x04, 0x01, -1, 0x03, 0x0022, 0x000a},
+ cmdLutElement{0x04, 0x01, -1, 0x03, 0x0022, 0x000c},
+ cmdLutElement{0x04, 0x02, -1, 0x03, 0x0022, 0x000e},
+ cmdLutElement{0x04, 0x02, -1, 0x03, 0x0022, 0x0012},
+ cmdLutElement{0x04, 0x03, -1, 0x03, 0x0022, 0x0016},
+ cmdLutElement{0x04, 0x03, -1, 0x03, 0x0022, 0x001e},
+ cmdLutElement{0x04, 0x04, -1, 0x03, 0x0022, 0x0026},
+ cmdLutElement{0x04, 0x04, -1, 0x03, 0x0022, 0x0036},
+ cmdLutElement{0x04, 0x01, -1, 0x03, 0x0032, 0x000a},
+ cmdLutElement{0x04, 0x01, -1, 0x03, 0x0032, 0x000c},
+ cmdLutElement{0x04, 0x02, -1, 0x03, 0x0032, 0x000e},
+ cmdLutElement{0x04, 0x02, -1, 0x03, 0x0032, 0x0012},
+ cmdLutElement{0x04, 0x03, -1, 0x03, 0x0032, 0x0016},
+ cmdLutElement{0x04, 0x03, -1, 0x03, 0x0032, 0x001e},
+ cmdLutElement{0x04, 0x04, -1, 0x03, 0x0032, 0x0026},
+ cmdLutElement{0x04, 0x04, -1, 0x03, 0x0032, 0x0036},
+ cmdLutElement{0x05, 0x01, -1, 0x03, 0x0042, 0x000a},
+ cmdLutElement{0x05, 0x01, -1, 0x03, 0x0042, 0x000c},
+ cmdLutElement{0x05, 0x02, -1, 0x03, 0x0042, 0x000e},
+ cmdLutElement{0x05, 0x02, -1, 0x03, 0x0042, 0x0012},
+ cmdLutElement{0x05, 0x03, -1, 0x03, 0x0042, 0x0016},
+ cmdLutElement{0x05, 0x03, -1, 0x03, 0x0042, 0x001e},
+ cmdLutElement{0x05, 0x04, -1, 0x03, 0x0042, 0x0026},
+ cmdLutElement{0x05, 0x04, -1, 0x03, 0x0042, 0x0036},
+ cmdLutElement{0x05, 0x01, -1, 0x03, 0x0062, 0x000a},
+ cmdLutElement{0x05, 0x01, -1, 0x03, 0x0062, 0x000c},
+ cmdLutElement{0x05, 0x02, -1, 0x03, 0x0062, 0x000e},
+ cmdLutElement{0x05, 0x02, -1, 0x03, 0x0062, 0x0012},
+ cmdLutElement{0x05, 0x03, -1, 0x03, 0x0062, 0x0016},
+ cmdLutElement{0x05, 0x03, -1, 0x03, 0x0062, 0x001e},
+ cmdLutElement{0x05, 0x04, -1, 0x03, 0x0062, 0x0026},
+ cmdLutElement{0x05, 0x04, -1, 0x03, 0x0062, 0x0036},
+ cmdLutElement{0x00, 0x05, -1, 0x03, 0x0000, 0x0046},
+ cmdLutElement{0x00, 0x05, -1, 0x03, 0x0000, 0x0066},
+ cmdLutElement{0x00, 0x06, -1, 0x03, 0x0000, 0x0086},
+ cmdLutElement{0x00, 0x07, -1, 0x03, 0x0000, 0x00c6},
+ cmdLutElement{0x00, 0x08, -1, 0x03, 0x0000, 0x0146},
+ cmdLutElement{0x00, 0x09, -1, 0x03, 0x0000, 0x0246},
+ cmdLutElement{0x00, 0x0a, -1, 0x03, 0x0000, 0x0446},
+ cmdLutElement{0x00, 0x18, -1, 0x03, 0x0000, 0x0846},
+ cmdLutElement{0x00, 0x05, -1, 0x03, 0x0001, 0x0046},
+ cmdLutElement{0x00, 0x05, -1, 0x03, 0x0001, 0x0066},
+ cmdLutElement{0x00, 0x06, -1, 0x03, 0x0001, 0x0086},
+ cmdLutElement{0x00, 0x07, -1, 0x03, 0x0001, 0x00c6},
+ cmdLutElement{0x00, 0x08, -1, 0x03, 0x0001, 0x0146},
+ cmdLutElement{0x00, 0x09, -1, 0x03, 0x0001, 0x0246},
+ cmdLutElement{0x00, 0x0a, -1, 0x03, 0x0001, 0x0446},
+ cmdLutElement{0x00, 0x18, -1, 0x03, 0x0001, 0x0846},
+ cmdLutElement{0x00, 0x05, -1, 0x03, 0x0002, 0x0046},
+ cmdLutElement{0x00, 0x05, -1, 0x03, 0x0002, 0x0066},
+ cmdLutElement{0x00, 0x06, -1, 0x03, 0x0002, 0x0086},
+ cmdLutElement{0x00, 0x07, -1, 0x03, 0x0002, 0x00c6},
+ cmdLutElement{0x00, 0x08, -1, 0x03, 0x0002, 0x0146},
+ cmdLutElement{0x00, 0x09, -1, 0x03, 0x0002, 0x0246},
+ cmdLutElement{0x00, 0x0a, -1, 0x03, 0x0002, 0x0446},
+ cmdLutElement{0x00, 0x18, -1, 0x03, 0x0002, 0x0846},
+ cmdLutElement{0x00, 0x05, -1, 0x03, 0x0003, 0x0046},
+ cmdLutElement{0x00, 0x05, -1, 0x03, 0x0003, 0x0066},
+ cmdLutElement{0x00, 0x06, -1, 0x03, 0x0003, 0x0086},
+ cmdLutElement{0x00, 0x07, -1, 0x03, 0x0003, 0x00c6},
+ cmdLutElement{0x00, 0x08, -1, 0x03, 0x0003, 0x0146},
+ cmdLutElement{0x00, 0x09, -1, 0x03, 0x0003, 0x0246},
+ cmdLutElement{0x00, 0x0a, -1, 0x03, 0x0003, 0x0446},
+ cmdLutElement{0x00, 0x18, -1, 0x03, 0x0003, 0x0846},
+ cmdLutElement{0x00, 0x05, -1, 0x03, 0x0004, 0x0046},
+ cmdLutElement{0x00, 0x05, -1, 0x03, 0x0004, 0x0066},
+ cmdLutElement{0x00, 0x06, -1, 0x03, 0x0004, 0x0086},
+ cmdLutElement{0x00, 0x07, -1, 0x03, 0x0004, 0x00c6},
+ cmdLutElement{0x00, 0x08, -1, 0x03, 0x0004, 0x0146},
+ cmdLutElement{0x00, 0x09, -1, 0x03, 0x0004, 0x0246},
+ cmdLutElement{0x00, 0x0a, -1, 0x03, 0x0004, 0x0446},
+ cmdLutElement{0x00, 0x18, -1, 0x03, 0x0004, 0x0846},
+ cmdLutElement{0x00, 0x05, -1, 0x03, 0x0005, 0x0046},
+ cmdLutElement{0x00, 0x05, -1, 0x03, 0x0005, 0x0066},
+ cmdLutElement{0x00, 0x06, -1, 0x03, 0x0005, 0x0086},
+ cmdLutElement{0x00, 0x07, -1, 0x03, 0x0005, 0x00c6},
+ cmdLutElement{0x00, 0x08, -1, 0x03, 0x0005, 0x0146},
+ cmdLutElement{0x00, 0x09, -1, 0x03, 0x0005, 0x0246},
+ cmdLutElement{0x00, 0x0a, -1, 0x03, 0x0005, 0x0446},
+ cmdLutElement{0x00, 0x18, -1, 0x03, 0x0005, 0x0846},
+ cmdLutElement{0x01, 0x05, -1, 0x03, 0x0006, 0x0046},
+ cmdLutElement{0x01, 0x05, -1, 0x03, 0x0006, 0x0066},
+ cmdLutElement{0x01, 0x06, -1, 0x03, 0x0006, 0x0086},
+ cmdLutElement{0x01, 0x07, -1, 0x03, 0x0006, 0x00c6},
+ cmdLutElement{0x01, 0x08, -1, 0x03, 0x0006, 0x0146},
+ cmdLutElement{0x01, 0x09, -1, 0x03, 0x0006, 0x0246},
+ cmdLutElement{0x01, 0x0a, -1, 0x03, 0x0006, 0x0446},
+ cmdLutElement{0x01, 0x18, -1, 0x03, 0x0006, 0x0846},
+ cmdLutElement{0x01, 0x05, -1, 0x03, 0x0008, 0x0046},
+ cmdLutElement{0x01, 0x05, -1, 0x03, 0x0008, 0x0066},
+ cmdLutElement{0x01, 0x06, -1, 0x03, 0x0008, 0x0086},
+ cmdLutElement{0x01, 0x07, -1, 0x03, 0x0008, 0x00c6},
+ cmdLutElement{0x01, 0x08, -1, 0x03, 0x0008, 0x0146},
+ cmdLutElement{0x01, 0x09, -1, 0x03, 0x0008, 0x0246},
+ cmdLutElement{0x01, 0x0a, -1, 0x03, 0x0008, 0x0446},
+ cmdLutElement{0x01, 0x18, -1, 0x03, 0x0008, 0x0846},
+ cmdLutElement{0x06, 0x00, -1, 0x00, 0x0082, 0x0002},
+ cmdLutElement{0x06, 0x00, -1, 0x01, 0x0082, 0x0003},
+ cmdLutElement{0x06, 0x00, -1, 0x02, 0x0082, 0x0004},
+ cmdLutElement{0x06, 0x00, -1, 0x03, 0x0082, 0x0005},
+ cmdLutElement{0x06, 0x00, -1, 0x03, 0x0082, 0x0006},
+ cmdLutElement{0x06, 0x00, -1, 0x03, 0x0082, 0x0007},
+ cmdLutElement{0x06, 0x00, -1, 0x03, 0x0082, 0x0008},
+ cmdLutElement{0x06, 0x00, -1, 0x03, 0x0082, 0x0009},
+ cmdLutElement{0x07, 0x00, -1, 0x00, 0x00c2, 0x0002},
+ cmdLutElement{0x07, 0x00, -1, 0x01, 0x00c2, 0x0003},
+ cmdLutElement{0x07, 0x00, -1, 0x02, 0x00c2, 0x0004},
+ cmdLutElement{0x07, 0x00, -1, 0x03, 0x00c2, 0x0005},
+ cmdLutElement{0x07, 0x00, -1, 0x03, 0x00c2, 0x0006},
+ cmdLutElement{0x07, 0x00, -1, 0x03, 0x00c2, 0x0007},
+ cmdLutElement{0x07, 0x00, -1, 0x03, 0x00c2, 0x0008},
+ cmdLutElement{0x07, 0x00, -1, 0x03, 0x00c2, 0x0009},
+ cmdLutElement{0x08, 0x00, -1, 0x00, 0x0142, 0x0002},
+ cmdLutElement{0x08, 0x00, -1, 0x01, 0x0142, 0x0003},
+ cmdLutElement{0x08, 0x00, -1, 0x02, 0x0142, 0x0004},
+ cmdLutElement{0x08, 0x00, -1, 0x03, 0x0142, 0x0005},
+ cmdLutElement{0x08, 0x00, -1, 0x03, 0x0142, 0x0006},
+ cmdLutElement{0x08, 0x00, -1, 0x03, 0x0142, 0x0007},
+ cmdLutElement{0x08, 0x00, -1, 0x03, 0x0142, 0x0008},
+ cmdLutElement{0x08, 0x00, -1, 0x03, 0x0142, 0x0009},
+ cmdLutElement{0x09, 0x00, -1, 0x00, 0x0242, 0x0002},
+ cmdLutElement{0x09, 0x00, -1, 0x01, 0x0242, 0x0003},
+ cmdLutElement{0x09, 0x00, -1, 0x02, 0x0242, 0x0004},
+ cmdLutElement{0x09, 0x00, -1, 0x03, 0x0242, 0x0005},
+ cmdLutElement{0x09, 0x00, -1, 0x03, 0x0242, 0x0006},
+ cmdLutElement{0x09, 0x00, -1, 0x03, 0x0242, 0x0007},
+ cmdLutElement{0x09, 0x00, -1, 0x03, 0x0242, 0x0008},
+ cmdLutElement{0x09, 0x00, -1, 0x03, 0x0242, 0x0009},
+ cmdLutElement{0x0a, 0x00, -1, 0x00, 0x0442, 0x0002},
+ cmdLutElement{0x0a, 0x00, -1, 0x01, 0x0442, 0x0003},
+ cmdLutElement{0x0a, 0x00, -1, 0x02, 0x0442, 0x0004},
+ cmdLutElement{0x0a, 0x00, -1, 0x03, 0x0442, 0x0005},
+ cmdLutElement{0x0a, 0x00, -1, 0x03, 0x0442, 0x0006},
+ cmdLutElement{0x0a, 0x00, -1, 0x03, 0x0442, 0x0007},
+ cmdLutElement{0x0a, 0x00, -1, 0x03, 0x0442, 0x0008},
+ cmdLutElement{0x0a, 0x00, -1, 0x03, 0x0442, 0x0009},
+ cmdLutElement{0x0c, 0x00, -1, 0x00, 0x0842, 0x0002},
+ cmdLutElement{0x0c, 0x00, -1, 0x01, 0x0842, 0x0003},
+ cmdLutElement{0x0c, 0x00, -1, 0x02, 0x0842, 0x0004},
+ cmdLutElement{0x0c, 0x00, -1, 0x03, 0x0842, 0x0005},
+ cmdLutElement{0x0c, 0x00, -1, 0x03, 0x0842, 0x0006},
+ cmdLutElement{0x0c, 0x00, -1, 0x03, 0x0842, 0x0007},
+ cmdLutElement{0x0c, 0x00, -1, 0x03, 0x0842, 0x0008},
+ cmdLutElement{0x0c, 0x00, -1, 0x03, 0x0842, 0x0009},
+ cmdLutElement{0x0e, 0x00, -1, 0x00, 0x1842, 0x0002},
+ cmdLutElement{0x0e, 0x00, -1, 0x01, 0x1842, 0x0003},
+ cmdLutElement{0x0e, 0x00, -1, 0x02, 0x1842, 0x0004},
+ cmdLutElement{0x0e, 0x00, -1, 0x03, 0x1842, 0x0005},
+ cmdLutElement{0x0e, 0x00, -1, 0x03, 0x1842, 0x0006},
+ cmdLutElement{0x0e, 0x00, -1, 0x03, 0x1842, 0x0007},
+ cmdLutElement{0x0e, 0x00, -1, 0x03, 0x1842, 0x0008},
+ cmdLutElement{0x0e, 0x00, -1, 0x03, 0x1842, 0x0009},
+ cmdLutElement{0x18, 0x00, -1, 0x00, 0x5842, 0x0002},
+ cmdLutElement{0x18, 0x00, -1, 0x01, 0x5842, 0x0003},
+ cmdLutElement{0x18, 0x00, -1, 0x02, 0x5842, 0x0004},
+ cmdLutElement{0x18, 0x00, -1, 0x03, 0x5842, 0x0005},
+ cmdLutElement{0x18, 0x00, -1, 0x03, 0x5842, 0x0006},
+ cmdLutElement{0x18, 0x00, -1, 0x03, 0x5842, 0x0007},
+ cmdLutElement{0x18, 0x00, -1, 0x03, 0x5842, 0x0008},
+ cmdLutElement{0x18, 0x00, -1, 0x03, 0x5842, 0x0009},
+ cmdLutElement{0x02, 0x05, -1, 0x03, 0x000a, 0x0046},
+ cmdLutElement{0x02, 0x05, -1, 0x03, 0x000a, 0x0066},
+ cmdLutElement{0x02, 0x06, -1, 0x03, 0x000a, 0x0086},
+ cmdLutElement{0x02, 0x07, -1, 0x03, 0x000a, 0x00c6},
+ cmdLutElement{0x02, 0x08, -1, 0x03, 0x000a, 0x0146},
+ cmdLutElement{0x02, 0x09, -1, 0x03, 0x000a, 0x0246},
+ cmdLutElement{0x02, 0x0a, -1, 0x03, 0x000a, 0x0446},
+ cmdLutElement{0x02, 0x18, -1, 0x03, 0x000a, 0x0846},
+ cmdLutElement{0x02, 0x05, -1, 0x03, 0x000e, 0x0046},
+ cmdLutElement{0x02, 0x05, -1, 0x03, 0x000e, 0x0066},
+ cmdLutElement{0x02, 0x06, -1, 0x03, 0x000e, 0x0086},
+ cmdLutElement{0x02, 0x07, -1, 0x03, 0x000e, 0x00c6},
+ cmdLutElement{0x02, 0x08, -1, 0x03, 0x000e, 0x0146},
+ cmdLutElement{0x02, 0x09, -1, 0x03, 0x000e, 0x0246},
+ cmdLutElement{0x02, 0x0a, -1, 0x03, 0x000e, 0x0446},
+ cmdLutElement{0x02, 0x18, -1, 0x03, 0x000e, 0x0846},
+ cmdLutElement{0x03, 0x05, -1, 0x03, 0x0012, 0x0046},
+ cmdLutElement{0x03, 0x05, -1, 0x03, 0x0012, 0x0066},
+ cmdLutElement{0x03, 0x06, -1, 0x03, 0x0012, 0x0086},
+ cmdLutElement{0x03, 0x07, -1, 0x03, 0x0012, 0x00c6},
+ cmdLutElement{0x03, 0x08, -1, 0x03, 0x0012, 0x0146},
+ cmdLutElement{0x03, 0x09, -1, 0x03, 0x0012, 0x0246},
+ cmdLutElement{0x03, 0x0a, -1, 0x03, 0x0012, 0x0446},
+ cmdLutElement{0x03, 0x18, -1, 0x03, 0x0012, 0x0846},
+ cmdLutElement{0x03, 0x05, -1, 0x03, 0x001a, 0x0046},
+ cmdLutElement{0x03, 0x05, -1, 0x03, 0x001a, 0x0066},
+ cmdLutElement{0x03, 0x06, -1, 0x03, 0x001a, 0x0086},
+ cmdLutElement{0x03, 0x07, -1, 0x03, 0x001a, 0x00c6},
+ cmdLutElement{0x03, 0x08, -1, 0x03, 0x001a, 0x0146},
+ cmdLutElement{0x03, 0x09, -1, 0x03, 0x001a, 0x0246},
+ cmdLutElement{0x03, 0x0a, -1, 0x03, 0x001a, 0x0446},
+ cmdLutElement{0x03, 0x18, -1, 0x03, 0x001a, 0x0846},
+ cmdLutElement{0x04, 0x05, -1, 0x03, 0x0022, 0x0046},
+ cmdLutElement{0x04, 0x05, -1, 0x03, 0x0022, 0x0066},
+ cmdLutElement{0x04, 0x06, -1, 0x03, 0x0022, 0x0086},
+ cmdLutElement{0x04, 0x07, -1, 0x03, 0x0022, 0x00c6},
+ cmdLutElement{0x04, 0x08, -1, 0x03, 0x0022, 0x0146},
+ cmdLutElement{0x04, 0x09, -1, 0x03, 0x0022, 0x0246},
+ cmdLutElement{0x04, 0x0a, -1, 0x03, 0x0022, 0x0446},
+ cmdLutElement{0x04, 0x18, -1, 0x03, 0x0022, 0x0846},
+ cmdLutElement{0x04, 0x05, -1, 0x03, 0x0032, 0x0046},
+ cmdLutElement{0x04, 0x05, -1, 0x03, 0x0032, 0x0066},
+ cmdLutElement{0x04, 0x06, -1, 0x03, 0x0032, 0x0086},
+ cmdLutElement{0x04, 0x07, -1, 0x03, 0x0032, 0x00c6},
+ cmdLutElement{0x04, 0x08, -1, 0x03, 0x0032, 0x0146},
+ cmdLutElement{0x04, 0x09, -1, 0x03, 0x0032, 0x0246},
+ cmdLutElement{0x04, 0x0a, -1, 0x03, 0x0032, 0x0446},
+ cmdLutElement{0x04, 0x18, -1, 0x03, 0x0032, 0x0846},
+ cmdLutElement{0x05, 0x05, -1, 0x03, 0x0042, 0x0046},
+ cmdLutElement{0x05, 0x05, -1, 0x03, 0x0042, 0x0066},
+ cmdLutElement{0x05, 0x06, -1, 0x03, 0x0042, 0x0086},
+ cmdLutElement{0x05, 0x07, -1, 0x03, 0x0042, 0x00c6},
+ cmdLutElement{0x05, 0x08, -1, 0x03, 0x0042, 0x0146},
+ cmdLutElement{0x05, 0x09, -1, 0x03, 0x0042, 0x0246},
+ cmdLutElement{0x05, 0x0a, -1, 0x03, 0x0042, 0x0446},
+ cmdLutElement{0x05, 0x18, -1, 0x03, 0x0042, 0x0846},
+ cmdLutElement{0x05, 0x05, -1, 0x03, 0x0062, 0x0046},
+ cmdLutElement{0x05, 0x05, -1, 0x03, 0x0062, 0x0066},
+ cmdLutElement{0x05, 0x06, -1, 0x03, 0x0062, 0x0086},
+ cmdLutElement{0x05, 0x07, -1, 0x03, 0x0062, 0x00c6},
+ cmdLutElement{0x05, 0x08, -1, 0x03, 0x0062, 0x0146},
+ cmdLutElement{0x05, 0x09, -1, 0x03, 0x0062, 0x0246},
+ cmdLutElement{0x05, 0x0a, -1, 0x03, 0x0062, 0x0446},
+ cmdLutElement{0x05, 0x18, -1, 0x03, 0x0062, 0x0846},
+ cmdLutElement{0x06, 0x01, -1, 0x03, 0x0082, 0x000a},
+ cmdLutElement{0x06, 0x01, -1, 0x03, 0x0082, 0x000c},
+ cmdLutElement{0x06, 0x02, -1, 0x03, 0x0082, 0x000e},
+ cmdLutElement{0x06, 0x02, -1, 0x03, 0x0082, 0x0012},
+ cmdLutElement{0x06, 0x03, -1, 0x03, 0x0082, 0x0016},
+ cmdLutElement{0x06, 0x03, -1, 0x03, 0x0082, 0x001e},
+ cmdLutElement{0x06, 0x04, -1, 0x03, 0x0082, 0x0026},
+ cmdLutElement{0x06, 0x04, -1, 0x03, 0x0082, 0x0036},
+ cmdLutElement{0x07, 0x01, -1, 0x03, 0x00c2, 0x000a},
+ cmdLutElement{0x07, 0x01, -1, 0x03, 0x00c2, 0x000c},
+ cmdLutElement{0x07, 0x02, -1, 0x03, 0x00c2, 0x000e},
+ cmdLutElement{0x07, 0x02, -1, 0x03, 0x00c2, 0x0012},
+ cmdLutElement{0x07, 0x03, -1, 0x03, 0x00c2, 0x0016},
+ cmdLutElement{0x07, 0x03, -1, 0x03, 0x00c2, 0x001e},
+ cmdLutElement{0x07, 0x04, -1, 0x03, 0x00c2, 0x0026},
+ cmdLutElement{0x07, 0x04, -1, 0x03, 0x00c2, 0x0036},
+ cmdLutElement{0x08, 0x01, -1, 0x03, 0x0142, 0x000a},
+ cmdLutElement{0x08, 0x01, -1, 0x03, 0x0142, 0x000c},
+ cmdLutElement{0x08, 0x02, -1, 0x03, 0x0142, 0x000e},
+ cmdLutElement{0x08, 0x02, -1, 0x03, 0x0142, 0x0012},
+ cmdLutElement{0x08, 0x03, -1, 0x03, 0x0142, 0x0016},
+ cmdLutElement{0x08, 0x03, -1, 0x03, 0x0142, 0x001e},
+ cmdLutElement{0x08, 0x04, -1, 0x03, 0x0142, 0x0026},
+ cmdLutElement{0x08, 0x04, -1, 0x03, 0x0142, 0x0036},
+ cmdLutElement{0x09, 0x01, -1, 0x03, 0x0242, 0x000a},
+ cmdLutElement{0x09, 0x01, -1, 0x03, 0x0242, 0x000c},
+ cmdLutElement{0x09, 0x02, -1, 0x03, 0x0242, 0x000e},
+ cmdLutElement{0x09, 0x02, -1, 0x03, 0x0242, 0x0012},
+ cmdLutElement{0x09, 0x03, -1, 0x03, 0x0242, 0x0016},
+ cmdLutElement{0x09, 0x03, -1, 0x03, 0x0242, 0x001e},
+ cmdLutElement{0x09, 0x04, -1, 0x03, 0x0242, 0x0026},
+ cmdLutElement{0x09, 0x04, -1, 0x03, 0x0242, 0x0036},
+ cmdLutElement{0x0a, 0x01, -1, 0x03, 0x0442, 0x000a},
+ cmdLutElement{0x0a, 0x01, -1, 0x03, 0x0442, 0x000c},
+ cmdLutElement{0x0a, 0x02, -1, 0x03, 0x0442, 0x000e},
+ cmdLutElement{0x0a, 0x02, -1, 0x03, 0x0442, 0x0012},
+ cmdLutElement{0x0a, 0x03, -1, 0x03, 0x0442, 0x0016},
+ cmdLutElement{0x0a, 0x03, -1, 0x03, 0x0442, 0x001e},
+ cmdLutElement{0x0a, 0x04, -1, 0x03, 0x0442, 0x0026},
+ cmdLutElement{0x0a, 0x04, -1, 0x03, 0x0442, 0x0036},
+ cmdLutElement{0x0c, 0x01, -1, 0x03, 0x0842, 0x000a},
+ cmdLutElement{0x0c, 0x01, -1, 0x03, 0x0842, 0x000c},
+ cmdLutElement{0x0c, 0x02, -1, 0x03, 0x0842, 0x000e},
+ cmdLutElement{0x0c, 0x02, -1, 0x03, 0x0842, 0x0012},
+ cmdLutElement{0x0c, 0x03, -1, 0x03, 0x0842, 0x0016},
+ cmdLutElement{0x0c, 0x03, -1, 0x03, 0x0842, 0x001e},
+ cmdLutElement{0x0c, 0x04, -1, 0x03, 0x0842, 0x0026},
+ cmdLutElement{0x0c, 0x04, -1, 0x03, 0x0842, 0x0036},
+ cmdLutElement{0x0e, 0x01, -1, 0x03, 0x1842, 0x000a},
+ cmdLutElement{0x0e, 0x01, -1, 0x03, 0x1842, 0x000c},
+ cmdLutElement{0x0e, 0x02, -1, 0x03, 0x1842, 0x000e},
+ cmdLutElement{0x0e, 0x02, -1, 0x03, 0x1842, 0x0012},
+ cmdLutElement{0x0e, 0x03, -1, 0x03, 0x1842, 0x0016},
+ cmdLutElement{0x0e, 0x03, -1, 0x03, 0x1842, 0x001e},
+ cmdLutElement{0x0e, 0x04, -1, 0x03, 0x1842, 0x0026},
+ cmdLutElement{0x0e, 0x04, -1, 0x03, 0x1842, 0x0036},
+ cmdLutElement{0x18, 0x01, -1, 0x03, 0x5842, 0x000a},
+ cmdLutElement{0x18, 0x01, -1, 0x03, 0x5842, 0x000c},
+ cmdLutElement{0x18, 0x02, -1, 0x03, 0x5842, 0x000e},
+ cmdLutElement{0x18, 0x02, -1, 0x03, 0x5842, 0x0012},
+ cmdLutElement{0x18, 0x03, -1, 0x03, 0x5842, 0x0016},
+ cmdLutElement{0x18, 0x03, -1, 0x03, 0x5842, 0x001e},
+ cmdLutElement{0x18, 0x04, -1, 0x03, 0x5842, 0x0026},
+ cmdLutElement{0x18, 0x04, -1, 0x03, 0x5842, 0x0036},
+ cmdLutElement{0x06, 0x05, -1, 0x03, 0x0082, 0x0046},
+ cmdLutElement{0x06, 0x05, -1, 0x03, 0x0082, 0x0066},
+ cmdLutElement{0x06, 0x06, -1, 0x03, 0x0082, 0x0086},
+ cmdLutElement{0x06, 0x07, -1, 0x03, 0x0082, 0x00c6},
+ cmdLutElement{0x06, 0x08, -1, 0x03, 0x0082, 0x0146},
+ cmdLutElement{0x06, 0x09, -1, 0x03, 0x0082, 0x0246},
+ cmdLutElement{0x06, 0x0a, -1, 0x03, 0x0082, 0x0446},
+ cmdLutElement{0x06, 0x18, -1, 0x03, 0x0082, 0x0846},
+ cmdLutElement{0x07, 0x05, -1, 0x03, 0x00c2, 0x0046},
+ cmdLutElement{0x07, 0x05, -1, 0x03, 0x00c2, 0x0066},
+ cmdLutElement{0x07, 0x06, -1, 0x03, 0x00c2, 0x0086},
+ cmdLutElement{0x07, 0x07, -1, 0x03, 0x00c2, 0x00c6},
+ cmdLutElement{0x07, 0x08, -1, 0x03, 0x00c2, 0x0146},
+ cmdLutElement{0x07, 0x09, -1, 0x03, 0x00c2, 0x0246},
+ cmdLutElement{0x07, 0x0a, -1, 0x03, 0x00c2, 0x0446},
+ cmdLutElement{0x07, 0x18, -1, 0x03, 0x00c2, 0x0846},
+ cmdLutElement{0x08, 0x05, -1, 0x03, 0x0142, 0x0046},
+ cmdLutElement{0x08, 0x05, -1, 0x03, 0x0142, 0x0066},
+ cmdLutElement{0x08, 0x06, -1, 0x03, 0x0142, 0x0086},
+ cmdLutElement{0x08, 0x07, -1, 0x03, 0x0142, 0x00c6},
+ cmdLutElement{0x08, 0x08, -1, 0x03, 0x0142, 0x0146},
+ cmdLutElement{0x08, 0x09, -1, 0x03, 0x0142, 0x0246},
+ cmdLutElement{0x08, 0x0a, -1, 0x03, 0x0142, 0x0446},
+ cmdLutElement{0x08, 0x18, -1, 0x03, 0x0142, 0x0846},
+ cmdLutElement{0x09, 0x05, -1, 0x03, 0x0242, 0x0046},
+ cmdLutElement{0x09, 0x05, -1, 0x03, 0x0242, 0x0066},
+ cmdLutElement{0x09, 0x06, -1, 0x03, 0x0242, 0x0086},
+ cmdLutElement{0x09, 0x07, -1, 0x03, 0x0242, 0x00c6},
+ cmdLutElement{0x09, 0x08, -1, 0x03, 0x0242, 0x0146},
+ cmdLutElement{0x09, 0x09, -1, 0x03, 0x0242, 0x0246},
+ cmdLutElement{0x09, 0x0a, -1, 0x03, 0x0242, 0x0446},
+ cmdLutElement{0x09, 0x18, -1, 0x03, 0x0242, 0x0846},
+ cmdLutElement{0x0a, 0x05, -1, 0x03, 0x0442, 0x0046},
+ cmdLutElement{0x0a, 0x05, -1, 0x03, 0x0442, 0x0066},
+ cmdLutElement{0x0a, 0x06, -1, 0x03, 0x0442, 0x0086},
+ cmdLutElement{0x0a, 0x07, -1, 0x03, 0x0442, 0x00c6},
+ cmdLutElement{0x0a, 0x08, -1, 0x03, 0x0442, 0x0146},
+ cmdLutElement{0x0a, 0x09, -1, 0x03, 0x0442, 0x0246},
+ cmdLutElement{0x0a, 0x0a, -1, 0x03, 0x0442, 0x0446},
+ cmdLutElement{0x0a, 0x18, -1, 0x03, 0x0442, 0x0846},
+ cmdLutElement{0x0c, 0x05, -1, 0x03, 0x0842, 0x0046},
+ cmdLutElement{0x0c, 0x05, -1, 0x03, 0x0842, 0x0066},
+ cmdLutElement{0x0c, 0x06, -1, 0x03, 0x0842, 0x0086},
+ cmdLutElement{0x0c, 0x07, -1, 0x03, 0x0842, 0x00c6},
+ cmdLutElement{0x0c, 0x08, -1, 0x03, 0x0842, 0x0146},
+ cmdLutElement{0x0c, 0x09, -1, 0x03, 0x0842, 0x0246},
+ cmdLutElement{0x0c, 0x0a, -1, 0x03, 0x0842, 0x0446},
+ cmdLutElement{0x0c, 0x18, -1, 0x03, 0x0842, 0x0846},
+ cmdLutElement{0x0e, 0x05, -1, 0x03, 0x1842, 0x0046},
+ cmdLutElement{0x0e, 0x05, -1, 0x03, 0x1842, 0x0066},
+ cmdLutElement{0x0e, 0x06, -1, 0x03, 0x1842, 0x0086},
+ cmdLutElement{0x0e, 0x07, -1, 0x03, 0x1842, 0x00c6},
+ cmdLutElement{0x0e, 0x08, -1, 0x03, 0x1842, 0x0146},
+ cmdLutElement{0x0e, 0x09, -1, 0x03, 0x1842, 0x0246},
+ cmdLutElement{0x0e, 0x0a, -1, 0x03, 0x1842, 0x0446},
+ cmdLutElement{0x0e, 0x18, -1, 0x03, 0x1842, 0x0846},
+ cmdLutElement{0x18, 0x05, -1, 0x03, 0x5842, 0x0046},
+ cmdLutElement{0x18, 0x05, -1, 0x03, 0x5842, 0x0066},
+ cmdLutElement{0x18, 0x06, -1, 0x03, 0x5842, 0x0086},
+ cmdLutElement{0x18, 0x07, -1, 0x03, 0x5842, 0x00c6},
+ cmdLutElement{0x18, 0x08, -1, 0x03, 0x5842, 0x0146},
+ cmdLutElement{0x18, 0x09, -1, 0x03, 0x5842, 0x0246},
+ cmdLutElement{0x18, 0x0a, -1, 0x03, 0x5842, 0x0446},
+ cmdLutElement{0x18, 0x18, -1, 0x03, 0x5842, 0x0846},
+}
diff --git a/vendor/github.com/andybalholm/brotli/quality.go b/vendor/github.com/andybalholm/brotli/quality.go
new file mode 100644
index 0000000..49709a3
--- /dev/null
+++ b/vendor/github.com/andybalholm/brotli/quality.go
@@ -0,0 +1,196 @@
+package brotli
+
+const fastOnePassCompressionQuality = 0
+
+const fastTwoPassCompressionQuality = 1
+
+const zopflificationQuality = 10
+
+const hqZopflificationQuality = 11
+
+const maxQualityForStaticEntropyCodes = 2
+
+const minQualityForBlockSplit = 4
+
+const minQualityForNonzeroDistanceParams = 4
+
+const minQualityForOptimizeHistograms = 4
+
+const minQualityForExtensiveReferenceSearch = 5
+
+const minQualityForContextModeling = 5
+
+const minQualityForHqContextModeling = 7
+
+const minQualityForHqBlockSplitting = 10
+
+/* For quality below MIN_QUALITY_FOR_BLOCK_SPLIT there is no block splitting,
+ so we buffer at most this much literals and commands. */
+const maxNumDelayedSymbols = 0x2FFF
+
+/* Returns hash-table size for quality levels 0 and 1. */
+func maxHashTableSize(quality int) uint {
+ if quality == fastOnePassCompressionQuality {
+ return 1 << 15
+ } else {
+ return 1 << 17
+ }
+}
+
+/* The maximum length for which the zopflification uses distinct distances. */
+const maxZopfliLenQuality10 = 150
+
+const maxZopfliLenQuality11 = 325
+
+/* Do not thoroughly search when a long copy is found. */
+const longCopyQuickStep = 16384
+
+func maxZopfliLen(params *encoderParams) uint {
+ if params.quality <= 10 {
+ return maxZopfliLenQuality10
+ } else {
+ return maxZopfliLenQuality11
+ }
+}
+
+/* Number of best candidates to evaluate to expand Zopfli chain. */
+func maxZopfliCandidates(params *encoderParams) uint {
+ if params.quality <= 10 {
+ return 1
+ } else {
+ return 5
+ }
+}
+
+func sanitizeParams(params *encoderParams) {
+ params.quality = brotli_min_int(maxQuality, brotli_max_int(minQuality, params.quality))
+ if params.quality <= maxQualityForStaticEntropyCodes {
+ params.large_window = false
+ }
+
+ if params.lgwin < minWindowBits {
+ params.lgwin = minWindowBits
+ } else {
+ var max_lgwin int
+ if params.large_window {
+ max_lgwin = largeMaxWindowBits
+ } else {
+ max_lgwin = maxWindowBits
+ }
+ if params.lgwin > uint(max_lgwin) {
+ params.lgwin = uint(max_lgwin)
+ }
+ }
+}
+
+/* Returns optimized lg_block value. */
+func computeLgBlock(params *encoderParams) int {
+ var lgblock int = params.lgblock
+ if params.quality == fastOnePassCompressionQuality || params.quality == fastTwoPassCompressionQuality {
+ lgblock = int(params.lgwin)
+ } else if params.quality < minQualityForBlockSplit {
+ lgblock = 14
+ } else if lgblock == 0 {
+ lgblock = 16
+ if params.quality >= 9 && params.lgwin > uint(lgblock) {
+ lgblock = brotli_min_int(18, int(params.lgwin))
+ }
+ } else {
+ lgblock = brotli_min_int(maxInputBlockBits, brotli_max_int(minInputBlockBits, lgblock))
+ }
+
+ return lgblock
+}
+
+/* Returns log2 of the size of main ring buffer area.
+ Allocate at least lgwin + 1 bits for the ring buffer so that the newly
+ added block fits there completely and we still get lgwin bits and at least
+ read_block_size_bits + 1 bits because the copy tail length needs to be
+ smaller than ring-buffer size. */
+func computeRbBits(params *encoderParams) int {
+ return 1 + brotli_max_int(int(params.lgwin), params.lgblock)
+}
+
+func maxMetablockSize(params *encoderParams) uint {
+ var bits int = brotli_min_int(computeRbBits(params), maxInputBlockBits)
+ return uint(1) << uint(bits)
+}
+
+/* When searching for backward references and have not seen matches for a long
+ time, we can skip some match lookups. Unsuccessful match lookups are very
+ expensive and this kind of a heuristic speeds up compression quite a lot.
+ At first 8 byte strides are taken and every second byte is put to hasher.
+ After 4x more literals stride by 16 bytes, every put 4-th byte to hasher.
+ Applied only to qualities 2 to 9. */
+func literalSpreeLengthForSparseSearch(params *encoderParams) uint {
+ if params.quality < 9 {
+ return 64
+ } else {
+ return 512
+ }
+}
+
+func chooseHasher(params *encoderParams, hparams *hasherParams) {
+ if params.quality > 9 {
+ hparams.type_ = 10
+ } else if params.quality == 4 && params.size_hint >= 1<<20 {
+ hparams.type_ = 54
+ } else if params.quality < 5 {
+ hparams.type_ = params.quality
+ } else if params.lgwin <= 16 {
+ if params.quality < 7 {
+ hparams.type_ = 40
+ } else if params.quality < 9 {
+ hparams.type_ = 41
+ } else {
+ hparams.type_ = 42
+ }
+ } else if params.size_hint >= 1<<20 && params.lgwin >= 19 {
+ hparams.type_ = 6
+ hparams.block_bits = params.quality - 1
+ hparams.bucket_bits = 15
+ hparams.hash_len = 5
+ if params.quality < 7 {
+ hparams.num_last_distances_to_check = 4
+ } else if params.quality < 9 {
+ hparams.num_last_distances_to_check = 10
+ } else {
+ hparams.num_last_distances_to_check = 16
+ }
+ } else {
+ hparams.type_ = 5
+ hparams.block_bits = params.quality - 1
+ if params.quality < 7 {
+ hparams.bucket_bits = 14
+ } else {
+ hparams.bucket_bits = 15
+ }
+ if params.quality < 7 {
+ hparams.num_last_distances_to_check = 4
+ } else if params.quality < 9 {
+ hparams.num_last_distances_to_check = 10
+ } else {
+ hparams.num_last_distances_to_check = 16
+ }
+ }
+
+ if params.lgwin > 24 {
+ /* Different hashers for large window brotli: not for qualities <= 2,
+ these are too fast for large window. Not for qualities >= 10: their
+ hasher already works well with large window. So the changes are:
+ H3 --> H35: for quality 3.
+ H54 --> H55: for quality 4 with size hint > 1MB
+ H6 --> H65: for qualities 5, 6, 7, 8, 9. */
+ if hparams.type_ == 3 {
+ hparams.type_ = 35
+ }
+
+ if hparams.type_ == 54 {
+ hparams.type_ = 55
+ }
+
+ if hparams.type_ == 6 {
+ hparams.type_ = 65
+ }
+ }
+}
diff --git a/vendor/github.com/andybalholm/brotli/reader.go b/vendor/github.com/andybalholm/brotli/reader.go
new file mode 100644
index 0000000..9419c79
--- /dev/null
+++ b/vendor/github.com/andybalholm/brotli/reader.go
@@ -0,0 +1,108 @@
+package brotli
+
+import (
+ "errors"
+ "io"
+)
+
+type decodeError int
+
+func (err decodeError) Error() string {
+ return "brotli: " + string(decoderErrorString(int(err)))
+}
+
+var errExcessiveInput = errors.New("brotli: excessive input")
+var errInvalidState = errors.New("brotli: invalid state")
+
+// readBufSize is a "good" buffer size that avoids excessive round-trips
+// between C and Go but doesn't waste too much memory on buffering.
+// It is arbitrarily chosen to be equal to the constant used in io.Copy.
+const readBufSize = 32 * 1024
+
+// NewReader creates a new Reader reading the given reader.
+func NewReader(src io.Reader) *Reader {
+ r := new(Reader)
+ r.Reset(src)
+ return r
+}
+
+// Reset discards the Reader's state and makes it equivalent to the result of
+// its original state from NewReader, but reading from src instead.
+// This permits reusing a Reader rather than allocating a new one.
+// Error is always nil
+func (r *Reader) Reset(src io.Reader) error {
+ if r.error_code < 0 {
+ // There was an unrecoverable error, leaving the Reader's state
+ // undefined. Clear out everything but the buffer.
+ *r = Reader{buf: r.buf}
+ }
+
+ decoderStateInit(r)
+ r.src = src
+ if r.buf == nil {
+ r.buf = make([]byte, readBufSize)
+ }
+ return nil
+}
+
+func (r *Reader) Read(p []byte) (n int, err error) {
+ if !decoderHasMoreOutput(r) && len(r.in) == 0 {
+ m, readErr := r.src.Read(r.buf)
+ if m == 0 {
+ // If readErr is `nil`, we just proxy underlying stream behavior.
+ return 0, readErr
+ }
+ r.in = r.buf[:m]
+ }
+
+ if len(p) == 0 {
+ return 0, nil
+ }
+
+ for {
+ var written uint
+ in_len := uint(len(r.in))
+ out_len := uint(len(p))
+ in_remaining := in_len
+ out_remaining := out_len
+ result := decoderDecompressStream(r, &in_remaining, &r.in, &out_remaining, &p)
+ written = out_len - out_remaining
+ n = int(written)
+
+ switch result {
+ case decoderResultSuccess:
+ if len(r.in) > 0 {
+ return n, errExcessiveInput
+ }
+ return n, nil
+ case decoderResultError:
+ return n, decodeError(decoderGetErrorCode(r))
+ case decoderResultNeedsMoreOutput:
+ if n == 0 {
+ return 0, io.ErrShortBuffer
+ }
+ return n, nil
+ case decoderNeedsMoreInput:
+ }
+
+ if len(r.in) != 0 {
+ return 0, errInvalidState
+ }
+
+ // Calling r.src.Read may block. Don't block if we have data to return.
+ if n > 0 {
+ return n, nil
+ }
+
+ // Top off the buffer.
+ encN, err := r.src.Read(r.buf)
+ if encN == 0 {
+ // Not enough data to complete decoding.
+ if err == io.EOF {
+ return 0, io.ErrUnexpectedEOF
+ }
+ return 0, err
+ }
+ r.in = r.buf[:encN]
+ }
+}
diff --git a/vendor/github.com/andybalholm/brotli/ringbuffer.go b/vendor/github.com/andybalholm/brotli/ringbuffer.go
new file mode 100644
index 0000000..1c8f86f
--- /dev/null
+++ b/vendor/github.com/andybalholm/brotli/ringbuffer.go
@@ -0,0 +1,134 @@
+package brotli
+
+/* Copyright 2013 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* A ringBuffer(window_bits, tail_bits) contains `1 << window_bits' bytes of
+ data in a circular manner: writing a byte writes it to:
+ `position() % (1 << window_bits)'.
+ For convenience, the ringBuffer array contains another copy of the
+ first `1 << tail_bits' bytes:
+ buffer_[i] == buffer_[i + (1 << window_bits)], if i < (1 << tail_bits),
+ and another copy of the last two bytes:
+ buffer_[-1] == buffer_[(1 << window_bits) - 1] and
+ buffer_[-2] == buffer_[(1 << window_bits) - 2]. */
+type ringBuffer struct {
+ size_ uint32
+ mask_ uint32
+ tail_size_ uint32
+ total_size_ uint32
+ cur_size_ uint32
+ pos_ uint32
+ data_ []byte
+ buffer_ []byte
+}
+
+func ringBufferInit(rb *ringBuffer) {
+ rb.pos_ = 0
+}
+
+func ringBufferSetup(params *encoderParams, rb *ringBuffer) {
+ var window_bits int = computeRbBits(params)
+ var tail_bits int = params.lgblock
+ *(*uint32)(&rb.size_) = 1 << uint(window_bits)
+ *(*uint32)(&rb.mask_) = (1 << uint(window_bits)) - 1
+ *(*uint32)(&rb.tail_size_) = 1 << uint(tail_bits)
+ *(*uint32)(&rb.total_size_) = rb.size_ + rb.tail_size_
+}
+
+const kSlackForEightByteHashingEverywhere uint = 7
+
+/* Allocates or re-allocates data_ to the given length + plus some slack
+ region before and after. Fills the slack regions with zeros. */
+func ringBufferInitBuffer(buflen uint32, rb *ringBuffer) {
+ var new_data []byte
+ var i uint
+ size := 2 + int(buflen) + int(kSlackForEightByteHashingEverywhere)
+ if cap(rb.data_) < size {
+ new_data = make([]byte, size)
+ } else {
+ new_data = rb.data_[:size]
+ }
+ if rb.data_ != nil {
+ copy(new_data, rb.data_[:2+rb.cur_size_+uint32(kSlackForEightByteHashingEverywhere)])
+ }
+
+ rb.data_ = new_data
+ rb.cur_size_ = buflen
+ rb.buffer_ = rb.data_[2:]
+ rb.data_[1] = 0
+ rb.data_[0] = rb.data_[1]
+ for i = 0; i < kSlackForEightByteHashingEverywhere; i++ {
+ rb.buffer_[rb.cur_size_+uint32(i)] = 0
+ }
+}
+
+func ringBufferWriteTail(bytes []byte, n uint, rb *ringBuffer) {
+ var masked_pos uint = uint(rb.pos_ & rb.mask_)
+ if uint32(masked_pos) < rb.tail_size_ {
+ /* Just fill the tail buffer with the beginning data. */
+ var p uint = uint(rb.size_ + uint32(masked_pos))
+ copy(rb.buffer_[p:], bytes[:brotli_min_size_t(n, uint(rb.tail_size_-uint32(masked_pos)))])
+ }
+}
+
+/* Push bytes into the ring buffer. */
+func ringBufferWrite(bytes []byte, n uint, rb *ringBuffer) {
+ if rb.pos_ == 0 && uint32(n) < rb.tail_size_ {
+ /* Special case for the first write: to process the first block, we don't
+ need to allocate the whole ring-buffer and we don't need the tail
+ either. However, we do this memory usage optimization only if the
+ first write is less than the tail size, which is also the input block
+ size, otherwise it is likely that other blocks will follow and we
+ will need to reallocate to the full size anyway. */
+ rb.pos_ = uint32(n)
+
+ ringBufferInitBuffer(rb.pos_, rb)
+ copy(rb.buffer_, bytes[:n])
+ return
+ }
+
+ if rb.cur_size_ < rb.total_size_ {
+ /* Lazily allocate the full buffer. */
+ ringBufferInitBuffer(rb.total_size_, rb)
+
+ /* Initialize the last two bytes to zero, so that we don't have to worry
+ later when we copy the last two bytes to the first two positions. */
+ rb.buffer_[rb.size_-2] = 0
+
+ rb.buffer_[rb.size_-1] = 0
+ }
+ {
+ var masked_pos uint = uint(rb.pos_ & rb.mask_)
+
+ /* The length of the writes is limited so that we do not need to worry
+ about a write */
+ ringBufferWriteTail(bytes, n, rb)
+
+ if uint32(masked_pos+n) <= rb.size_ {
+ /* A single write fits. */
+ copy(rb.buffer_[masked_pos:], bytes[:n])
+ } else {
+ /* Split into two writes.
+ Copy into the end of the buffer, including the tail buffer. */
+ copy(rb.buffer_[masked_pos:], bytes[:brotli_min_size_t(n, uint(rb.total_size_-uint32(masked_pos)))])
+
+ /* Copy into the beginning of the buffer */
+ copy(rb.buffer_, bytes[rb.size_-uint32(masked_pos):][:uint32(n)-(rb.size_-uint32(masked_pos))])
+ }
+ }
+ {
+ var not_first_lap bool = rb.pos_&(1<<31) != 0
+ var rb_pos_mask uint32 = (1 << 31) - 1
+ rb.data_[0] = rb.buffer_[rb.size_-2]
+ rb.data_[1] = rb.buffer_[rb.size_-1]
+ rb.pos_ = (rb.pos_ & rb_pos_mask) + uint32(uint32(n)&rb_pos_mask)
+ if not_first_lap {
+ /* Wrap, but preserve not-a-first-lap feature. */
+ rb.pos_ |= 1 << 31
+ }
+ }
+}
diff --git a/vendor/github.com/andybalholm/brotli/state.go b/vendor/github.com/andybalholm/brotli/state.go
new file mode 100644
index 0000000..38d753e
--- /dev/null
+++ b/vendor/github.com/andybalholm/brotli/state.go
@@ -0,0 +1,294 @@
+package brotli
+
+import "io"
+
+/* Copyright 2015 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Brotli state for partial streaming decoding. */
+const (
+ stateUninited = iota
+ stateLargeWindowBits
+ stateInitialize
+ stateMetablockBegin
+ stateMetablockHeader
+ stateMetablockHeader2
+ stateContextModes
+ stateCommandBegin
+ stateCommandInner
+ stateCommandPostDecodeLiterals
+ stateCommandPostWrapCopy
+ stateUncompressed
+ stateMetadata
+ stateCommandInnerWrite
+ stateMetablockDone
+ stateCommandPostWrite1
+ stateCommandPostWrite2
+ stateHuffmanCode0
+ stateHuffmanCode1
+ stateHuffmanCode2
+ stateHuffmanCode3
+ stateContextMap1
+ stateContextMap2
+ stateTreeGroup
+ stateDone
+)
+
+const (
+ stateMetablockHeaderNone = iota
+ stateMetablockHeaderEmpty
+ stateMetablockHeaderNibbles
+ stateMetablockHeaderSize
+ stateMetablockHeaderUncompressed
+ stateMetablockHeaderReserved
+ stateMetablockHeaderBytes
+ stateMetablockHeaderMetadata
+)
+
+const (
+ stateUncompressedNone = iota
+ stateUncompressedWrite
+)
+
+const (
+ stateTreeGroupNone = iota
+ stateTreeGroupLoop
+)
+
+const (
+ stateContextMapNone = iota
+ stateContextMapReadPrefix
+ stateContextMapHuffman
+ stateContextMapDecode
+ stateContextMapTransform
+)
+
+const (
+ stateHuffmanNone = iota
+ stateHuffmanSimpleSize
+ stateHuffmanSimpleRead
+ stateHuffmanSimpleBuild
+ stateHuffmanComplex
+ stateHuffmanLengthSymbols
+)
+
+const (
+ stateDecodeUint8None = iota
+ stateDecodeUint8Short
+ stateDecodeUint8Long
+)
+
+const (
+ stateReadBlockLengthNone = iota
+ stateReadBlockLengthSuffix
+)
+
+type Reader struct {
+ src io.Reader
+ buf []byte // scratch space for reading from src
+ in []byte // current chunk to decode; usually aliases buf
+
+ state int
+ loop_counter int
+ br bitReader
+ buffer struct {
+ u64 uint64
+ u8 [8]byte
+ }
+ buffer_length uint32
+ pos int
+ max_backward_distance int
+ max_distance int
+ ringbuffer_size int
+ ringbuffer_mask int
+ dist_rb_idx int
+ dist_rb [4]int
+ error_code int
+ sub_loop_counter uint32
+ ringbuffer []byte
+ ringbuffer_end []byte
+ htree_command []huffmanCode
+ context_lookup []byte
+ context_map_slice []byte
+ dist_context_map_slice []byte
+ literal_hgroup huffmanTreeGroup
+ insert_copy_hgroup huffmanTreeGroup
+ distance_hgroup huffmanTreeGroup
+ block_type_trees []huffmanCode
+ block_len_trees []huffmanCode
+ trivial_literal_context int
+ distance_context int
+ meta_block_remaining_len int
+ block_length_index uint32
+ block_length [3]uint32
+ num_block_types [3]uint32
+ block_type_rb [6]uint32
+ distance_postfix_bits uint32
+ num_direct_distance_codes uint32
+ distance_postfix_mask int
+ num_dist_htrees uint32
+ dist_context_map []byte
+ literal_htree []huffmanCode
+ dist_htree_index byte
+ repeat_code_len uint32
+ prev_code_len uint32
+ copy_length int
+ distance_code int
+ rb_roundtrips uint
+ partial_pos_out uint
+ symbol uint32
+ repeat uint32
+ space uint32
+ table [32]huffmanCode
+ symbol_lists symbolList
+ symbols_lists_array [huffmanMaxCodeLength + 1 + numCommandSymbols]uint16
+ next_symbol [32]int
+ code_length_code_lengths [codeLengthCodes]byte
+ code_length_histo [16]uint16
+ htree_index int
+ next []huffmanCode
+ context_index uint32
+ max_run_length_prefix uint32
+ code uint32
+ context_map_table [huffmanMaxSize272]huffmanCode
+ substate_metablock_header int
+ substate_tree_group int
+ substate_context_map int
+ substate_uncompressed int
+ substate_huffman int
+ substate_decode_uint8 int
+ substate_read_block_length int
+ is_last_metablock uint
+ is_uncompressed uint
+ is_metadata uint
+ should_wrap_ringbuffer uint
+ canny_ringbuffer_allocation uint
+ large_window bool
+ size_nibbles uint
+ window_bits uint32
+ new_ringbuffer_size int
+ num_literal_htrees uint32
+ context_map []byte
+ context_modes []byte
+ dictionary *dictionary
+ transforms *transforms
+ trivial_literal_contexts [8]uint32
+}
+
+func decoderStateInit(s *Reader) bool {
+ s.error_code = 0 /* BROTLI_DECODER_NO_ERROR */
+
+ initBitReader(&s.br)
+ s.state = stateUninited
+ s.large_window = false
+ s.substate_metablock_header = stateMetablockHeaderNone
+ s.substate_tree_group = stateTreeGroupNone
+ s.substate_context_map = stateContextMapNone
+ s.substate_uncompressed = stateUncompressedNone
+ s.substate_huffman = stateHuffmanNone
+ s.substate_decode_uint8 = stateDecodeUint8None
+ s.substate_read_block_length = stateReadBlockLengthNone
+
+ s.buffer_length = 0
+ s.loop_counter = 0
+ s.pos = 0
+ s.rb_roundtrips = 0
+ s.partial_pos_out = 0
+
+ s.block_type_trees = nil
+ s.block_len_trees = nil
+ s.ringbuffer_size = 0
+ s.new_ringbuffer_size = 0
+ s.ringbuffer_mask = 0
+
+ s.context_map = nil
+ s.context_modes = nil
+ s.dist_context_map = nil
+ s.context_map_slice = nil
+ s.dist_context_map_slice = nil
+
+ s.sub_loop_counter = 0
+
+ s.literal_hgroup.codes = nil
+ s.literal_hgroup.htrees = nil
+ s.insert_copy_hgroup.codes = nil
+ s.insert_copy_hgroup.htrees = nil
+ s.distance_hgroup.codes = nil
+ s.distance_hgroup.htrees = nil
+
+ s.is_last_metablock = 0
+ s.is_uncompressed = 0
+ s.is_metadata = 0
+ s.should_wrap_ringbuffer = 0
+ s.canny_ringbuffer_allocation = 1
+
+ s.window_bits = 0
+ s.max_distance = 0
+ s.dist_rb[0] = 16
+ s.dist_rb[1] = 15
+ s.dist_rb[2] = 11
+ s.dist_rb[3] = 4
+ s.dist_rb_idx = 0
+ s.block_type_trees = nil
+ s.block_len_trees = nil
+
+ s.symbol_lists.storage = s.symbols_lists_array[:]
+ s.symbol_lists.offset = huffmanMaxCodeLength + 1
+
+ s.dictionary = getDictionary()
+ s.transforms = getTransforms()
+
+ return true
+}
+
+func decoderStateMetablockBegin(s *Reader) {
+ s.meta_block_remaining_len = 0
+ s.block_length[0] = 1 << 24
+ s.block_length[1] = 1 << 24
+ s.block_length[2] = 1 << 24
+ s.num_block_types[0] = 1
+ s.num_block_types[1] = 1
+ s.num_block_types[2] = 1
+ s.block_type_rb[0] = 1
+ s.block_type_rb[1] = 0
+ s.block_type_rb[2] = 1
+ s.block_type_rb[3] = 0
+ s.block_type_rb[4] = 1
+ s.block_type_rb[5] = 0
+ s.context_map = nil
+ s.context_modes = nil
+ s.dist_context_map = nil
+ s.context_map_slice = nil
+ s.literal_htree = nil
+ s.dist_context_map_slice = nil
+ s.dist_htree_index = 0
+ s.context_lookup = nil
+ s.literal_hgroup.codes = nil
+ s.literal_hgroup.htrees = nil
+ s.insert_copy_hgroup.codes = nil
+ s.insert_copy_hgroup.htrees = nil
+ s.distance_hgroup.codes = nil
+ s.distance_hgroup.htrees = nil
+}
+
+func decoderStateCleanupAfterMetablock(s *Reader) {
+ s.context_modes = nil
+ s.context_map = nil
+ s.dist_context_map = nil
+ s.literal_hgroup.htrees = nil
+ s.insert_copy_hgroup.htrees = nil
+ s.distance_hgroup.htrees = nil
+}
+
+func decoderHuffmanTreeGroupInit(s *Reader, group *huffmanTreeGroup, alphabet_size uint32, max_symbol uint32, ntrees uint32) bool {
+ var max_table_size uint = uint(kMaxHuffmanTableSize[(alphabet_size+31)>>5])
+ group.alphabet_size = uint16(alphabet_size)
+ group.max_symbol = uint16(max_symbol)
+ group.num_htrees = uint16(ntrees)
+ group.htrees = make([][]huffmanCode, ntrees)
+ group.codes = make([]huffmanCode, (uint(ntrees) * max_table_size))
+ return !(group.codes == nil)
+}
diff --git a/vendor/github.com/andybalholm/brotli/static_dict.go b/vendor/github.com/andybalholm/brotli/static_dict.go
new file mode 100644
index 0000000..bc05566
--- /dev/null
+++ b/vendor/github.com/andybalholm/brotli/static_dict.go
@@ -0,0 +1,662 @@
+package brotli
+
+import "encoding/binary"
+
+/* Copyright 2013 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Class to model the static dictionary. */
+
+const maxStaticDictionaryMatchLen = 37
+
+const kInvalidMatch uint32 = 0xFFFFFFF
+
+/* Copyright 2013 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+func hash(data []byte) uint32 {
+ var h uint32 = binary.LittleEndian.Uint32(data) * kDictHashMul32
+
+ /* The higher bits contain more mixture from the multiplication,
+ so we take our results from there. */
+ return h >> uint(32-kDictNumBits)
+}
+
+func addMatch(distance uint, len uint, len_code uint, matches []uint32) {
+ var match uint32 = uint32((distance << 5) + len_code)
+ matches[len] = brotli_min_uint32_t(matches[len], match)
+}
+
+func dictMatchLength(dict *dictionary, data []byte, id uint, len uint, maxlen uint) uint {
+ var offset uint = uint(dict.offsets_by_length[len]) + len*id
+ return findMatchLengthWithLimit(dict.data[offset:], data, brotli_min_size_t(uint(len), maxlen))
+}
+
+func isMatch(d *dictionary, w dictWord, data []byte, max_length uint) bool {
+ if uint(w.len) > max_length {
+ return false
+ } else {
+ var offset uint = uint(d.offsets_by_length[w.len]) + uint(w.len)*uint(w.idx)
+ var dict []byte = d.data[offset:]
+ if w.transform == 0 {
+ /* Match against base dictionary word. */
+ return findMatchLengthWithLimit(dict, data, uint(w.len)) == uint(w.len)
+ } else if w.transform == 10 {
+ /* Match against uppercase first transform.
+ Note that there are only ASCII uppercase words in the lookup table. */
+ return dict[0] >= 'a' && dict[0] <= 'z' && (dict[0]^32) == data[0] && findMatchLengthWithLimit(dict[1:], data[1:], uint(w.len)-1) == uint(w.len-1)
+ } else {
+ /* Match against uppercase all transform.
+ Note that there are only ASCII uppercase words in the lookup table. */
+ var i uint
+ for i = 0; i < uint(w.len); i++ {
+ if dict[i] >= 'a' && dict[i] <= 'z' {
+ if (dict[i] ^ 32) != data[i] {
+ return false
+ }
+ } else {
+ if dict[i] != data[i] {
+ return false
+ }
+ }
+ }
+
+ return true
+ }
+ }
+}
+
+func findAllStaticDictionaryMatches(dict *encoderDictionary, data []byte, min_length uint, max_length uint, matches []uint32) bool {
+ var has_found_match bool = false
+ {
+ var offset uint = uint(dict.buckets[hash(data)])
+ var end bool = offset == 0
+ for !end {
+ w := dict.dict_words[offset]
+ offset++
+ var l uint = uint(w.len) & 0x1F
+ var n uint = uint(1) << dict.words.size_bits_by_length[l]
+ var id uint = uint(w.idx)
+ end = !(w.len&0x80 == 0)
+ w.len = byte(l)
+ if w.transform == 0 {
+ var matchlen uint = dictMatchLength(dict.words, data, id, l, max_length)
+ var s []byte
+ var minlen uint
+ var maxlen uint
+ var len uint
+
+ /* Transform "" + BROTLI_TRANSFORM_IDENTITY + "" */
+ if matchlen == l {
+ addMatch(id, l, l, matches)
+ has_found_match = true
+ }
+
+ /* Transforms "" + BROTLI_TRANSFORM_OMIT_LAST_1 + "" and
+ "" + BROTLI_TRANSFORM_OMIT_LAST_1 + "ing " */
+ if matchlen >= l-1 {
+ addMatch(id+12*n, l-1, l, matches)
+ if l+2 < max_length && data[l-1] == 'i' && data[l] == 'n' && data[l+1] == 'g' && data[l+2] == ' ' {
+ addMatch(id+49*n, l+3, l, matches)
+ }
+
+ has_found_match = true
+ }
+
+ /* Transform "" + BROTLI_TRANSFORM_OMIT_LAST_# + "" (# = 2 .. 9) */
+ minlen = min_length
+
+ if l > 9 {
+ minlen = brotli_max_size_t(minlen, l-9)
+ }
+ maxlen = brotli_min_size_t(matchlen, l-2)
+ for len = minlen; len <= maxlen; len++ {
+ var cut uint = l - len
+ var transform_id uint = (cut << 2) + uint((dict.cutoffTransforms>>(cut*6))&0x3F)
+ addMatch(id+transform_id*n, uint(len), l, matches)
+ has_found_match = true
+ }
+
+ if matchlen < l || l+6 >= max_length {
+ continue
+ }
+
+ s = data[l:]
+
+ /* Transforms "" + BROTLI_TRANSFORM_IDENTITY + */
+ if s[0] == ' ' {
+ addMatch(id+n, l+1, l, matches)
+ if s[1] == 'a' {
+ if s[2] == ' ' {
+ addMatch(id+28*n, l+3, l, matches)
+ } else if s[2] == 's' {
+ if s[3] == ' ' {
+ addMatch(id+46*n, l+4, l, matches)
+ }
+ } else if s[2] == 't' {
+ if s[3] == ' ' {
+ addMatch(id+60*n, l+4, l, matches)
+ }
+ } else if s[2] == 'n' {
+ if s[3] == 'd' && s[4] == ' ' {
+ addMatch(id+10*n, l+5, l, matches)
+ }
+ }
+ } else if s[1] == 'b' {
+ if s[2] == 'y' && s[3] == ' ' {
+ addMatch(id+38*n, l+4, l, matches)
+ }
+ } else if s[1] == 'i' {
+ if s[2] == 'n' {
+ if s[3] == ' ' {
+ addMatch(id+16*n, l+4, l, matches)
+ }
+ } else if s[2] == 's' {
+ if s[3] == ' ' {
+ addMatch(id+47*n, l+4, l, matches)
+ }
+ }
+ } else if s[1] == 'f' {
+ if s[2] == 'o' {
+ if s[3] == 'r' && s[4] == ' ' {
+ addMatch(id+25*n, l+5, l, matches)
+ }
+ } else if s[2] == 'r' {
+ if s[3] == 'o' && s[4] == 'm' && s[5] == ' ' {
+ addMatch(id+37*n, l+6, l, matches)
+ }
+ }
+ } else if s[1] == 'o' {
+ if s[2] == 'f' {
+ if s[3] == ' ' {
+ addMatch(id+8*n, l+4, l, matches)
+ }
+ } else if s[2] == 'n' {
+ if s[3] == ' ' {
+ addMatch(id+45*n, l+4, l, matches)
+ }
+ }
+ } else if s[1] == 'n' {
+ if s[2] == 'o' && s[3] == 't' && s[4] == ' ' {
+ addMatch(id+80*n, l+5, l, matches)
+ }
+ } else if s[1] == 't' {
+ if s[2] == 'h' {
+ if s[3] == 'e' {
+ if s[4] == ' ' {
+ addMatch(id+5*n, l+5, l, matches)
+ }
+ } else if s[3] == 'a' {
+ if s[4] == 't' && s[5] == ' ' {
+ addMatch(id+29*n, l+6, l, matches)
+ }
+ }
+ } else if s[2] == 'o' {
+ if s[3] == ' ' {
+ addMatch(id+17*n, l+4, l, matches)
+ }
+ }
+ } else if s[1] == 'w' {
+ if s[2] == 'i' && s[3] == 't' && s[4] == 'h' && s[5] == ' ' {
+ addMatch(id+35*n, l+6, l, matches)
+ }
+ }
+ } else if s[0] == '"' {
+ addMatch(id+19*n, l+1, l, matches)
+ if s[1] == '>' {
+ addMatch(id+21*n, l+2, l, matches)
+ }
+ } else if s[0] == '.' {
+ addMatch(id+20*n, l+1, l, matches)
+ if s[1] == ' ' {
+ addMatch(id+31*n, l+2, l, matches)
+ if s[2] == 'T' && s[3] == 'h' {
+ if s[4] == 'e' {
+ if s[5] == ' ' {
+ addMatch(id+43*n, l+6, l, matches)
+ }
+ } else if s[4] == 'i' {
+ if s[5] == 's' && s[6] == ' ' {
+ addMatch(id+75*n, l+7, l, matches)
+ }
+ }
+ }
+ }
+ } else if s[0] == ',' {
+ addMatch(id+76*n, l+1, l, matches)
+ if s[1] == ' ' {
+ addMatch(id+14*n, l+2, l, matches)
+ }
+ } else if s[0] == '\n' {
+ addMatch(id+22*n, l+1, l, matches)
+ if s[1] == '\t' {
+ addMatch(id+50*n, l+2, l, matches)
+ }
+ } else if s[0] == ']' {
+ addMatch(id+24*n, l+1, l, matches)
+ } else if s[0] == '\'' {
+ addMatch(id+36*n, l+1, l, matches)
+ } else if s[0] == ':' {
+ addMatch(id+51*n, l+1, l, matches)
+ } else if s[0] == '(' {
+ addMatch(id+57*n, l+1, l, matches)
+ } else if s[0] == '=' {
+ if s[1] == '"' {
+ addMatch(id+70*n, l+2, l, matches)
+ } else if s[1] == '\'' {
+ addMatch(id+86*n, l+2, l, matches)
+ }
+ } else if s[0] == 'a' {
+ if s[1] == 'l' && s[2] == ' ' {
+ addMatch(id+84*n, l+3, l, matches)
+ }
+ } else if s[0] == 'e' {
+ if s[1] == 'd' {
+ if s[2] == ' ' {
+ addMatch(id+53*n, l+3, l, matches)
+ }
+ } else if s[1] == 'r' {
+ if s[2] == ' ' {
+ addMatch(id+82*n, l+3, l, matches)
+ }
+ } else if s[1] == 's' {
+ if s[2] == 't' && s[3] == ' ' {
+ addMatch(id+95*n, l+4, l, matches)
+ }
+ }
+ } else if s[0] == 'f' {
+ if s[1] == 'u' && s[2] == 'l' && s[3] == ' ' {
+ addMatch(id+90*n, l+4, l, matches)
+ }
+ } else if s[0] == 'i' {
+ if s[1] == 'v' {
+ if s[2] == 'e' && s[3] == ' ' {
+ addMatch(id+92*n, l+4, l, matches)
+ }
+ } else if s[1] == 'z' {
+ if s[2] == 'e' && s[3] == ' ' {
+ addMatch(id+100*n, l+4, l, matches)
+ }
+ }
+ } else if s[0] == 'l' {
+ if s[1] == 'e' {
+ if s[2] == 's' && s[3] == 's' && s[4] == ' ' {
+ addMatch(id+93*n, l+5, l, matches)
+ }
+ } else if s[1] == 'y' {
+ if s[2] == ' ' {
+ addMatch(id+61*n, l+3, l, matches)
+ }
+ }
+ } else if s[0] == 'o' {
+ if s[1] == 'u' && s[2] == 's' && s[3] == ' ' {
+ addMatch(id+106*n, l+4, l, matches)
+ }
+ }
+ } else {
+ var is_all_caps bool = (w.transform != transformUppercaseFirst)
+ /* Set is_all_caps=0 for BROTLI_TRANSFORM_UPPERCASE_FIRST and
+ is_all_caps=1 otherwise (BROTLI_TRANSFORM_UPPERCASE_ALL)
+ transform. */
+
+ var s []byte
+ if !isMatch(dict.words, w, data, max_length) {
+ continue
+ }
+
+ /* Transform "" + kUppercase{First,All} + "" */
+ var tmp int
+ if is_all_caps {
+ tmp = 44
+ } else {
+ tmp = 9
+ }
+ addMatch(id+uint(tmp)*n, l, l, matches)
+
+ has_found_match = true
+ if l+1 >= max_length {
+ continue
+ }
+
+ /* Transforms "" + kUppercase{First,All} + */
+ s = data[l:]
+
+ if s[0] == ' ' {
+ var tmp int
+ if is_all_caps {
+ tmp = 68
+ } else {
+ tmp = 4
+ }
+ addMatch(id+uint(tmp)*n, l+1, l, matches)
+ } else if s[0] == '"' {
+ var tmp int
+ if is_all_caps {
+ tmp = 87
+ } else {
+ tmp = 66
+ }
+ addMatch(id+uint(tmp)*n, l+1, l, matches)
+ if s[1] == '>' {
+ var tmp int
+ if is_all_caps {
+ tmp = 97
+ } else {
+ tmp = 69
+ }
+ addMatch(id+uint(tmp)*n, l+2, l, matches)
+ }
+ } else if s[0] == '.' {
+ var tmp int
+ if is_all_caps {
+ tmp = 101
+ } else {
+ tmp = 79
+ }
+ addMatch(id+uint(tmp)*n, l+1, l, matches)
+ if s[1] == ' ' {
+ var tmp int
+ if is_all_caps {
+ tmp = 114
+ } else {
+ tmp = 88
+ }
+ addMatch(id+uint(tmp)*n, l+2, l, matches)
+ }
+ } else if s[0] == ',' {
+ var tmp int
+ if is_all_caps {
+ tmp = 112
+ } else {
+ tmp = 99
+ }
+ addMatch(id+uint(tmp)*n, l+1, l, matches)
+ if s[1] == ' ' {
+ var tmp int
+ if is_all_caps {
+ tmp = 107
+ } else {
+ tmp = 58
+ }
+ addMatch(id+uint(tmp)*n, l+2, l, matches)
+ }
+ } else if s[0] == '\'' {
+ var tmp int
+ if is_all_caps {
+ tmp = 94
+ } else {
+ tmp = 74
+ }
+ addMatch(id+uint(tmp)*n, l+1, l, matches)
+ } else if s[0] == '(' {
+ var tmp int
+ if is_all_caps {
+ tmp = 113
+ } else {
+ tmp = 78
+ }
+ addMatch(id+uint(tmp)*n, l+1, l, matches)
+ } else if s[0] == '=' {
+ if s[1] == '"' {
+ var tmp int
+ if is_all_caps {
+ tmp = 105
+ } else {
+ tmp = 104
+ }
+ addMatch(id+uint(tmp)*n, l+2, l, matches)
+ } else if s[1] == '\'' {
+ var tmp int
+ if is_all_caps {
+ tmp = 116
+ } else {
+ tmp = 108
+ }
+ addMatch(id+uint(tmp)*n, l+2, l, matches)
+ }
+ }
+ }
+ }
+ }
+
+ /* Transforms with prefixes " " and "." */
+ if max_length >= 5 && (data[0] == ' ' || data[0] == '.') {
+ var is_space bool = (data[0] == ' ')
+ var offset uint = uint(dict.buckets[hash(data[1:])])
+ var end bool = offset == 0
+ for !end {
+ w := dict.dict_words[offset]
+ offset++
+ var l uint = uint(w.len) & 0x1F
+ var n uint = uint(1) << dict.words.size_bits_by_length[l]
+ var id uint = uint(w.idx)
+ end = !(w.len&0x80 == 0)
+ w.len = byte(l)
+ if w.transform == 0 {
+ var s []byte
+ if !isMatch(dict.words, w, data[1:], max_length-1) {
+ continue
+ }
+
+ /* Transforms " " + BROTLI_TRANSFORM_IDENTITY + "" and
+ "." + BROTLI_TRANSFORM_IDENTITY + "" */
+ var tmp int
+ if is_space {
+ tmp = 6
+ } else {
+ tmp = 32
+ }
+ addMatch(id+uint(tmp)*n, l+1, l, matches)
+
+ has_found_match = true
+ if l+2 >= max_length {
+ continue
+ }
+
+ /* Transforms " " + BROTLI_TRANSFORM_IDENTITY + and
+ "." + BROTLI_TRANSFORM_IDENTITY +
+ */
+ s = data[l+1:]
+
+ if s[0] == ' ' {
+ var tmp int
+ if is_space {
+ tmp = 2
+ } else {
+ tmp = 77
+ }
+ addMatch(id+uint(tmp)*n, l+2, l, matches)
+ } else if s[0] == '(' {
+ var tmp int
+ if is_space {
+ tmp = 89
+ } else {
+ tmp = 67
+ }
+ addMatch(id+uint(tmp)*n, l+2, l, matches)
+ } else if is_space {
+ if s[0] == ',' {
+ addMatch(id+103*n, l+2, l, matches)
+ if s[1] == ' ' {
+ addMatch(id+33*n, l+3, l, matches)
+ }
+ } else if s[0] == '.' {
+ addMatch(id+71*n, l+2, l, matches)
+ if s[1] == ' ' {
+ addMatch(id+52*n, l+3, l, matches)
+ }
+ } else if s[0] == '=' {
+ if s[1] == '"' {
+ addMatch(id+81*n, l+3, l, matches)
+ } else if s[1] == '\'' {
+ addMatch(id+98*n, l+3, l, matches)
+ }
+ }
+ }
+ } else if is_space {
+ var is_all_caps bool = (w.transform != transformUppercaseFirst)
+ /* Set is_all_caps=0 for BROTLI_TRANSFORM_UPPERCASE_FIRST and
+ is_all_caps=1 otherwise (BROTLI_TRANSFORM_UPPERCASE_ALL)
+ transform. */
+
+ var s []byte
+ if !isMatch(dict.words, w, data[1:], max_length-1) {
+ continue
+ }
+
+ /* Transforms " " + kUppercase{First,All} + "" */
+ var tmp int
+ if is_all_caps {
+ tmp = 85
+ } else {
+ tmp = 30
+ }
+ addMatch(id+uint(tmp)*n, l+1, l, matches)
+
+ has_found_match = true
+ if l+2 >= max_length {
+ continue
+ }
+
+ /* Transforms " " + kUppercase{First,All} + */
+ s = data[l+1:]
+
+ if s[0] == ' ' {
+ var tmp int
+ if is_all_caps {
+ tmp = 83
+ } else {
+ tmp = 15
+ }
+ addMatch(id+uint(tmp)*n, l+2, l, matches)
+ } else if s[0] == ',' {
+ if !is_all_caps {
+ addMatch(id+109*n, l+2, l, matches)
+ }
+
+ if s[1] == ' ' {
+ var tmp int
+ if is_all_caps {
+ tmp = 111
+ } else {
+ tmp = 65
+ }
+ addMatch(id+uint(tmp)*n, l+3, l, matches)
+ }
+ } else if s[0] == '.' {
+ var tmp int
+ if is_all_caps {
+ tmp = 115
+ } else {
+ tmp = 96
+ }
+ addMatch(id+uint(tmp)*n, l+2, l, matches)
+ if s[1] == ' ' {
+ var tmp int
+ if is_all_caps {
+ tmp = 117
+ } else {
+ tmp = 91
+ }
+ addMatch(id+uint(tmp)*n, l+3, l, matches)
+ }
+ } else if s[0] == '=' {
+ if s[1] == '"' {
+ var tmp int
+ if is_all_caps {
+ tmp = 110
+ } else {
+ tmp = 118
+ }
+ addMatch(id+uint(tmp)*n, l+3, l, matches)
+ } else if s[1] == '\'' {
+ var tmp int
+ if is_all_caps {
+ tmp = 119
+ } else {
+ tmp = 120
+ }
+ addMatch(id+uint(tmp)*n, l+3, l, matches)
+ }
+ }
+ }
+ }
+ }
+
+ if max_length >= 6 {
+ /* Transforms with prefixes "e ", "s ", ", " and "\xC2\xA0" */
+ if (data[1] == ' ' && (data[0] == 'e' || data[0] == 's' || data[0] == ',')) || (data[0] == 0xC2 && data[1] == 0xA0) {
+ var offset uint = uint(dict.buckets[hash(data[2:])])
+ var end bool = offset == 0
+ for !end {
+ w := dict.dict_words[offset]
+ offset++
+ var l uint = uint(w.len) & 0x1F
+ var n uint = uint(1) << dict.words.size_bits_by_length[l]
+ var id uint = uint(w.idx)
+ end = !(w.len&0x80 == 0)
+ w.len = byte(l)
+ if w.transform == 0 && isMatch(dict.words, w, data[2:], max_length-2) {
+ if data[0] == 0xC2 {
+ addMatch(id+102*n, l+2, l, matches)
+ has_found_match = true
+ } else if l+2 < max_length && data[l+2] == ' ' {
+ var t uint = 13
+ if data[0] == 'e' {
+ t = 18
+ } else if data[0] == 's' {
+ t = 7
+ }
+ addMatch(id+t*n, l+3, l, matches)
+ has_found_match = true
+ }
+ }
+ }
+ }
+ }
+
+ if max_length >= 9 {
+ /* Transforms with prefixes " the " and ".com/" */
+ if (data[0] == ' ' && data[1] == 't' && data[2] == 'h' && data[3] == 'e' && data[4] == ' ') || (data[0] == '.' && data[1] == 'c' && data[2] == 'o' && data[3] == 'm' && data[4] == '/') {
+ var offset uint = uint(dict.buckets[hash(data[5:])])
+ var end bool = offset == 0
+ for !end {
+ w := dict.dict_words[offset]
+ offset++
+ var l uint = uint(w.len) & 0x1F
+ var n uint = uint(1) << dict.words.size_bits_by_length[l]
+ var id uint = uint(w.idx)
+ end = !(w.len&0x80 == 0)
+ w.len = byte(l)
+ if w.transform == 0 && isMatch(dict.words, w, data[5:], max_length-5) {
+ var tmp int
+ if data[0] == ' ' {
+ tmp = 41
+ } else {
+ tmp = 72
+ }
+ addMatch(id+uint(tmp)*n, l+5, l, matches)
+ has_found_match = true
+ if l+5 < max_length {
+ var s []byte = data[l+5:]
+ if data[0] == ' ' {
+ if l+8 < max_length && s[0] == ' ' && s[1] == 'o' && s[2] == 'f' && s[3] == ' ' {
+ addMatch(id+62*n, l+9, l, matches)
+ if l+12 < max_length && s[4] == 't' && s[5] == 'h' && s[6] == 'e' && s[7] == ' ' {
+ addMatch(id+73*n, l+13, l, matches)
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return has_found_match
+}
diff --git a/vendor/github.com/andybalholm/brotli/static_dict_lut.go b/vendor/github.com/andybalholm/brotli/static_dict_lut.go
new file mode 100644
index 0000000..b33963e
--- /dev/null
+++ b/vendor/github.com/andybalholm/brotli/static_dict_lut.go
@@ -0,0 +1,75094 @@
+package brotli
+
+/* Copyright 2017 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Lookup table for static dictionary and transforms. */
+
+type dictWord struct {
+ len byte
+ transform byte
+ idx uint16
+}
+
+const kDictNumBits int = 15
+
+const kDictHashMul32 uint32 = 0x1E35A7BD
+
+var kStaticDictionaryBuckets = [32768]uint16{
+ 1,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3,
+ 6,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20,
+ 0,
+ 0,
+ 0,
+ 21,
+ 0,
+ 22,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23,
+ 0,
+ 0,
+ 25,
+ 0,
+ 29,
+ 0,
+ 53,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 55,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 61,
+ 76,
+ 0,
+ 0,
+ 0,
+ 94,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 96,
+ 0,
+ 97,
+ 0,
+ 98,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 99,
+ 101,
+ 106,
+ 108,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 110,
+ 0,
+ 111,
+ 112,
+ 0,
+ 113,
+ 118,
+ 124,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 125,
+ 128,
+ 0,
+ 0,
+ 0,
+ 0,
+ 129,
+ 0,
+ 0,
+ 131,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 132,
+ 0,
+ 0,
+ 135,
+ 0,
+ 0,
+ 0,
+ 137,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 138,
+ 139,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 142,
+ 143,
+ 144,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 145,
+ 0,
+ 0,
+ 0,
+ 146,
+ 149,
+ 151,
+ 152,
+ 0,
+ 0,
+ 153,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 154,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 155,
+ 0,
+ 0,
+ 0,
+ 0,
+ 160,
+ 182,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 183,
+ 0,
+ 0,
+ 0,
+ 188,
+ 189,
+ 0,
+ 0,
+ 192,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 194,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 197,
+ 202,
+ 209,
+ 0,
+ 0,
+ 210,
+ 0,
+ 224,
+ 0,
+ 0,
+ 0,
+ 225,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 231,
+ 0,
+ 0,
+ 0,
+ 232,
+ 0,
+ 240,
+ 0,
+ 0,
+ 242,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 244,
+ 0,
+ 0,
+ 0,
+ 246,
+ 0,
+ 0,
+ 249,
+ 251,
+ 253,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 258,
+ 0,
+ 0,
+ 261,
+ 263,
+ 0,
+ 0,
+ 0,
+ 267,
+ 0,
+ 0,
+ 268,
+ 0,
+ 269,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 271,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 272,
+ 0,
+ 273,
+ 0,
+ 277,
+ 0,
+ 278,
+ 286,
+ 0,
+ 0,
+ 0,
+ 0,
+ 287,
+ 0,
+ 289,
+ 290,
+ 291,
+ 0,
+ 0,
+ 0,
+ 295,
+ 0,
+ 0,
+ 296,
+ 297,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 298,
+ 0,
+ 0,
+ 0,
+ 299,
+ 0,
+ 0,
+ 305,
+ 0,
+ 324,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 327,
+ 0,
+ 328,
+ 329,
+ 0,
+ 0,
+ 0,
+ 0,
+ 336,
+ 0,
+ 0,
+ 340,
+ 0,
+ 341,
+ 342,
+ 343,
+ 0,
+ 0,
+ 346,
+ 0,
+ 348,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 349,
+ 351,
+ 0,
+ 0,
+ 355,
+ 0,
+ 363,
+ 0,
+ 364,
+ 0,
+ 368,
+ 369,
+ 0,
+ 370,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 372,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 373,
+ 0,
+ 375,
+ 0,
+ 0,
+ 0,
+ 0,
+ 376,
+ 377,
+ 0,
+ 0,
+ 394,
+ 395,
+ 396,
+ 0,
+ 0,
+ 398,
+ 0,
+ 0,
+ 0,
+ 0,
+ 400,
+ 0,
+ 0,
+ 408,
+ 0,
+ 0,
+ 0,
+ 0,
+ 420,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 421,
+ 0,
+ 0,
+ 422,
+ 423,
+ 0,
+ 0,
+ 429,
+ 435,
+ 436,
+ 442,
+ 0,
+ 0,
+ 443,
+ 0,
+ 444,
+ 445,
+ 453,
+ 456,
+ 0,
+ 457,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 458,
+ 0,
+ 0,
+ 0,
+ 459,
+ 0,
+ 0,
+ 0,
+ 460,
+ 0,
+ 462,
+ 463,
+ 465,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 466,
+ 469,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 470,
+ 0,
+ 0,
+ 0,
+ 474,
+ 0,
+ 476,
+ 0,
+ 0,
+ 0,
+ 0,
+ 483,
+ 0,
+ 485,
+ 0,
+ 0,
+ 0,
+ 486,
+ 0,
+ 0,
+ 488,
+ 491,
+ 492,
+ 0,
+ 0,
+ 497,
+ 499,
+ 500,
+ 0,
+ 501,
+ 0,
+ 0,
+ 0,
+ 505,
+ 0,
+ 0,
+ 506,
+ 0,
+ 0,
+ 0,
+ 507,
+ 0,
+ 0,
+ 0,
+ 509,
+ 0,
+ 0,
+ 0,
+ 0,
+ 511,
+ 512,
+ 519,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 529,
+ 530,
+ 0,
+ 0,
+ 0,
+ 534,
+ 0,
+ 0,
+ 0,
+ 0,
+ 543,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 553,
+ 0,
+ 0,
+ 0,
+ 0,
+ 557,
+ 560,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 561,
+ 0,
+ 564,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 565,
+ 566,
+ 0,
+ 575,
+ 0,
+ 619,
+ 0,
+ 620,
+ 0,
+ 0,
+ 623,
+ 624,
+ 0,
+ 0,
+ 0,
+ 625,
+ 0,
+ 0,
+ 626,
+ 627,
+ 0,
+ 0,
+ 628,
+ 0,
+ 0,
+ 0,
+ 0,
+ 630,
+ 0,
+ 631,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 641,
+ 0,
+ 0,
+ 0,
+ 0,
+ 643,
+ 656,
+ 668,
+ 0,
+ 0,
+ 0,
+ 673,
+ 0,
+ 0,
+ 0,
+ 674,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 682,
+ 0,
+ 687,
+ 0,
+ 690,
+ 0,
+ 693,
+ 699,
+ 700,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 704,
+ 705,
+ 0,
+ 0,
+ 0,
+ 0,
+ 707,
+ 710,
+ 0,
+ 711,
+ 0,
+ 0,
+ 0,
+ 0,
+ 726,
+ 0,
+ 0,
+ 729,
+ 0,
+ 0,
+ 0,
+ 730,
+ 731,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 752,
+ 0,
+ 0,
+ 0,
+ 762,
+ 0,
+ 763,
+ 0,
+ 0,
+ 767,
+ 0,
+ 0,
+ 0,
+ 770,
+ 774,
+ 0,
+ 0,
+ 775,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 776,
+ 0,
+ 0,
+ 0,
+ 777,
+ 783,
+ 0,
+ 0,
+ 0,
+ 785,
+ 788,
+ 0,
+ 0,
+ 0,
+ 0,
+ 790,
+ 0,
+ 0,
+ 0,
+ 793,
+ 0,
+ 0,
+ 0,
+ 0,
+ 794,
+ 0,
+ 0,
+ 804,
+ 819,
+ 821,
+ 0,
+ 827,
+ 0,
+ 0,
+ 0,
+ 834,
+ 0,
+ 0,
+ 835,
+ 0,
+ 0,
+ 0,
+ 841,
+ 0,
+ 844,
+ 0,
+ 850,
+ 851,
+ 859,
+ 0,
+ 860,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 874,
+ 0,
+ 876,
+ 0,
+ 877,
+ 890,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 893,
+ 894,
+ 898,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 899,
+ 0,
+ 0,
+ 0,
+ 900,
+ 904,
+ 906,
+ 0,
+ 0,
+ 0,
+ 907,
+ 0,
+ 908,
+ 909,
+ 0,
+ 910,
+ 0,
+ 0,
+ 0,
+ 0,
+ 911,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 916,
+ 0,
+ 0,
+ 0,
+ 922,
+ 925,
+ 0,
+ 930,
+ 0,
+ 934,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 943,
+ 0,
+ 0,
+ 944,
+ 0,
+ 953,
+ 954,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 955,
+ 0,
+ 962,
+ 963,
+ 0,
+ 0,
+ 976,
+ 0,
+ 0,
+ 977,
+ 978,
+ 979,
+ 980,
+ 0,
+ 981,
+ 0,
+ 0,
+ 0,
+ 0,
+ 984,
+ 0,
+ 0,
+ 985,
+ 0,
+ 0,
+ 987,
+ 989,
+ 991,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 992,
+ 0,
+ 0,
+ 0,
+ 993,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 996,
+ 0,
+ 0,
+ 0,
+ 1000,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1002,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1005,
+ 1007,
+ 0,
+ 0,
+ 0,
+ 1009,
+ 0,
+ 0,
+ 0,
+ 1010,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1011,
+ 0,
+ 1012,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1014,
+ 1016,
+ 0,
+ 0,
+ 0,
+ 1020,
+ 0,
+ 1021,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1022,
+ 0,
+ 0,
+ 0,
+ 1024,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1025,
+ 0,
+ 0,
+ 1026,
+ 1027,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1031,
+ 0,
+ 1033,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1034,
+ 0,
+ 0,
+ 0,
+ 1037,
+ 1040,
+ 0,
+ 0,
+ 0,
+ 1042,
+ 1043,
+ 0,
+ 0,
+ 1053,
+ 0,
+ 1054,
+ 0,
+ 0,
+ 1057,
+ 0,
+ 0,
+ 0,
+ 1058,
+ 0,
+ 0,
+ 1060,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1061,
+ 0,
+ 0,
+ 1062,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1063,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1064,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1065,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1066,
+ 1067,
+ 0,
+ 0,
+ 0,
+ 1069,
+ 1070,
+ 1072,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1073,
+ 0,
+ 1075,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1080,
+ 1084,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1088,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1094,
+ 0,
+ 1095,
+ 0,
+ 1107,
+ 0,
+ 0,
+ 0,
+ 1112,
+ 1114,
+ 0,
+ 1119,
+ 0,
+ 1122,
+ 0,
+ 0,
+ 1126,
+ 0,
+ 1129,
+ 0,
+ 1130,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1132,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1144,
+ 0,
+ 0,
+ 1145,
+ 1146,
+ 0,
+ 1148,
+ 1149,
+ 0,
+ 0,
+ 1150,
+ 1151,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1152,
+ 0,
+ 1153,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1154,
+ 0,
+ 1163,
+ 0,
+ 0,
+ 0,
+ 1164,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1165,
+ 0,
+ 1167,
+ 0,
+ 1170,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1171,
+ 1172,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1173,
+ 1175,
+ 1177,
+ 0,
+ 1186,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1195,
+ 0,
+ 0,
+ 1221,
+ 0,
+ 0,
+ 1224,
+ 0,
+ 0,
+ 1227,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1228,
+ 1229,
+ 0,
+ 0,
+ 1230,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1231,
+ 0,
+ 0,
+ 0,
+ 1233,
+ 0,
+ 0,
+ 1243,
+ 1244,
+ 1246,
+ 1248,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1254,
+ 1255,
+ 1258,
+ 1259,
+ 0,
+ 0,
+ 0,
+ 1260,
+ 0,
+ 0,
+ 1261,
+ 0,
+ 0,
+ 0,
+ 1262,
+ 1264,
+ 0,
+ 0,
+ 1265,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1266,
+ 0,
+ 1267,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1273,
+ 1274,
+ 1276,
+ 1289,
+ 0,
+ 0,
+ 1291,
+ 1292,
+ 1293,
+ 0,
+ 0,
+ 1294,
+ 1295,
+ 1296,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1302,
+ 0,
+ 1304,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1311,
+ 1312,
+ 0,
+ 1314,
+ 0,
+ 1316,
+ 1320,
+ 1321,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1322,
+ 1323,
+ 1324,
+ 0,
+ 1335,
+ 0,
+ 1336,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1341,
+ 1342,
+ 0,
+ 1346,
+ 0,
+ 1357,
+ 0,
+ 0,
+ 0,
+ 1358,
+ 1360,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1361,
+ 0,
+ 0,
+ 0,
+ 1362,
+ 1365,
+ 0,
+ 1366,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1379,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1386,
+ 0,
+ 1388,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1395,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1403,
+ 0,
+ 1405,
+ 0,
+ 0,
+ 1407,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1408,
+ 1409,
+ 0,
+ 1410,
+ 0,
+ 0,
+ 0,
+ 1412,
+ 1413,
+ 1416,
+ 0,
+ 0,
+ 1429,
+ 1451,
+ 0,
+ 0,
+ 1454,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1455,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1456,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1459,
+ 1460,
+ 1461,
+ 1475,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1477,
+ 0,
+ 1480,
+ 0,
+ 1481,
+ 0,
+ 0,
+ 1486,
+ 0,
+ 0,
+ 1495,
+ 0,
+ 0,
+ 0,
+ 1496,
+ 0,
+ 0,
+ 1498,
+ 1499,
+ 1501,
+ 1520,
+ 1521,
+ 0,
+ 0,
+ 0,
+ 1526,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1528,
+ 1529,
+ 0,
+ 1533,
+ 1536,
+ 0,
+ 0,
+ 0,
+ 1537,
+ 1538,
+ 1549,
+ 0,
+ 1550,
+ 1558,
+ 1559,
+ 1572,
+ 0,
+ 1573,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1575,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1579,
+ 0,
+ 1599,
+ 0,
+ 1603,
+ 0,
+ 1604,
+ 0,
+ 1605,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1608,
+ 1610,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1611,
+ 0,
+ 1615,
+ 0,
+ 1616,
+ 1618,
+ 0,
+ 1619,
+ 0,
+ 0,
+ 1622,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1634,
+ 0,
+ 0,
+ 0,
+ 1635,
+ 0,
+ 0,
+ 0,
+ 1641,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1643,
+ 0,
+ 0,
+ 0,
+ 1650,
+ 0,
+ 0,
+ 1652,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1653,
+ 0,
+ 0,
+ 0,
+ 1654,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1655,
+ 0,
+ 1662,
+ 0,
+ 0,
+ 1663,
+ 1664,
+ 0,
+ 0,
+ 1668,
+ 0,
+ 0,
+ 1669,
+ 1670,
+ 0,
+ 1672,
+ 1673,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1674,
+ 0,
+ 0,
+ 0,
+ 1675,
+ 1676,
+ 1680,
+ 0,
+ 1682,
+ 0,
+ 0,
+ 1687,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1704,
+ 0,
+ 0,
+ 1705,
+ 0,
+ 0,
+ 1721,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1734,
+ 1735,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1737,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1739,
+ 0,
+ 0,
+ 1740,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1741,
+ 1743,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1745,
+ 0,
+ 0,
+ 0,
+ 1749,
+ 0,
+ 0,
+ 0,
+ 1751,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1760,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1765,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1784,
+ 0,
+ 1785,
+ 1787,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1788,
+ 1789,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1790,
+ 1791,
+ 1793,
+ 0,
+ 1798,
+ 1799,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1801,
+ 0,
+ 1803,
+ 1805,
+ 0,
+ 0,
+ 0,
+ 1806,
+ 1811,
+ 0,
+ 1812,
+ 1814,
+ 0,
+ 1821,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1822,
+ 1833,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1848,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1857,
+ 0,
+ 0,
+ 0,
+ 1859,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1861,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1866,
+ 0,
+ 1921,
+ 1925,
+ 0,
+ 0,
+ 0,
+ 1929,
+ 1930,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1931,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1932,
+ 0,
+ 0,
+ 0,
+ 1934,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1946,
+ 0,
+ 0,
+ 1948,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1950,
+ 0,
+ 1957,
+ 0,
+ 1958,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1965,
+ 1967,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1968,
+ 0,
+ 1969,
+ 0,
+ 1971,
+ 1972,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1973,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1975,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1976,
+ 1979,
+ 0,
+ 1982,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1984,
+ 1988,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1990,
+ 2004,
+ 2008,
+ 0,
+ 0,
+ 0,
+ 2012,
+ 2013,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2015,
+ 0,
+ 2016,
+ 2017,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2021,
+ 0,
+ 0,
+ 2025,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2029,
+ 2036,
+ 2040,
+ 0,
+ 2042,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2043,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2045,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2046,
+ 2047,
+ 0,
+ 2048,
+ 2049,
+ 0,
+ 2059,
+ 0,
+ 0,
+ 2063,
+ 0,
+ 2064,
+ 2065,
+ 0,
+ 0,
+ 2066,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2069,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2070,
+ 0,
+ 2071,
+ 0,
+ 2072,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2080,
+ 2082,
+ 2083,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2085,
+ 0,
+ 2086,
+ 2088,
+ 2089,
+ 2105,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2107,
+ 0,
+ 0,
+ 2116,
+ 2117,
+ 0,
+ 2120,
+ 0,
+ 0,
+ 2122,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2123,
+ 0,
+ 0,
+ 2125,
+ 2127,
+ 2128,
+ 0,
+ 0,
+ 0,
+ 2130,
+ 0,
+ 0,
+ 0,
+ 2137,
+ 2139,
+ 2140,
+ 2141,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2144,
+ 2145,
+ 0,
+ 0,
+ 2146,
+ 2149,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2150,
+ 0,
+ 0,
+ 2151,
+ 2158,
+ 0,
+ 2159,
+ 0,
+ 2160,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2161,
+ 2162,
+ 0,
+ 0,
+ 2194,
+ 2202,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2205,
+ 2217,
+ 0,
+ 2220,
+ 0,
+ 2221,
+ 0,
+ 2222,
+ 2224,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2237,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2238,
+ 0,
+ 2239,
+ 2241,
+ 0,
+ 0,
+ 2242,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2243,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2252,
+ 0,
+ 0,
+ 2253,
+ 0,
+ 0,
+ 0,
+ 2257,
+ 2258,
+ 0,
+ 0,
+ 0,
+ 2260,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2262,
+ 0,
+ 2264,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2269,
+ 2270,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2271,
+ 0,
+ 2273,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2277,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2278,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2279,
+ 0,
+ 2280,
+ 0,
+ 2283,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2287,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2289,
+ 2290,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2291,
+ 0,
+ 2292,
+ 0,
+ 0,
+ 0,
+ 2293,
+ 2295,
+ 2296,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2298,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2303,
+ 0,
+ 2305,
+ 0,
+ 0,
+ 2306,
+ 0,
+ 2307,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2313,
+ 2314,
+ 2315,
+ 2316,
+ 0,
+ 0,
+ 2318,
+ 0,
+ 2319,
+ 0,
+ 2322,
+ 0,
+ 0,
+ 2323,
+ 0,
+ 2324,
+ 0,
+ 2326,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2335,
+ 0,
+ 2336,
+ 2338,
+ 2339,
+ 0,
+ 2340,
+ 0,
+ 0,
+ 0,
+ 2355,
+ 0,
+ 2375,
+ 0,
+ 2382,
+ 2386,
+ 0,
+ 2387,
+ 0,
+ 0,
+ 2394,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2395,
+ 0,
+ 2397,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2398,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2399,
+ 2402,
+ 2404,
+ 2408,
+ 2411,
+ 0,
+ 0,
+ 0,
+ 2413,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2415,
+ 0,
+ 0,
+ 2416,
+ 2417,
+ 2419,
+ 0,
+ 2420,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2425,
+ 0,
+ 0,
+ 0,
+ 2426,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2427,
+ 2428,
+ 0,
+ 2429,
+ 0,
+ 0,
+ 2430,
+ 2434,
+ 0,
+ 2436,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2441,
+ 2442,
+ 0,
+ 2445,
+ 0,
+ 0,
+ 2446,
+ 2457,
+ 0,
+ 2459,
+ 0,
+ 0,
+ 2462,
+ 0,
+ 2464,
+ 0,
+ 2477,
+ 0,
+ 2478,
+ 2486,
+ 0,
+ 0,
+ 0,
+ 2491,
+ 0,
+ 0,
+ 2493,
+ 0,
+ 0,
+ 2494,
+ 0,
+ 2495,
+ 0,
+ 2513,
+ 2523,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2524,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2528,
+ 2529,
+ 2530,
+ 0,
+ 0,
+ 2531,
+ 0,
+ 2533,
+ 0,
+ 0,
+ 2534,
+ 2535,
+ 0,
+ 2536,
+ 2537,
+ 0,
+ 2538,
+ 0,
+ 2539,
+ 2540,
+ 0,
+ 0,
+ 0,
+ 2545,
+ 2546,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2548,
+ 0,
+ 0,
+ 2549,
+ 0,
+ 2550,
+ 2555,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2557,
+ 0,
+ 2560,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2561,
+ 0,
+ 2576,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2577,
+ 2578,
+ 0,
+ 0,
+ 0,
+ 2579,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2580,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2581,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2583,
+ 0,
+ 2584,
+ 0,
+ 2588,
+ 2590,
+ 0,
+ 0,
+ 0,
+ 2591,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2593,
+ 2594,
+ 0,
+ 2595,
+ 0,
+ 2601,
+ 2602,
+ 0,
+ 0,
+ 2603,
+ 0,
+ 2605,
+ 0,
+ 0,
+ 0,
+ 2606,
+ 2607,
+ 2611,
+ 0,
+ 2615,
+ 0,
+ 0,
+ 0,
+ 2617,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2619,
+ 0,
+ 0,
+ 2620,
+ 0,
+ 0,
+ 0,
+ 2621,
+ 0,
+ 2623,
+ 0,
+ 2625,
+ 0,
+ 0,
+ 2628,
+ 2629,
+ 0,
+ 0,
+ 2635,
+ 2636,
+ 2637,
+ 0,
+ 0,
+ 2639,
+ 0,
+ 0,
+ 0,
+ 2642,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2643,
+ 0,
+ 2644,
+ 0,
+ 2649,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2655,
+ 2656,
+ 0,
+ 0,
+ 2657,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2658,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2659,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2664,
+ 2685,
+ 0,
+ 2687,
+ 0,
+ 2688,
+ 0,
+ 0,
+ 2689,
+ 0,
+ 0,
+ 2694,
+ 0,
+ 2695,
+ 0,
+ 0,
+ 2698,
+ 0,
+ 2701,
+ 2706,
+ 0,
+ 0,
+ 0,
+ 2707,
+ 0,
+ 2709,
+ 2710,
+ 2711,
+ 0,
+ 0,
+ 0,
+ 2720,
+ 2730,
+ 2735,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2738,
+ 2740,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2747,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2748,
+ 0,
+ 0,
+ 2749,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2750,
+ 0,
+ 0,
+ 2752,
+ 2754,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2758,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2762,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2763,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2764,
+ 2767,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2768,
+ 0,
+ 0,
+ 2770,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2771,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2772,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2773,
+ 2776,
+ 0,
+ 0,
+ 2783,
+ 0,
+ 0,
+ 2784,
+ 0,
+ 2789,
+ 0,
+ 2790,
+ 0,
+ 0,
+ 0,
+ 2792,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2793,
+ 2795,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2796,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2797,
+ 2799,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2803,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2806,
+ 0,
+ 2807,
+ 2808,
+ 2817,
+ 2819,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2821,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2822,
+ 2823,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2824,
+ 0,
+ 0,
+ 2828,
+ 0,
+ 2834,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2836,
+ 0,
+ 2838,
+ 0,
+ 0,
+ 2839,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2841,
+ 0,
+ 0,
+ 0,
+ 2842,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2843,
+ 2844,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2846,
+ 0,
+ 0,
+ 2847,
+ 0,
+ 2849,
+ 0,
+ 2853,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2857,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2858,
+ 0,
+ 2859,
+ 0,
+ 0,
+ 2860,
+ 0,
+ 2862,
+ 2868,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2875,
+ 0,
+ 2876,
+ 0,
+ 0,
+ 2877,
+ 2878,
+ 2884,
+ 2889,
+ 2890,
+ 0,
+ 0,
+ 2891,
+ 0,
+ 0,
+ 2892,
+ 0,
+ 0,
+ 0,
+ 2906,
+ 2912,
+ 0,
+ 2913,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2916,
+ 0,
+ 2934,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2935,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2939,
+ 0,
+ 2940,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2941,
+ 0,
+ 0,
+ 0,
+ 2946,
+ 0,
+ 2949,
+ 0,
+ 0,
+ 2950,
+ 2954,
+ 2955,
+ 0,
+ 0,
+ 0,
+ 2959,
+ 2961,
+ 0,
+ 0,
+ 2962,
+ 0,
+ 2963,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2964,
+ 2965,
+ 2966,
+ 2967,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2969,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2970,
+ 2975,
+ 0,
+ 2982,
+ 2983,
+ 2984,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2989,
+ 0,
+ 0,
+ 2990,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2991,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2998,
+ 0,
+ 3000,
+ 3001,
+ 0,
+ 0,
+ 3002,
+ 0,
+ 0,
+ 0,
+ 3003,
+ 0,
+ 0,
+ 3012,
+ 0,
+ 0,
+ 3022,
+ 0,
+ 0,
+ 3024,
+ 0,
+ 0,
+ 3025,
+ 3027,
+ 0,
+ 0,
+ 0,
+ 3030,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3034,
+ 3035,
+ 0,
+ 0,
+ 3036,
+ 0,
+ 3039,
+ 0,
+ 3049,
+ 0,
+ 0,
+ 3050,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3051,
+ 0,
+ 3053,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3057,
+ 0,
+ 3058,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3063,
+ 0,
+ 0,
+ 3073,
+ 3074,
+ 3078,
+ 3079,
+ 0,
+ 3080,
+ 3086,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3087,
+ 0,
+ 3092,
+ 0,
+ 3095,
+ 0,
+ 3099,
+ 0,
+ 0,
+ 0,
+ 3100,
+ 0,
+ 3101,
+ 3102,
+ 0,
+ 3122,
+ 0,
+ 0,
+ 0,
+ 3124,
+ 0,
+ 3125,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3132,
+ 3134,
+ 0,
+ 0,
+ 3136,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3147,
+ 0,
+ 0,
+ 3149,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3150,
+ 3151,
+ 3152,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3158,
+ 0,
+ 0,
+ 3160,
+ 0,
+ 0,
+ 3161,
+ 0,
+ 0,
+ 3162,
+ 0,
+ 3163,
+ 3166,
+ 3168,
+ 0,
+ 0,
+ 3169,
+ 3170,
+ 0,
+ 0,
+ 3171,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3182,
+ 0,
+ 3184,
+ 0,
+ 0,
+ 3188,
+ 0,
+ 0,
+ 3194,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3204,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3209,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3216,
+ 3217,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3219,
+ 0,
+ 0,
+ 3220,
+ 3222,
+ 0,
+ 3223,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3224,
+ 0,
+ 3225,
+ 3226,
+ 0,
+ 3228,
+ 3233,
+ 0,
+ 3239,
+ 3241,
+ 3242,
+ 0,
+ 0,
+ 3251,
+ 3252,
+ 3253,
+ 3255,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3260,
+ 0,
+ 0,
+ 3261,
+ 0,
+ 0,
+ 0,
+ 3267,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3271,
+ 0,
+ 0,
+ 0,
+ 3278,
+ 0,
+ 3282,
+ 0,
+ 0,
+ 0,
+ 3284,
+ 0,
+ 0,
+ 0,
+ 3285,
+ 3286,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3287,
+ 3292,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3294,
+ 3296,
+ 0,
+ 0,
+ 3299,
+ 3300,
+ 3301,
+ 0,
+ 3302,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3304,
+ 3306,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3308,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3311,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3312,
+ 3314,
+ 3315,
+ 0,
+ 3318,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3319,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3321,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3322,
+ 0,
+ 0,
+ 3324,
+ 3325,
+ 0,
+ 0,
+ 3326,
+ 0,
+ 0,
+ 3328,
+ 3329,
+ 3331,
+ 0,
+ 0,
+ 3335,
+ 0,
+ 0,
+ 3337,
+ 0,
+ 3338,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3343,
+ 3347,
+ 0,
+ 0,
+ 0,
+ 3348,
+ 0,
+ 0,
+ 3351,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3354,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3355,
+ 0,
+ 0,
+ 3365,
+ 3366,
+ 3367,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3368,
+ 3369,
+ 0,
+ 3370,
+ 0,
+ 0,
+ 3373,
+ 0,
+ 0,
+ 3376,
+ 0,
+ 0,
+ 3377,
+ 0,
+ 3379,
+ 3387,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3390,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3402,
+ 0,
+ 3403,
+ 3436,
+ 3437,
+ 3439,
+ 0,
+ 0,
+ 3441,
+ 0,
+ 0,
+ 0,
+ 3442,
+ 0,
+ 0,
+ 3449,
+ 0,
+ 0,
+ 0,
+ 3450,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3451,
+ 0,
+ 0,
+ 3452,
+ 0,
+ 3453,
+ 3456,
+ 0,
+ 3457,
+ 0,
+ 0,
+ 3458,
+ 0,
+ 3459,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3460,
+ 0,
+ 0,
+ 3469,
+ 3470,
+ 0,
+ 0,
+ 3475,
+ 0,
+ 0,
+ 0,
+ 3480,
+ 3487,
+ 3489,
+ 0,
+ 3490,
+ 0,
+ 0,
+ 3491,
+ 3499,
+ 0,
+ 3500,
+ 0,
+ 0,
+ 3501,
+ 0,
+ 0,
+ 0,
+ 3502,
+ 0,
+ 3514,
+ 0,
+ 0,
+ 0,
+ 3516,
+ 3517,
+ 0,
+ 0,
+ 0,
+ 3518,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3520,
+ 3521,
+ 3522,
+ 0,
+ 0,
+ 3526,
+ 3530,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3531,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3536,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3539,
+ 3541,
+ 0,
+ 0,
+ 3542,
+ 3544,
+ 0,
+ 3547,
+ 3548,
+ 0,
+ 0,
+ 3550,
+ 0,
+ 3553,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3554,
+ 0,
+ 3555,
+ 0,
+ 3558,
+ 0,
+ 3559,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3563,
+ 0,
+ 3581,
+ 0,
+ 0,
+ 0,
+ 3599,
+ 0,
+ 0,
+ 0,
+ 3600,
+ 0,
+ 3601,
+ 0,
+ 3602,
+ 3603,
+ 0,
+ 0,
+ 3606,
+ 3608,
+ 0,
+ 3610,
+ 3611,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3612,
+ 3616,
+ 3619,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3624,
+ 3628,
+ 0,
+ 3629,
+ 3634,
+ 3635,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3636,
+ 0,
+ 3637,
+ 0,
+ 0,
+ 3638,
+ 3651,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3652,
+ 3653,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3656,
+ 3657,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3658,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3659,
+ 0,
+ 3661,
+ 3663,
+ 3664,
+ 0,
+ 3665,
+ 0,
+ 3692,
+ 0,
+ 0,
+ 0,
+ 3694,
+ 3696,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3698,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3700,
+ 0,
+ 0,
+ 3701,
+ 0,
+ 0,
+ 0,
+ 3708,
+ 3709,
+ 0,
+ 0,
+ 0,
+ 3711,
+ 3712,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3723,
+ 0,
+ 3724,
+ 3725,
+ 0,
+ 0,
+ 3726,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3728,
+ 3729,
+ 0,
+ 3734,
+ 3735,
+ 3737,
+ 0,
+ 0,
+ 0,
+ 3743,
+ 0,
+ 3745,
+ 0,
+ 0,
+ 3746,
+ 0,
+ 0,
+ 3747,
+ 3748,
+ 0,
+ 3757,
+ 0,
+ 3759,
+ 3766,
+ 3767,
+ 0,
+ 3768,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3769,
+ 0,
+ 0,
+ 3771,
+ 0,
+ 3774,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3775,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3776,
+ 0,
+ 3777,
+ 3786,
+ 0,
+ 3788,
+ 3789,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3791,
+ 0,
+ 3811,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3814,
+ 3815,
+ 3816,
+ 3820,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3821,
+ 0,
+ 0,
+ 3825,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3835,
+ 0,
+ 0,
+ 3848,
+ 3849,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3850,
+ 3851,
+ 3853,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3859,
+ 0,
+ 3860,
+ 3862,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3863,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3873,
+ 0,
+ 3874,
+ 0,
+ 3875,
+ 3886,
+ 0,
+ 3887,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3892,
+ 3913,
+ 0,
+ 3914,
+ 0,
+ 0,
+ 0,
+ 3925,
+ 3931,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3934,
+ 3941,
+ 3942,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3943,
+ 0,
+ 0,
+ 0,
+ 3944,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3945,
+ 0,
+ 3947,
+ 0,
+ 0,
+ 0,
+ 3956,
+ 3957,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3958,
+ 0,
+ 3959,
+ 3965,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3966,
+ 0,
+ 0,
+ 0,
+ 3967,
+ 0,
+ 0,
+ 0,
+ 3968,
+ 3974,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3975,
+ 3977,
+ 3978,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3980,
+ 0,
+ 3985,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3986,
+ 4011,
+ 0,
+ 0,
+ 4017,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4018,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4019,
+ 0,
+ 4023,
+ 0,
+ 0,
+ 0,
+ 4027,
+ 4028,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4031,
+ 4034,
+ 0,
+ 0,
+ 4035,
+ 4037,
+ 4039,
+ 4040,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4059,
+ 0,
+ 4060,
+ 4061,
+ 0,
+ 4062,
+ 4063,
+ 4066,
+ 0,
+ 0,
+ 4072,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4088,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4091,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4094,
+ 4095,
+ 0,
+ 0,
+ 4096,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4098,
+ 4099,
+ 0,
+ 0,
+ 0,
+ 4101,
+ 0,
+ 4104,
+ 0,
+ 0,
+ 0,
+ 4105,
+ 4108,
+ 0,
+ 4113,
+ 0,
+ 0,
+ 4115,
+ 4116,
+ 0,
+ 4126,
+ 0,
+ 0,
+ 4127,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4128,
+ 4132,
+ 4133,
+ 0,
+ 4134,
+ 0,
+ 0,
+ 0,
+ 4137,
+ 0,
+ 0,
+ 4141,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4144,
+ 4146,
+ 4147,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4148,
+ 0,
+ 0,
+ 4311,
+ 0,
+ 0,
+ 0,
+ 4314,
+ 4329,
+ 0,
+ 4331,
+ 4332,
+ 0,
+ 4333,
+ 0,
+ 4334,
+ 0,
+ 0,
+ 0,
+ 4335,
+ 0,
+ 4336,
+ 0,
+ 0,
+ 0,
+ 4337,
+ 0,
+ 0,
+ 0,
+ 4342,
+ 4345,
+ 4346,
+ 4350,
+ 0,
+ 4351,
+ 4352,
+ 0,
+ 4354,
+ 4355,
+ 0,
+ 0,
+ 4364,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4369,
+ 0,
+ 0,
+ 0,
+ 4373,
+ 0,
+ 4374,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4377,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4378,
+ 0,
+ 0,
+ 0,
+ 4380,
+ 0,
+ 0,
+ 0,
+ 4381,
+ 4382,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4384,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4385,
+ 0,
+ 0,
+ 0,
+ 4386,
+ 0,
+ 0,
+ 0,
+ 4391,
+ 4398,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4407,
+ 4409,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4410,
+ 0,
+ 0,
+ 4411,
+ 0,
+ 4414,
+ 4415,
+ 4418,
+ 0,
+ 4427,
+ 4428,
+ 4430,
+ 0,
+ 4431,
+ 0,
+ 4448,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4449,
+ 0,
+ 0,
+ 0,
+ 4451,
+ 4452,
+ 0,
+ 4453,
+ 4454,
+ 0,
+ 4456,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4459,
+ 0,
+ 4463,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4466,
+ 0,
+ 4467,
+ 0,
+ 4469,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4470,
+ 4471,
+ 0,
+ 4473,
+ 0,
+ 0,
+ 4475,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4477,
+ 4478,
+ 0,
+ 0,
+ 0,
+ 4479,
+ 4481,
+ 0,
+ 4482,
+ 0,
+ 4484,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4486,
+ 0,
+ 0,
+ 4488,
+ 0,
+ 0,
+ 4497,
+ 0,
+ 4508,
+ 0,
+ 0,
+ 4510,
+ 4511,
+ 0,
+ 4520,
+ 4523,
+ 0,
+ 4524,
+ 0,
+ 4525,
+ 0,
+ 4527,
+ 0,
+ 0,
+ 4528,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4530,
+ 0,
+ 4531,
+ 0,
+ 0,
+ 4532,
+ 0,
+ 0,
+ 0,
+ 4533,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4535,
+ 0,
+ 0,
+ 0,
+ 4536,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4541,
+ 4543,
+ 4544,
+ 4545,
+ 4547,
+ 0,
+ 4548,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4550,
+ 4551,
+ 0,
+ 4553,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4562,
+ 0,
+ 0,
+ 4571,
+ 0,
+ 0,
+ 0,
+ 4574,
+ 0,
+ 0,
+ 0,
+ 4575,
+ 0,
+ 4576,
+ 0,
+ 4577,
+ 0,
+ 0,
+ 0,
+ 4581,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4582,
+ 0,
+ 0,
+ 4586,
+ 0,
+ 0,
+ 0,
+ 4588,
+ 0,
+ 0,
+ 4597,
+ 0,
+ 4598,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4616,
+ 4617,
+ 0,
+ 4618,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4619,
+ 0,
+ 4620,
+ 0,
+ 0,
+ 4621,
+ 0,
+ 4624,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4625,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4657,
+ 0,
+ 4659,
+ 0,
+ 4667,
+ 0,
+ 0,
+ 0,
+ 4668,
+ 4670,
+ 0,
+ 4672,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4673,
+ 4676,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4687,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4697,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4699,
+ 0,
+ 4701,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4702,
+ 0,
+ 0,
+ 4706,
+ 0,
+ 0,
+ 4713,
+ 0,
+ 0,
+ 0,
+ 4714,
+ 4715,
+ 4716,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4717,
+ 0,
+ 0,
+ 4720,
+ 0,
+ 4721,
+ 4729,
+ 4735,
+ 0,
+ 0,
+ 0,
+ 4737,
+ 0,
+ 0,
+ 0,
+ 4739,
+ 0,
+ 0,
+ 0,
+ 4740,
+ 0,
+ 0,
+ 0,
+ 4741,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4742,
+ 0,
+ 4745,
+ 4746,
+ 4747,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4748,
+ 0,
+ 0,
+ 0,
+ 4749,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4751,
+ 4786,
+ 0,
+ 4787,
+ 0,
+ 4788,
+ 4796,
+ 0,
+ 0,
+ 4797,
+ 4798,
+ 0,
+ 4799,
+ 4806,
+ 4807,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4809,
+ 4810,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4811,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4812,
+ 0,
+ 4813,
+ 0,
+ 0,
+ 4815,
+ 0,
+ 4821,
+ 4822,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4823,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4824,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4826,
+ 0,
+ 0,
+ 0,
+ 4828,
+ 0,
+ 4829,
+ 0,
+ 0,
+ 0,
+ 4843,
+ 0,
+ 0,
+ 4847,
+ 0,
+ 4853,
+ 4855,
+ 4858,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4859,
+ 0,
+ 4864,
+ 0,
+ 0,
+ 4879,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4880,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4881,
+ 0,
+ 4882,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4883,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4884,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4886,
+ 4887,
+ 4888,
+ 4894,
+ 4896,
+ 0,
+ 4902,
+ 0,
+ 0,
+ 4905,
+ 0,
+ 0,
+ 4915,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4916,
+ 4917,
+ 4919,
+ 4921,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4926,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4927,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4929,
+ 0,
+ 4930,
+ 4931,
+ 0,
+ 4938,
+ 0,
+ 4952,
+ 0,
+ 4953,
+ 4957,
+ 4960,
+ 4964,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5019,
+ 5020,
+ 5022,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5023,
+ 0,
+ 0,
+ 0,
+ 5024,
+ 0,
+ 0,
+ 0,
+ 5025,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5028,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5029,
+ 5030,
+ 5031,
+ 0,
+ 5033,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5034,
+ 5035,
+ 0,
+ 5036,
+ 0,
+ 0,
+ 5037,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5038,
+ 0,
+ 0,
+ 5039,
+ 0,
+ 0,
+ 0,
+ 5041,
+ 5042,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5044,
+ 5049,
+ 5054,
+ 0,
+ 5055,
+ 0,
+ 5057,
+ 0,
+ 0,
+ 0,
+ 5060,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5063,
+ 0,
+ 5064,
+ 5065,
+ 0,
+ 5067,
+ 0,
+ 0,
+ 0,
+ 5068,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5076,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5077,
+ 0,
+ 0,
+ 5078,
+ 5080,
+ 0,
+ 0,
+ 5083,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5085,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5098,
+ 5099,
+ 5101,
+ 5105,
+ 5107,
+ 0,
+ 5108,
+ 0,
+ 5109,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5110,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5117,
+ 5118,
+ 0,
+ 5121,
+ 0,
+ 5122,
+ 0,
+ 0,
+ 5130,
+ 0,
+ 0,
+ 0,
+ 5137,
+ 0,
+ 0,
+ 0,
+ 5148,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5151,
+ 5154,
+ 0,
+ 0,
+ 0,
+ 5155,
+ 0,
+ 0,
+ 5156,
+ 5159,
+ 5161,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5162,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5163,
+ 5164,
+ 0,
+ 5166,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5167,
+ 0,
+ 0,
+ 0,
+ 5172,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5178,
+ 5179,
+ 0,
+ 0,
+ 5190,
+ 0,
+ 0,
+ 5191,
+ 5192,
+ 5194,
+ 0,
+ 0,
+ 5198,
+ 5201,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5203,
+ 0,
+ 5206,
+ 5209,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5213,
+ 0,
+ 5214,
+ 5216,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5217,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5218,
+ 5219,
+ 0,
+ 5231,
+ 0,
+ 0,
+ 5244,
+ 5249,
+ 0,
+ 5254,
+ 0,
+ 5255,
+ 0,
+ 0,
+ 5257,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5258,
+ 0,
+ 5260,
+ 5270,
+ 0,
+ 5277,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5280,
+ 5281,
+ 5282,
+ 5283,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5284,
+ 0,
+ 5285,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5287,
+ 5288,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5289,
+ 5291,
+ 0,
+ 0,
+ 5294,
+ 0,
+ 0,
+ 5295,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5304,
+ 0,
+ 0,
+ 5306,
+ 5307,
+ 5308,
+ 0,
+ 5309,
+ 0,
+ 0,
+ 5310,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5311,
+ 5312,
+ 0,
+ 5313,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5316,
+ 0,
+ 0,
+ 0,
+ 5317,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5325,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5326,
+ 0,
+ 5327,
+ 5329,
+ 0,
+ 5332,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5338,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5340,
+ 0,
+ 0,
+ 5341,
+ 0,
+ 0,
+ 0,
+ 5342,
+ 0,
+ 5343,
+ 5344,
+ 0,
+ 0,
+ 5345,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5347,
+ 5348,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5349,
+ 0,
+ 5350,
+ 0,
+ 5354,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5358,
+ 0,
+ 0,
+ 5359,
+ 0,
+ 0,
+ 5361,
+ 0,
+ 0,
+ 5365,
+ 0,
+ 5367,
+ 0,
+ 5373,
+ 0,
+ 0,
+ 0,
+ 5379,
+ 0,
+ 0,
+ 0,
+ 5380,
+ 0,
+ 0,
+ 0,
+ 5382,
+ 0,
+ 5384,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5385,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5387,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5388,
+ 5390,
+ 5393,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5396,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5397,
+ 5402,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5403,
+ 0,
+ 0,
+ 0,
+ 5404,
+ 5405,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5406,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5410,
+ 0,
+ 0,
+ 5411,
+ 0,
+ 5415,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5416,
+ 5434,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5438,
+ 0,
+ 5440,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5441,
+ 5442,
+ 0,
+ 0,
+ 0,
+ 5443,
+ 5444,
+ 5447,
+ 0,
+ 0,
+ 5448,
+ 5449,
+ 5451,
+ 0,
+ 0,
+ 0,
+ 5456,
+ 5457,
+ 0,
+ 0,
+ 0,
+ 5459,
+ 0,
+ 0,
+ 0,
+ 5461,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5464,
+ 0,
+ 5466,
+ 0,
+ 0,
+ 5467,
+ 0,
+ 5470,
+ 0,
+ 0,
+ 5473,
+ 0,
+ 0,
+ 5474,
+ 0,
+ 0,
+ 5476,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5477,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5484,
+ 0,
+ 0,
+ 5485,
+ 5486,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5488,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5489,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5507,
+ 0,
+ 0,
+ 0,
+ 5510,
+ 0,
+ 5511,
+ 0,
+ 0,
+ 5512,
+ 0,
+ 0,
+ 0,
+ 5513,
+ 0,
+ 5515,
+ 0,
+ 0,
+ 5516,
+ 5517,
+ 0,
+ 5518,
+ 0,
+ 0,
+ 5522,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5534,
+ 5535,
+ 0,
+ 0,
+ 5536,
+ 0,
+ 5538,
+ 0,
+ 0,
+ 5543,
+ 0,
+ 5544,
+ 0,
+ 0,
+ 5545,
+ 0,
+ 5547,
+ 0,
+ 5557,
+ 0,
+ 0,
+ 5558,
+ 0,
+ 5560,
+ 5567,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5568,
+ 0,
+ 0,
+ 0,
+ 5571,
+ 5573,
+ 0,
+ 5574,
+ 0,
+ 5575,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5577,
+ 0,
+ 0,
+ 5598,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5600,
+ 5609,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5610,
+ 0,
+ 0,
+ 5612,
+ 0,
+ 5624,
+ 0,
+ 5625,
+ 0,
+ 0,
+ 0,
+ 5629,
+ 0,
+ 5641,
+ 0,
+ 5642,
+ 5643,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5651,
+ 0,
+ 0,
+ 0,
+ 5652,
+ 5653,
+ 0,
+ 5661,
+ 5662,
+ 5678,
+ 0,
+ 5679,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5685,
+ 5686,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5690,
+ 5692,
+ 0,
+ 5703,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5706,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5707,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5708,
+ 0,
+ 0,
+ 5709,
+ 0,
+ 5710,
+ 0,
+ 0,
+ 0,
+ 5712,
+ 0,
+ 5733,
+ 0,
+ 5734,
+ 5735,
+ 0,
+ 0,
+ 5744,
+ 5751,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5752,
+ 0,
+ 5754,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5757,
+ 5758,
+ 0,
+ 5760,
+ 5761,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5763,
+ 5764,
+ 5765,
+ 0,
+ 5766,
+ 0,
+ 5767,
+ 5768,
+ 0,
+ 5770,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5776,
+ 5780,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5782,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5784,
+ 0,
+ 0,
+ 5788,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5797,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5799,
+ 0,
+ 0,
+ 5801,
+ 0,
+ 0,
+ 0,
+ 5811,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5816,
+ 0,
+ 0,
+ 5827,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5830,
+ 5831,
+ 0,
+ 0,
+ 5832,
+ 0,
+ 0,
+ 5833,
+ 0,
+ 5835,
+ 5844,
+ 5845,
+ 0,
+ 5846,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5850,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5852,
+ 0,
+ 5855,
+ 5857,
+ 0,
+ 0,
+ 5859,
+ 0,
+ 5861,
+ 0,
+ 0,
+ 5863,
+ 0,
+ 5865,
+ 0,
+ 0,
+ 0,
+ 5873,
+ 5875,
+ 0,
+ 0,
+ 0,
+ 5877,
+ 0,
+ 5879,
+ 0,
+ 0,
+ 0,
+ 5888,
+ 0,
+ 0,
+ 5889,
+ 5891,
+ 0,
+ 5894,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5895,
+ 0,
+ 5897,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5907,
+ 0,
+ 5911,
+ 0,
+ 0,
+ 5912,
+ 0,
+ 5913,
+ 5922,
+ 5924,
+ 0,
+ 5927,
+ 5928,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5929,
+ 5930,
+ 0,
+ 5933,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5949,
+ 0,
+ 0,
+ 5951,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5953,
+ 0,
+ 0,
+ 5954,
+ 0,
+ 5959,
+ 5960,
+ 5961,
+ 0,
+ 5964,
+ 0,
+ 0,
+ 0,
+ 5976,
+ 5978,
+ 5987,
+ 5990,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5991,
+ 0,
+ 5992,
+ 0,
+ 0,
+ 0,
+ 5994,
+ 5995,
+ 0,
+ 0,
+ 5996,
+ 0,
+ 0,
+ 6001,
+ 6003,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6007,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6008,
+ 0,
+ 0,
+ 6009,
+ 0,
+ 6010,
+ 0,
+ 0,
+ 0,
+ 6011,
+ 6015,
+ 0,
+ 6017,
+ 0,
+ 6019,
+ 0,
+ 6023,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6025,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6026,
+ 0,
+ 6030,
+ 0,
+ 0,
+ 6032,
+ 0,
+ 0,
+ 0,
+ 6033,
+ 6038,
+ 6040,
+ 0,
+ 0,
+ 0,
+ 6041,
+ 6045,
+ 0,
+ 0,
+ 6046,
+ 0,
+ 0,
+ 6053,
+ 0,
+ 0,
+ 6054,
+ 0,
+ 6055,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6057,
+ 0,
+ 6063,
+ 0,
+ 0,
+ 0,
+ 6064,
+ 0,
+ 6066,
+ 6071,
+ 6072,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6075,
+ 6076,
+ 0,
+ 0,
+ 6077,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6078,
+ 6079,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6080,
+ 0,
+ 6083,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6084,
+ 0,
+ 0,
+ 6088,
+ 0,
+ 6089,
+ 0,
+ 0,
+ 6093,
+ 6105,
+ 0,
+ 0,
+ 6107,
+ 0,
+ 6110,
+ 0,
+ 0,
+ 0,
+ 6111,
+ 6125,
+ 6126,
+ 0,
+ 0,
+ 0,
+ 6129,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6130,
+ 0,
+ 0,
+ 0,
+ 6131,
+ 6134,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6142,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6144,
+ 0,
+ 0,
+ 6146,
+ 6151,
+ 6153,
+ 0,
+ 6156,
+ 0,
+ 6163,
+ 0,
+ 6180,
+ 6181,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6182,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6184,
+ 6195,
+ 0,
+ 0,
+ 6206,
+ 0,
+ 6208,
+ 0,
+ 0,
+ 6212,
+ 6213,
+ 6214,
+ 0,
+ 6215,
+ 0,
+ 0,
+ 0,
+ 6228,
+ 0,
+ 0,
+ 0,
+ 6234,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6235,
+ 6240,
+ 0,
+ 6242,
+ 6243,
+ 6244,
+ 0,
+ 6250,
+ 6255,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6257,
+ 0,
+ 0,
+ 0,
+ 6258,
+ 6278,
+ 0,
+ 6284,
+ 0,
+ 0,
+ 0,
+ 6285,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6286,
+ 0,
+ 0,
+ 0,
+ 6320,
+ 0,
+ 0,
+ 6322,
+ 6332,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6334,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6335,
+ 0,
+ 0,
+ 6337,
+ 0,
+ 6338,
+ 0,
+ 6339,
+ 6340,
+ 0,
+ 0,
+ 6356,
+ 6357,
+ 6369,
+ 0,
+ 0,
+ 0,
+ 6370,
+ 6371,
+ 6372,
+ 0,
+ 6373,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6376,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6382,
+ 6383,
+ 6384,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6386,
+ 0,
+ 6389,
+ 6397,
+ 6400,
+ 6411,
+ 0,
+ 6414,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6415,
+ 6416,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6417,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6418,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6420,
+ 0,
+ 6421,
+ 6423,
+ 6425,
+ 0,
+ 6429,
+ 6430,
+ 0,
+ 6433,
+ 6438,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6439,
+ 6440,
+ 0,
+ 0,
+ 6441,
+ 0,
+ 0,
+ 6444,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6446,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6447,
+ 6448,
+ 0,
+ 0,
+ 6450,
+ 0,
+ 0,
+ 0,
+ 6454,
+ 0,
+ 0,
+ 6455,
+ 0,
+ 6461,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6462,
+ 0,
+ 0,
+ 6463,
+ 0,
+ 6464,
+ 0,
+ 6465,
+ 6467,
+ 0,
+ 0,
+ 0,
+ 6468,
+ 0,
+ 6479,
+ 6480,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6481,
+ 0,
+ 0,
+ 6485,
+ 6487,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6493,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6494,
+ 6495,
+ 6496,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6498,
+ 0,
+ 0,
+ 0,
+ 6507,
+ 6508,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6511,
+ 6512,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6513,
+ 0,
+ 0,
+ 0,
+ 6514,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6516,
+ 0,
+ 0,
+ 6517,
+ 6518,
+ 0,
+ 0,
+ 0,
+ 6519,
+ 6520,
+ 6521,
+ 0,
+ 6523,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6524,
+ 6528,
+ 0,
+ 6530,
+ 0,
+ 0,
+ 6532,
+ 0,
+ 6578,
+ 0,
+ 0,
+ 0,
+ 6583,
+ 0,
+ 6584,
+ 0,
+ 0,
+ 0,
+ 6587,
+ 0,
+ 0,
+ 0,
+ 6590,
+ 0,
+ 6591,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6592,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6593,
+ 6594,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6599,
+ 6600,
+ 0,
+ 0,
+ 6601,
+ 6602,
+ 6604,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6608,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6610,
+ 6611,
+ 0,
+ 6615,
+ 0,
+ 6616,
+ 6618,
+ 6620,
+ 0,
+ 6637,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6639,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6641,
+ 0,
+ 6642,
+ 0,
+ 0,
+ 0,
+ 6647,
+ 0,
+ 6660,
+ 6663,
+ 0,
+ 6664,
+ 0,
+ 6666,
+ 6669,
+ 0,
+ 6675,
+ 6676,
+ 6677,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6678,
+ 0,
+ 0,
+ 0,
+ 6679,
+ 0,
+ 6680,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6693,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6704,
+ 6705,
+ 6706,
+ 0,
+ 0,
+ 6711,
+ 6713,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6716,
+ 0,
+ 0,
+ 0,
+ 6717,
+ 0,
+ 6719,
+ 6724,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6725,
+ 6726,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6728,
+ 6729,
+ 6735,
+ 0,
+ 6737,
+ 6742,
+ 0,
+ 0,
+ 6743,
+ 6750,
+ 0,
+ 6751,
+ 0,
+ 0,
+ 6752,
+ 6753,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6754,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6756,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6763,
+ 0,
+ 0,
+ 6764,
+ 6765,
+ 0,
+ 0,
+ 0,
+ 6770,
+ 0,
+ 0,
+ 0,
+ 6776,
+ 6780,
+ 0,
+ 6781,
+ 0,
+ 0,
+ 0,
+ 6783,
+ 0,
+ 6784,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6785,
+ 0,
+ 0,
+ 0,
+ 6792,
+ 0,
+ 0,
+ 0,
+ 6793,
+ 0,
+ 0,
+ 6802,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6803,
+ 0,
+ 0,
+ 0,
+ 6804,
+ 0,
+ 0,
+ 0,
+ 6812,
+ 0,
+ 0,
+ 6823,
+ 0,
+ 6824,
+ 6839,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6852,
+ 0,
+ 0,
+ 6854,
+ 0,
+ 6856,
+ 6857,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6867,
+ 0,
+ 6868,
+ 6870,
+ 6872,
+ 0,
+ 0,
+ 0,
+ 6873,
+ 6874,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6875,
+ 0,
+ 0,
+ 6877,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6878,
+ 0,
+ 0,
+ 0,
+ 6879,
+ 0,
+ 6880,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6887,
+ 0,
+ 6888,
+ 6891,
+ 6893,
+ 0,
+ 6895,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6899,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6901,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6910,
+ 0,
+ 6911,
+ 0,
+ 0,
+ 6912,
+ 0,
+ 0,
+ 6913,
+ 6914,
+ 0,
+ 0,
+ 0,
+ 6915,
+ 0,
+ 0,
+ 0,
+ 6916,
+ 6919,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6924,
+ 0,
+ 6925,
+ 0,
+ 0,
+ 0,
+ 6926,
+ 6927,
+ 6928,
+ 0,
+ 6929,
+ 0,
+ 6930,
+ 0,
+ 0,
+ 6931,
+ 6935,
+ 0,
+ 6936,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6939,
+ 6940,
+ 6941,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6942,
+ 6948,
+ 6949,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6952,
+ 6954,
+ 6963,
+ 6965,
+ 6966,
+ 0,
+ 0,
+ 6967,
+ 6968,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6969,
+ 0,
+ 0,
+ 6970,
+ 6979,
+ 0,
+ 0,
+ 6980,
+ 0,
+ 0,
+ 6983,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6984,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6988,
+ 6990,
+ 6992,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6995,
+ 0,
+ 0,
+ 0,
+ 7012,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7019,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7021,
+ 0,
+ 0,
+ 7022,
+ 7023,
+ 7028,
+ 0,
+ 7030,
+ 7033,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7038,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7039,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7046,
+ 0,
+ 7047,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7048,
+ 7052,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7054,
+ 0,
+ 7060,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7061,
+ 0,
+ 7065,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7067,
+ 7069,
+ 0,
+ 7070,
+ 7071,
+ 7072,
+ 0,
+ 0,
+ 7078,
+ 0,
+ 7080,
+ 7081,
+ 0,
+ 7083,
+ 0,
+ 0,
+ 0,
+ 7084,
+ 7087,
+ 7088,
+ 0,
+ 0,
+ 7090,
+ 0,
+ 7093,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7107,
+ 0,
+ 0,
+ 7108,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7110,
+ 0,
+ 7114,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7115,
+ 0,
+ 7116,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7117,
+ 0,
+ 0,
+ 7118,
+ 0,
+ 0,
+ 7124,
+ 0,
+ 7125,
+ 0,
+ 0,
+ 7126,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7128,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7129,
+ 0,
+ 7130,
+ 0,
+ 7132,
+ 7133,
+ 0,
+ 0,
+ 7134,
+ 0,
+ 0,
+ 7139,
+ 0,
+ 7148,
+ 7150,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7152,
+ 0,
+ 0,
+ 0,
+ 7153,
+ 7156,
+ 7157,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7158,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7163,
+ 7165,
+ 7169,
+ 0,
+ 7171,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7172,
+ 0,
+ 7173,
+ 7181,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7182,
+ 7185,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7187,
+ 0,
+ 7201,
+ 7204,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7206,
+ 7207,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7211,
+ 7216,
+ 0,
+ 7218,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7226,
+ 7228,
+ 7230,
+ 7232,
+ 7233,
+ 7235,
+ 7237,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7238,
+ 7241,
+ 0,
+ 7242,
+ 0,
+ 0,
+ 7247,
+ 0,
+ 0,
+ 0,
+ 7266,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7289,
+ 0,
+ 0,
+ 7290,
+ 7291,
+ 0,
+ 0,
+ 7292,
+ 0,
+ 7297,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7300,
+ 0,
+ 7301,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7302,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7305,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7307,
+ 0,
+ 7308,
+ 0,
+ 7310,
+ 0,
+ 7335,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7337,
+ 0,
+ 7343,
+ 7347,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7348,
+ 0,
+ 7349,
+ 7350,
+ 7352,
+ 7354,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7357,
+ 0,
+ 7358,
+ 7366,
+ 0,
+ 7367,
+ 7368,
+ 0,
+ 0,
+ 7373,
+ 0,
+ 0,
+ 0,
+ 7374,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7376,
+ 0,
+ 0,
+ 0,
+ 7377,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7378,
+ 0,
+ 7379,
+ 7380,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7383,
+ 0,
+ 0,
+ 7386,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7398,
+ 0,
+ 0,
+ 0,
+ 7399,
+ 7400,
+ 0,
+ 7401,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7402,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7405,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7406,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7421,
+ 7427,
+ 7429,
+ 0,
+ 0,
+ 0,
+ 7435,
+ 0,
+ 0,
+ 7436,
+ 0,
+ 0,
+ 0,
+ 7437,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7438,
+ 7443,
+ 0,
+ 7446,
+ 0,
+ 7448,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7456,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7457,
+ 0,
+ 0,
+ 7461,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7462,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7463,
+ 7466,
+ 7472,
+ 0,
+ 7476,
+ 0,
+ 0,
+ 7490,
+ 0,
+ 7491,
+ 0,
+ 0,
+ 7493,
+ 0,
+ 0,
+ 0,
+ 7498,
+ 7499,
+ 0,
+ 0,
+ 7508,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7512,
+ 0,
+ 0,
+ 0,
+ 7513,
+ 7514,
+ 7516,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7518,
+ 0,
+ 0,
+ 7519,
+ 7521,
+ 7522,
+ 0,
+ 0,
+ 0,
+ 7526,
+ 0,
+ 0,
+ 7529,
+ 0,
+ 0,
+ 7531,
+ 0,
+ 7536,
+ 0,
+ 7538,
+ 0,
+ 7539,
+ 0,
+ 0,
+ 7541,
+ 7542,
+ 7546,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7547,
+ 0,
+ 7548,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7550,
+ 0,
+ 0,
+ 7552,
+ 7553,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7554,
+ 7563,
+ 0,
+ 7573,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7574,
+ 7576,
+ 0,
+ 7578,
+ 7581,
+ 7583,
+ 0,
+ 0,
+ 0,
+ 7584,
+ 0,
+ 7587,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7589,
+ 0,
+ 0,
+ 0,
+ 7594,
+ 0,
+ 0,
+ 7595,
+ 0,
+ 0,
+ 7600,
+ 7602,
+ 7610,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7612,
+ 0,
+ 7613,
+ 7614,
+ 0,
+ 0,
+ 7615,
+ 0,
+ 0,
+ 7616,
+ 0,
+ 7620,
+ 0,
+ 7621,
+ 7622,
+ 0,
+ 7623,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7626,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7627,
+ 7629,
+ 7631,
+ 0,
+ 0,
+ 7633,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7639,
+ 0,
+ 7640,
+ 7642,
+ 0,
+ 0,
+ 7643,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7644,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7645,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7661,
+ 7662,
+ 7663,
+ 7665,
+ 0,
+ 7666,
+ 0,
+ 7667,
+ 0,
+ 7684,
+ 7688,
+ 7690,
+ 0,
+ 7691,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7692,
+ 0,
+ 0,
+ 7700,
+ 0,
+ 7707,
+ 0,
+ 7708,
+ 0,
+ 7709,
+ 0,
+ 7721,
+ 0,
+ 0,
+ 0,
+ 7722,
+ 0,
+ 7724,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7729,
+ 7731,
+ 0,
+ 7732,
+ 0,
+ 7733,
+ 7735,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7739,
+ 0,
+ 0,
+ 7741,
+ 7745,
+ 0,
+ 7748,
+ 0,
+ 0,
+ 0,
+ 7751,
+ 0,
+ 0,
+ 0,
+ 7752,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7753,
+ 0,
+ 0,
+ 7756,
+ 0,
+ 7757,
+ 0,
+ 7759,
+ 0,
+ 7760,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7761,
+ 7768,
+ 0,
+ 0,
+ 7769,
+ 0,
+ 0,
+ 7770,
+ 0,
+ 0,
+ 7771,
+ 0,
+ 0,
+ 7772,
+ 0,
+ 0,
+ 7773,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7778,
+ 7783,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7784,
+ 7785,
+ 0,
+ 7790,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7792,
+ 0,
+ 7798,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7799,
+ 0,
+ 7810,
+ 0,
+ 0,
+ 7813,
+ 0,
+ 7814,
+ 0,
+ 7816,
+ 0,
+ 7818,
+ 7824,
+ 7825,
+ 7826,
+ 0,
+ 7828,
+ 7830,
+ 0,
+ 0,
+ 0,
+ 7840,
+ 0,
+ 7842,
+ 0,
+ 7843,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7844,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7846,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7856,
+ 7857,
+ 7858,
+ 7862,
+ 0,
+ 7865,
+ 0,
+ 0,
+ 7866,
+ 0,
+ 0,
+ 7913,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7914,
+ 0,
+ 0,
+ 7915,
+ 7917,
+ 7918,
+ 7919,
+ 0,
+ 7920,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7921,
+ 7922,
+ 0,
+ 7924,
+ 0,
+ 0,
+ 7925,
+ 0,
+ 0,
+ 7927,
+ 0,
+ 7930,
+ 7935,
+ 0,
+ 0,
+ 7937,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7939,
+ 0,
+ 7940,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7941,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7945,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7949,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7950,
+ 0,
+ 7953,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7968,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7969,
+ 7972,
+ 7992,
+ 0,
+ 7993,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7994,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8007,
+ 8008,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8010,
+ 0,
+ 0,
+ 0,
+ 8012,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8018,
+ 0,
+ 8028,
+ 8029,
+ 0,
+ 0,
+ 8030,
+ 0,
+ 0,
+ 8032,
+ 8033,
+ 0,
+ 0,
+ 8034,
+ 8036,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8037,
+ 0,
+ 0,
+ 0,
+ 8043,
+ 8052,
+ 8059,
+ 8060,
+ 0,
+ 0,
+ 8061,
+ 0,
+ 0,
+ 0,
+ 8062,
+ 0,
+ 8063,
+ 0,
+ 8064,
+ 0,
+ 8066,
+ 8068,
+ 0,
+ 0,
+ 0,
+ 8080,
+ 8081,
+ 0,
+ 8089,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8092,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8093,
+ 8110,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8111,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8112,
+ 8115,
+ 0,
+ 8117,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8120,
+ 8121,
+ 8122,
+ 8128,
+ 8129,
+ 8130,
+ 8131,
+ 0,
+ 0,
+ 8139,
+ 0,
+ 0,
+ 8144,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8145,
+ 8146,
+ 8153,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8154,
+ 0,
+ 8157,
+ 8160,
+ 8162,
+ 0,
+ 8164,
+ 8165,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8166,
+ 8167,
+ 0,
+ 0,
+ 8179,
+ 0,
+ 0,
+ 0,
+ 8185,
+ 0,
+ 0,
+ 0,
+ 8186,
+ 0,
+ 0,
+ 8187,
+ 0,
+ 0,
+ 0,
+ 8188,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8204,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8210,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8213,
+ 0,
+ 8214,
+ 0,
+ 0,
+ 8215,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8218,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8219,
+ 0,
+ 8221,
+ 0,
+ 0,
+ 8222,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8225,
+ 0,
+ 0,
+ 0,
+ 8233,
+ 0,
+ 0,
+ 8242,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8247,
+ 0,
+ 8248,
+ 8252,
+ 0,
+ 8256,
+ 8257,
+ 0,
+ 0,
+ 8261,
+ 0,
+ 8264,
+ 8265,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8267,
+ 0,
+ 0,
+ 0,
+ 8269,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8270,
+ 0,
+ 0,
+ 0,
+ 8278,
+ 0,
+ 8279,
+ 8283,
+ 0,
+ 0,
+ 8285,
+ 8286,
+ 8289,
+ 8292,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8293,
+ 8295,
+ 8299,
+ 8300,
+ 8301,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8304,
+ 8307,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8321,
+ 0,
+ 0,
+ 0,
+ 8322,
+ 8323,
+ 8325,
+ 8326,
+ 8327,
+ 0,
+ 0,
+ 8332,
+ 8338,
+ 0,
+ 0,
+ 8340,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8350,
+ 0,
+ 0,
+ 8351,
+ 0,
+ 8354,
+ 8355,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8360,
+ 8372,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8377,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8380,
+ 0,
+ 0,
+ 0,
+ 8383,
+ 0,
+ 8384,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8386,
+ 8392,
+ 0,
+ 0,
+ 8394,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8396,
+ 8397,
+ 0,
+ 8398,
+ 0,
+ 8399,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8400,
+ 0,
+ 8401,
+ 8410,
+ 8411,
+ 0,
+ 8412,
+ 8413,
+ 8422,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8423,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8424,
+ 0,
+ 0,
+ 8425,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8441,
+ 8442,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8443,
+ 0,
+ 0,
+ 8444,
+ 0,
+ 8447,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8451,
+ 0,
+ 8458,
+ 0,
+ 8462,
+ 0,
+ 0,
+ 8468,
+ 0,
+ 8469,
+ 0,
+ 0,
+ 0,
+ 8470,
+ 0,
+ 8473,
+ 8479,
+ 8480,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8481,
+ 8483,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8484,
+ 0,
+ 0,
+ 8490,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8491,
+ 8493,
+ 8494,
+ 0,
+ 8528,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8530,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8534,
+ 8538,
+ 8540,
+ 0,
+ 0,
+ 8541,
+ 0,
+ 0,
+ 8545,
+ 0,
+ 8557,
+ 0,
+ 0,
+ 8569,
+ 8570,
+ 0,
+ 0,
+ 8571,
+ 8574,
+ 8575,
+ 8579,
+ 0,
+ 8583,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8591,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8606,
+ 0,
+ 8607,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8608,
+ 0,
+ 0,
+ 8609,
+ 0,
+ 0,
+ 0,
+ 8610,
+ 0,
+ 0,
+ 0,
+ 8611,
+ 0,
+ 0,
+ 8613,
+ 8617,
+ 8621,
+ 0,
+ 0,
+ 8622,
+ 0,
+ 8623,
+ 0,
+ 8624,
+ 8625,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8637,
+ 8638,
+ 8639,
+ 8650,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8652,
+ 8654,
+ 8655,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8656,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8657,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8658,
+ 0,
+ 0,
+ 8659,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8660,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8661,
+ 8663,
+ 8664,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8665,
+ 0,
+ 8669,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8671,
+ 8674,
+ 0,
+ 8684,
+ 0,
+ 8686,
+ 0,
+ 0,
+ 0,
+ 8689,
+ 0,
+ 0,
+ 0,
+ 8690,
+ 0,
+ 8706,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8710,
+ 0,
+ 8711,
+ 8713,
+ 8714,
+ 8724,
+ 8727,
+ 8728,
+ 8733,
+ 8736,
+ 0,
+ 8737,
+ 8739,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8742,
+ 8743,
+ 8745,
+ 8754,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8756,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8757,
+ 8760,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8762,
+ 8763,
+ 8764,
+ 0,
+ 8766,
+ 8769,
+ 8770,
+ 8773,
+ 0,
+ 8774,
+ 0,
+ 8779,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8780,
+ 0,
+ 0,
+ 8781,
+ 0,
+ 0,
+ 8783,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8784,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8785,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8786,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8788,
+ 8790,
+ 0,
+ 0,
+ 0,
+ 8803,
+ 0,
+ 8813,
+ 8814,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8815,
+ 8816,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8818,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8822,
+ 8828,
+ 8829,
+ 0,
+ 8831,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8833,
+ 0,
+ 0,
+ 0,
+ 8834,
+ 0,
+ 0,
+ 0,
+ 8835,
+ 0,
+ 8836,
+ 0,
+ 0,
+ 0,
+ 8837,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8838,
+ 8839,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8840,
+ 0,
+ 0,
+ 0,
+ 8841,
+ 0,
+ 8842,
+ 0,
+ 0,
+ 0,
+ 8846,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8847,
+ 0,
+ 8848,
+ 0,
+ 0,
+ 8864,
+ 0,
+ 0,
+ 8866,
+ 0,
+ 0,
+ 8870,
+ 8872,
+ 0,
+ 0,
+ 8873,
+ 8874,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8875,
+ 0,
+ 8876,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8896,
+ 8900,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8901,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8904,
+ 0,
+ 8907,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8911,
+ 8912,
+ 8913,
+ 0,
+ 0,
+ 0,
+ 8914,
+ 0,
+ 8915,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8916,
+ 0,
+ 0,
+ 0,
+ 8929,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8930,
+ 0,
+ 8932,
+ 0,
+ 8943,
+ 0,
+ 0,
+ 0,
+ 8945,
+ 8947,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8949,
+ 0,
+ 8950,
+ 0,
+ 8954,
+ 8957,
+ 0,
+ 0,
+ 8970,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8971,
+ 0,
+ 8996,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8997,
+ 9000,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9001,
+ 9002,
+ 0,
+ 9004,
+ 9009,
+ 9024,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9027,
+ 9082,
+ 0,
+ 0,
+ 9083,
+ 9089,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9090,
+ 0,
+ 0,
+ 0,
+ 9092,
+ 0,
+ 0,
+ 9093,
+ 0,
+ 9095,
+ 0,
+ 0,
+ 9096,
+ 9097,
+ 9101,
+ 9102,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9112,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9114,
+ 0,
+ 0,
+ 9120,
+ 0,
+ 9121,
+ 9122,
+ 0,
+ 0,
+ 0,
+ 9123,
+ 9124,
+ 0,
+ 0,
+ 9125,
+ 0,
+ 0,
+ 9126,
+ 0,
+ 9127,
+ 0,
+ 0,
+ 9129,
+ 9131,
+ 0,
+ 0,
+ 0,
+ 9132,
+ 0,
+ 0,
+ 9136,
+ 0,
+ 9144,
+ 0,
+ 0,
+ 9148,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9149,
+ 0,
+ 9152,
+ 9163,
+ 0,
+ 0,
+ 9165,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9166,
+ 0,
+ 9169,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9170,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9172,
+ 0,
+ 9174,
+ 9175,
+ 9176,
+ 0,
+ 9177,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9186,
+ 0,
+ 9187,
+ 0,
+ 0,
+ 0,
+ 9188,
+ 9189,
+ 0,
+ 0,
+ 9190,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9191,
+ 0,
+ 0,
+ 0,
+ 9193,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9197,
+ 9198,
+ 0,
+ 0,
+ 0,
+ 9208,
+ 9211,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9216,
+ 9217,
+ 0,
+ 9220,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9221,
+ 9222,
+ 9223,
+ 0,
+ 9224,
+ 9225,
+ 0,
+ 0,
+ 9227,
+ 0,
+ 9228,
+ 9229,
+ 0,
+ 0,
+ 9230,
+ 0,
+ 9232,
+ 0,
+ 9233,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9234,
+ 9235,
+ 0,
+ 0,
+ 9237,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9238,
+ 9240,
+ 0,
+ 0,
+ 9241,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9244,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9247,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9248,
+ 0,
+ 0,
+ 0,
+ 9249,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9250,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9251,
+ 0,
+ 0,
+ 9252,
+ 9255,
+ 0,
+ 0,
+ 0,
+ 9256,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9257,
+ 0,
+ 0,
+ 9258,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9259,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9262,
+ 9263,
+ 0,
+ 0,
+ 9265,
+ 9266,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9268,
+ 9271,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9273,
+ 0,
+ 0,
+ 0,
+ 9276,
+ 9277,
+ 9279,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9280,
+ 0,
+ 0,
+ 9293,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9297,
+ 9301,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9308,
+ 9309,
+ 9313,
+ 9321,
+ 9322,
+ 0,
+ 9326,
+ 9327,
+ 0,
+ 0,
+ 9477,
+ 0,
+ 9479,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9482,
+ 0,
+ 0,
+ 0,
+ 9483,
+ 0,
+ 9484,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9485,
+ 0,
+ 0,
+ 9486,
+ 0,
+ 0,
+ 0,
+ 9489,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9490,
+ 9491,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9493,
+ 0,
+ 9495,
+ 9496,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9500,
+ 0,
+ 9502,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9504,
+ 9507,
+ 0,
+ 9509,
+ 0,
+ 9511,
+ 0,
+ 0,
+ 9513,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9515,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9516,
+ 9517,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9532,
+ 0,
+ 0,
+ 9533,
+ 0,
+ 0,
+ 9538,
+ 0,
+ 9539,
+ 9540,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9541,
+ 0,
+ 0,
+ 0,
+ 9542,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9544,
+ 9545,
+ 0,
+ 9546,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9547,
+ 9548,
+ 0,
+ 0,
+ 0,
+ 9550,
+ 0,
+ 9557,
+ 0,
+ 9558,
+ 0,
+ 9561,
+ 0,
+ 9563,
+ 9570,
+ 0,
+ 9572,
+ 9574,
+ 9575,
+ 0,
+ 0,
+ 0,
+ 9577,
+ 9592,
+ 0,
+ 0,
+ 9596,
+ 0,
+ 0,
+ 0,
+ 9598,
+ 0,
+ 9600,
+ 0,
+ 9601,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9608,
+ 0,
+ 9638,
+ 9639,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9641,
+ 0,
+ 0,
+ 9643,
+ 9644,
+ 9645,
+ 9646,
+ 0,
+ 0,
+ 0,
+ 9648,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9650,
+ 9654,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9655,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9656,
+ 0,
+ 9657,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9658,
+ 0,
+ 0,
+ 9659,
+ 0,
+ 0,
+ 9664,
+ 0,
+ 0,
+ 9665,
+ 0,
+ 9667,
+ 9669,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9671,
+ 0,
+ 9673,
+ 9681,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9682,
+ 9683,
+ 9684,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9686,
+ 9698,
+ 0,
+ 0,
+ 9700,
+ 9701,
+ 9702,
+ 0,
+ 9703,
+ 9717,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9718,
+ 0,
+ 9726,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9727,
+ 0,
+ 0,
+ 0,
+ 9728,
+ 0,
+ 9742,
+ 0,
+ 9744,
+ 0,
+ 0,
+ 0,
+ 9750,
+ 0,
+ 9754,
+ 9755,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9756,
+ 0,
+ 9757,
+ 9768,
+ 0,
+ 9769,
+ 0,
+ 0,
+ 0,
+ 9770,
+ 9771,
+ 0,
+ 9773,
+ 0,
+ 9774,
+ 0,
+ 9775,
+ 0,
+ 0,
+ 0,
+ 9776,
+ 9777,
+ 9784,
+ 0,
+ 0,
+ 0,
+ 9786,
+ 0,
+ 9789,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9793,
+ 9794,
+ 0,
+ 0,
+ 0,
+ 9808,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9811,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9812,
+ 0,
+ 9820,
+ 0,
+ 9823,
+ 0,
+ 9828,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9830,
+ 0,
+ 0,
+ 9833,
+ 9836,
+ 0,
+ 0,
+ 0,
+ 9840,
+ 0,
+ 0,
+ 0,
+ 9841,
+ 0,
+ 0,
+ 9842,
+ 0,
+ 9845,
+ 0,
+ 0,
+ 0,
+ 9847,
+ 9848,
+ 0,
+ 0,
+ 9855,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9856,
+ 9863,
+ 9865,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9866,
+ 9867,
+ 9868,
+ 9873,
+ 9875,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9880,
+ 0,
+ 9886,
+ 0,
+ 0,
+ 0,
+ 9887,
+ 0,
+ 0,
+ 9891,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9906,
+ 9907,
+ 9908,
+ 0,
+ 0,
+ 0,
+ 9909,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9910,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9913,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9914,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9922,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9923,
+ 9925,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9930,
+ 0,
+ 0,
+ 0,
+ 9931,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9932,
+ 0,
+ 9939,
+ 0,
+ 0,
+ 9940,
+ 9962,
+ 9966,
+ 0,
+ 9969,
+ 9970,
+ 0,
+ 0,
+ 9974,
+ 0,
+ 9979,
+ 9981,
+ 9982,
+ 0,
+ 0,
+ 0,
+ 9985,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9987,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9988,
+ 9993,
+ 0,
+ 0,
+ 9994,
+ 0,
+ 0,
+ 0,
+ 9997,
+ 0,
+ 10004,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10007,
+ 10019,
+ 10020,
+ 10022,
+ 0,
+ 0,
+ 0,
+ 10031,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10032,
+ 0,
+ 0,
+ 10034,
+ 0,
+ 10036,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10038,
+ 0,
+ 10039,
+ 10040,
+ 10041,
+ 10042,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10043,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10045,
+ 10054,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10055,
+ 0,
+ 0,
+ 10057,
+ 10058,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10059,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10060,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10063,
+ 0,
+ 10066,
+ 0,
+ 0,
+ 0,
+ 10070,
+ 0,
+ 10072,
+ 0,
+ 0,
+ 10076,
+ 10077,
+ 0,
+ 0,
+ 10084,
+ 0,
+ 10087,
+ 10090,
+ 10091,
+ 0,
+ 0,
+ 0,
+ 10094,
+ 10097,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10098,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10103,
+ 0,
+ 10104,
+ 0,
+ 10108,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10120,
+ 0,
+ 0,
+ 0,
+ 10122,
+ 0,
+ 0,
+ 10125,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10127,
+ 10128,
+ 0,
+ 0,
+ 10134,
+ 0,
+ 10135,
+ 10136,
+ 0,
+ 10137,
+ 0,
+ 0,
+ 10147,
+ 0,
+ 10149,
+ 10150,
+ 0,
+ 0,
+ 10156,
+ 0,
+ 10158,
+ 10159,
+ 10160,
+ 10168,
+ 0,
+ 0,
+ 10171,
+ 0,
+ 10173,
+ 0,
+ 0,
+ 0,
+ 10176,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10177,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10178,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10194,
+ 0,
+ 10202,
+ 0,
+ 0,
+ 10203,
+ 10204,
+ 0,
+ 10205,
+ 10206,
+ 0,
+ 10207,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10209,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10213,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10217,
+ 0,
+ 10229,
+ 0,
+ 10230,
+ 10231,
+ 0,
+ 0,
+ 10232,
+ 0,
+ 0,
+ 10237,
+ 10238,
+ 10244,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10250,
+ 0,
+ 10252,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10255,
+ 0,
+ 0,
+ 10257,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10258,
+ 0,
+ 10259,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10260,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10284,
+ 10288,
+ 10289,
+ 0,
+ 0,
+ 0,
+ 10290,
+ 0,
+ 10296,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10297,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10298,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10299,
+ 10303,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10306,
+ 0,
+ 0,
+ 0,
+ 10307,
+ 0,
+ 10308,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10311,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10315,
+ 10317,
+ 0,
+ 0,
+ 0,
+ 10318,
+ 10319,
+ 0,
+ 10321,
+ 0,
+ 10326,
+ 0,
+ 10328,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10329,
+ 0,
+ 0,
+ 10331,
+ 0,
+ 10332,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10334,
+ 0,
+ 0,
+ 10335,
+ 10338,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10339,
+ 10349,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10351,
+ 0,
+ 10353,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10362,
+ 0,
+ 10368,
+ 0,
+ 10369,
+ 0,
+ 0,
+ 0,
+ 10372,
+ 10373,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10374,
+ 0,
+ 0,
+ 0,
+ 10375,
+ 0,
+ 10376,
+ 0,
+ 0,
+ 10386,
+ 10388,
+ 10390,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10391,
+ 0,
+ 0,
+ 10392,
+ 10394,
+ 0,
+ 0,
+ 10396,
+ 0,
+ 10397,
+ 0,
+ 10403,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10404,
+ 0,
+ 10405,
+ 10410,
+ 0,
+ 0,
+ 10411,
+ 0,
+ 10412,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10421,
+ 10422,
+ 10423,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10425,
+ 0,
+ 0,
+ 10427,
+ 0,
+ 0,
+ 10430,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10432,
+ 0,
+ 10433,
+ 10434,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10436,
+ 10437,
+ 0,
+ 10438,
+ 0,
+ 10439,
+ 0,
+ 10444,
+ 10446,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10448,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10449,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10451,
+ 0,
+ 10453,
+ 0,
+ 0,
+ 0,
+ 10454,
+ 10457,
+ 0,
+ 0,
+ 10459,
+ 0,
+ 10469,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10472,
+ 10481,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10482,
+ 10483,
+ 0,
+ 10492,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10499,
+ 0,
+ 0,
+ 0,
+ 10502,
+ 0,
+ 0,
+ 10510,
+ 0,
+ 10521,
+ 10524,
+ 0,
+ 0,
+ 10525,
+ 10526,
+ 10528,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10530,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10533,
+ 0,
+ 10534,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10535,
+ 10536,
+ 0,
+ 0,
+ 10544,
+ 0,
+ 10553,
+ 10556,
+ 0,
+ 10557,
+ 10559,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10562,
+ 10563,
+ 10564,
+ 0,
+ 10565,
+ 0,
+ 0,
+ 0,
+ 10566,
+ 0,
+ 10567,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10575,
+ 0,
+ 0,
+ 10576,
+ 0,
+ 10578,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10585,
+ 10586,
+ 10587,
+ 10589,
+ 0,
+ 10590,
+ 0,
+ 0,
+ 10594,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10598,
+ 0,
+ 0,
+ 10601,
+ 0,
+ 0,
+ 0,
+ 10602,
+ 0,
+ 10603,
+ 0,
+ 10604,
+ 0,
+ 10605,
+ 0,
+ 0,
+ 10607,
+ 0,
+ 10626,
+ 0,
+ 10627,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10629,
+ 10630,
+ 10631,
+ 0,
+ 0,
+ 0,
+ 10646,
+ 0,
+ 0,
+ 0,
+ 10647,
+ 0,
+ 10650,
+ 0,
+ 10651,
+ 0,
+ 0,
+ 0,
+ 10652,
+ 10653,
+ 10655,
+ 0,
+ 10658,
+ 0,
+ 0,
+ 10659,
+ 0,
+ 10667,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10669,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10670,
+ 0,
+ 0,
+ 0,
+ 10671,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10672,
+ 10673,
+ 0,
+ 10674,
+ 0,
+ 0,
+ 0,
+ 10676,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10678,
+ 0,
+ 10682,
+ 0,
+ 0,
+ 10692,
+ 0,
+ 10697,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10698,
+ 0,
+ 0,
+ 0,
+ 10700,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10703,
+ 0,
+ 10704,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10705,
+ 0,
+ 10715,
+ 10718,
+ 10720,
+ 0,
+ 0,
+ 10722,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10723,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10726,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10727,
+ 10730,
+ 10743,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10744,
+ 0,
+ 0,
+ 10745,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10748,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10750,
+ 0,
+ 0,
+ 10752,
+ 10753,
+ 0,
+ 0,
+ 0,
+ 10756,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10758,
+ 0,
+ 0,
+ 0,
+ 10759,
+ 0,
+ 10769,
+ 0,
+ 0,
+ 10772,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10773,
+ 0,
+ 0,
+ 0,
+ 10777,
+ 0,
+ 0,
+ 10779,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10780,
+ 10784,
+ 0,
+ 0,
+ 0,
+ 10789,
+ 0,
+ 0,
+ 0,
+ 10791,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10795,
+ 0,
+ 0,
+ 10796,
+ 0,
+ 10808,
+ 0,
+ 10809,
+ 0,
+ 0,
+ 0,
+ 10810,
+ 0,
+ 0,
+ 0,
+ 10812,
+ 0,
+ 0,
+ 10814,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10815,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10816,
+ 10817,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10819,
+ 0,
+ 10820,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10821,
+ 10822,
+ 10823,
+ 0,
+ 10826,
+ 10849,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10850,
+ 0,
+ 0,
+ 10852,
+ 0,
+ 10853,
+ 0,
+ 0,
+ 10856,
+ 0,
+ 0,
+ 10857,
+ 10858,
+ 10859,
+ 10860,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10863,
+ 0,
+ 10866,
+ 10867,
+ 10872,
+ 10890,
+ 0,
+ 0,
+ 10891,
+ 10892,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10893,
+ 0,
+ 0,
+ 0,
+ 10896,
+ 10899,
+ 0,
+ 0,
+ 10900,
+ 10902,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10903,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10905,
+ 0,
+ 10906,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10908,
+ 10911,
+ 0,
+ 10912,
+ 0,
+ 0,
+ 10916,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10917,
+ 0,
+ 10918,
+ 0,
+ 0,
+ 0,
+ 10923,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10924,
+ 0,
+ 0,
+ 10928,
+ 10929,
+ 0,
+ 0,
+ 10930,
+ 0,
+ 0,
+ 0,
+ 10932,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10939,
+ 0,
+ 0,
+ 10945,
+ 0,
+ 0,
+ 0,
+ 10947,
+ 0,
+ 0,
+ 10948,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10958,
+ 0,
+ 10960,
+ 10962,
+ 0,
+ 0,
+ 10964,
+ 0,
+ 0,
+ 0,
+ 10966,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10967,
+ 0,
+ 0,
+ 0,
+ 10968,
+ 0,
+ 0,
+ 0,
+ 10973,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10975,
+ 0,
+ 0,
+ 0,
+ 10976,
+ 10978,
+ 0,
+ 0,
+ 10982,
+ 10984,
+ 10987,
+ 0,
+ 0,
+ 10988,
+ 0,
+ 10989,
+ 0,
+ 0,
+ 10991,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10992,
+ 0,
+ 0,
+ 0,
+ 10993,
+ 0,
+ 10995,
+ 0,
+ 0,
+ 0,
+ 10996,
+ 10997,
+ 0,
+ 0,
+ 0,
+ 10998,
+ 0,
+ 10999,
+ 0,
+ 11001,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11010,
+ 11012,
+ 0,
+ 11013,
+ 11016,
+ 11017,
+ 0,
+ 0,
+ 11019,
+ 11020,
+ 11021,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11022,
+ 0,
+ 0,
+ 11023,
+ 11029,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11031,
+ 0,
+ 0,
+ 0,
+ 11034,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11055,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11056,
+ 11060,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11061,
+ 0,
+ 0,
+ 11064,
+ 11065,
+ 0,
+ 11066,
+ 0,
+ 11069,
+ 0,
+ 11085,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11086,
+ 0,
+ 0,
+ 0,
+ 11088,
+ 0,
+ 0,
+ 0,
+ 11094,
+ 0,
+ 0,
+ 0,
+ 11095,
+ 11096,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11097,
+ 11098,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11099,
+ 0,
+ 0,
+ 11102,
+ 11108,
+ 0,
+ 0,
+ 0,
+ 11109,
+ 0,
+ 11114,
+ 11119,
+ 0,
+ 11131,
+ 0,
+ 0,
+ 0,
+ 11142,
+ 0,
+ 0,
+ 11143,
+ 0,
+ 11146,
+ 0,
+ 11147,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11148,
+ 0,
+ 11149,
+ 11152,
+ 11153,
+ 11154,
+ 0,
+ 11156,
+ 0,
+ 11157,
+ 0,
+ 0,
+ 0,
+ 11158,
+ 0,
+ 0,
+ 11159,
+ 11160,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11163,
+ 0,
+ 0,
+ 11164,
+ 11166,
+ 0,
+ 0,
+ 0,
+ 11172,
+ 11174,
+ 0,
+ 0,
+ 0,
+ 11176,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11182,
+ 11183,
+ 0,
+ 0,
+ 0,
+ 11184,
+ 11187,
+ 0,
+ 0,
+ 11188,
+ 11189,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11194,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11200,
+ 11202,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11203,
+ 0,
+ 11204,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11205,
+ 0,
+ 0,
+ 0,
+ 11206,
+ 0,
+ 11207,
+ 0,
+ 0,
+ 11209,
+ 0,
+ 11211,
+ 0,
+ 11214,
+ 0,
+ 0,
+ 11231,
+ 0,
+ 0,
+ 0,
+ 11293,
+ 11295,
+ 0,
+ 0,
+ 11296,
+ 11297,
+ 11302,
+ 0,
+ 0,
+ 0,
+ 11307,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11309,
+ 11310,
+ 0,
+ 11311,
+ 0,
+ 0,
+ 0,
+ 11313,
+ 0,
+ 11314,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11334,
+ 0,
+ 11338,
+ 0,
+ 0,
+ 0,
+ 11339,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11340,
+ 0,
+ 11341,
+ 11342,
+ 0,
+ 11344,
+ 0,
+ 11345,
+ 0,
+ 0,
+ 0,
+ 11348,
+ 11349,
+ 0,
+ 0,
+ 11350,
+ 0,
+ 0,
+ 0,
+ 11355,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11356,
+ 0,
+ 11357,
+ 11370,
+ 0,
+ 0,
+ 11371,
+ 0,
+ 11374,
+ 11376,
+ 0,
+ 0,
+ 0,
+ 11377,
+ 0,
+ 0,
+ 11378,
+ 11383,
+ 0,
+ 11386,
+ 11399,
+ 0,
+ 11400,
+ 11406,
+ 0,
+ 0,
+ 0,
+ 11408,
+ 0,
+ 0,
+ 11409,
+ 11412,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11417,
+ 0,
+ 0,
+ 0,
+ 11418,
+ 0,
+ 11421,
+ 0,
+ 11426,
+ 11429,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11430,
+ 0,
+ 11437,
+ 0,
+ 11438,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11440,
+ 11453,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11454,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11455,
+ 0,
+ 0,
+ 11456,
+ 11460,
+ 11461,
+ 11463,
+ 0,
+ 11469,
+ 0,
+ 11473,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11474,
+ 0,
+ 0,
+ 0,
+ 11475,
+ 0,
+ 11476,
+ 11477,
+ 11480,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11481,
+ 0,
+ 0,
+ 11484,
+ 0,
+ 0,
+ 11487,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11497,
+ 0,
+ 0,
+ 11502,
+ 0,
+ 11509,
+ 0,
+ 0,
+ 11510,
+ 11511,
+ 11513,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11515,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11516,
+ 0,
+ 11520,
+ 11521,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11529,
+ 11530,
+ 11531,
+ 11534,
+ 0,
+ 0,
+ 11543,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11547,
+ 0,
+ 11548,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11552,
+ 11556,
+ 0,
+ 11557,
+ 0,
+ 0,
+ 11559,
+ 0,
+ 11560,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11561,
+ 0,
+ 0,
+ 11563,
+ 11564,
+ 0,
+ 11565,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11567,
+ 0,
+ 0,
+ 0,
+ 11569,
+ 0,
+ 11574,
+ 0,
+ 11575,
+ 0,
+ 0,
+ 0,
+ 11577,
+ 0,
+ 11578,
+ 0,
+ 0,
+ 0,
+ 11580,
+ 11581,
+ 0,
+ 0,
+ 0,
+ 11582,
+ 11584,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11587,
+ 0,
+ 11588,
+ 11591,
+ 0,
+ 11595,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11596,
+ 0,
+ 11597,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11598,
+ 11601,
+ 0,
+ 0,
+ 0,
+ 11602,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11603,
+ 11604,
+ 0,
+ 11606,
+ 0,
+ 0,
+ 11608,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11610,
+ 0,
+ 0,
+ 11611,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11613,
+ 0,
+ 11622,
+ 0,
+ 0,
+ 0,
+ 11623,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11625,
+ 0,
+ 0,
+ 11626,
+ 11627,
+ 11628,
+ 11630,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11639,
+ 0,
+ 0,
+ 11646,
+ 0,
+ 11648,
+ 11649,
+ 0,
+ 11650,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11651,
+ 0,
+ 0,
+ 11652,
+ 11653,
+ 11656,
+ 0,
+ 0,
+ 11677,
+ 11679,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11680,
+ 0,
+ 0,
+ 11681,
+ 0,
+ 11685,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11688,
+ 0,
+ 0,
+ 0,
+ 11716,
+ 0,
+ 11719,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11721,
+ 0,
+ 0,
+ 11724,
+ 11743,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11745,
+ 11748,
+ 11750,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11751,
+ 0,
+ 0,
+ 0,
+ 11752,
+ 11754,
+ 0,
+ 11755,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11759,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11760,
+ 0,
+ 0,
+ 0,
+ 11761,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11766,
+ 11767,
+ 0,
+ 11772,
+ 11773,
+ 0,
+ 11774,
+ 0,
+ 0,
+ 11775,
+ 0,
+ 11777,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11778,
+ 11780,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11783,
+ 0,
+ 11784,
+ 0,
+ 0,
+ 0,
+ 11785,
+ 0,
+ 0,
+ 0,
+ 11786,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11788,
+ 0,
+ 0,
+ 11789,
+ 11791,
+ 11792,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11795,
+ 11834,
+ 11835,
+ 11836,
+ 0,
+ 0,
+ 11837,
+ 0,
+ 0,
+ 0,
+ 11838,
+ 0,
+ 0,
+ 11846,
+ 11851,
+ 0,
+ 11852,
+ 0,
+ 11869,
+ 0,
+ 0,
+ 0,
+ 11871,
+ 0,
+ 0,
+ 0,
+ 11872,
+ 11874,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11875,
+ 0,
+ 11876,
+ 11877,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11883,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11884,
+ 0,
+ 11885,
+ 0,
+ 11886,
+ 0,
+ 0,
+ 11887,
+ 0,
+ 11894,
+ 11895,
+ 11897,
+ 11909,
+ 11910,
+ 0,
+ 11912,
+ 11918,
+ 0,
+ 0,
+ 11920,
+ 0,
+ 11922,
+ 11924,
+ 11927,
+ 11928,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11929,
+ 0,
+ 11934,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11941,
+ 11943,
+ 11944,
+ 0,
+ 11945,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11948,
+ 11949,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11953,
+ 0,
+ 11954,
+ 0,
+ 11955,
+ 0,
+ 11956,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11957,
+ 0,
+ 0,
+ 11959,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11961,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11978,
+ 0,
+ 0,
+ 0,
+ 11979,
+ 11980,
+ 11986,
+ 11987,
+ 0,
+ 11992,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11993,
+ 0,
+ 0,
+ 0,
+ 11994,
+ 0,
+ 11999,
+ 12004,
+ 12005,
+ 12006,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12011,
+ 0,
+ 0,
+ 12012,
+ 12014,
+ 0,
+ 0,
+ 12015,
+ 0,
+ 0,
+ 12019,
+ 12028,
+ 0,
+ 0,
+ 12029,
+ 0,
+ 0,
+ 12032,
+ 12033,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12034,
+ 0,
+ 12041,
+ 12043,
+ 0,
+ 0,
+ 12044,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12046,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12054,
+ 12055,
+ 0,
+ 12056,
+ 0,
+ 0,
+ 0,
+ 12060,
+ 12064,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12065,
+ 12067,
+ 12068,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12074,
+ 0,
+ 0,
+ 0,
+ 12075,
+ 12076,
+ 0,
+ 0,
+ 0,
+ 12079,
+ 0,
+ 12081,
+ 12086,
+ 12087,
+ 0,
+ 0,
+ 12088,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12089,
+ 0,
+ 12092,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12097,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12098,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12102,
+ 12103,
+ 12104,
+ 12111,
+ 0,
+ 0,
+ 12114,
+ 12116,
+ 0,
+ 0,
+ 0,
+ 12118,
+ 0,
+ 0,
+ 0,
+ 12119,
+ 12120,
+ 12128,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12130,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12131,
+ 0,
+ 0,
+ 0,
+ 12132,
+ 12134,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12137,
+ 0,
+ 12139,
+ 0,
+ 12141,
+ 0,
+ 0,
+ 12142,
+ 0,
+ 0,
+ 0,
+ 12144,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12145,
+ 0,
+ 12148,
+ 0,
+ 12153,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12154,
+ 12171,
+ 12173,
+ 0,
+ 0,
+ 0,
+ 12175,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12178,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12183,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12184,
+ 0,
+ 0,
+ 0,
+ 12186,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12187,
+ 12188,
+ 0,
+ 0,
+ 12189,
+ 0,
+ 12196,
+ 0,
+ 12197,
+ 0,
+ 0,
+ 12198,
+ 0,
+ 12201,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12203,
+ 0,
+ 12209,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12210,
+ 12211,
+ 12212,
+ 12213,
+ 0,
+ 12217,
+ 12218,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12222,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12223,
+ 0,
+ 0,
+ 12229,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12233,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12234,
+ 0,
+ 0,
+ 12236,
+ 12242,
+ 0,
+ 0,
+ 0,
+ 12243,
+ 0,
+ 0,
+ 0,
+ 12244,
+ 12253,
+ 0,
+ 12254,
+ 12256,
+ 0,
+ 12257,
+ 0,
+ 0,
+ 12275,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12277,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12278,
+ 0,
+ 12289,
+ 0,
+ 0,
+ 12290,
+ 0,
+ 12292,
+ 12293,
+ 0,
+ 0,
+ 12294,
+ 0,
+ 12295,
+ 0,
+ 0,
+ 12296,
+ 0,
+ 12297,
+ 0,
+ 12298,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12301,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12309,
+ 0,
+ 12338,
+ 12340,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12341,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12342,
+ 12343,
+ 0,
+ 12344,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12345,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12346,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12348,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12350,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12351,
+ 0,
+ 12355,
+ 12356,
+ 12357,
+ 0,
+ 0,
+ 12367,
+ 12370,
+ 12371,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12372,
+ 12376,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12379,
+ 0,
+ 12382,
+ 0,
+ 12383,
+ 0,
+ 0,
+ 12384,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12393,
+ 0,
+ 0,
+ 12394,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12398,
+ 12403,
+ 0,
+ 0,
+ 12404,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12410,
+ 0,
+ 0,
+ 0,
+ 12411,
+ 0,
+ 0,
+ 0,
+ 12412,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12420,
+ 0,
+ 12421,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12423,
+ 0,
+ 12425,
+ 12429,
+ 0,
+ 0,
+ 0,
+ 12431,
+ 12432,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12434,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12435,
+ 12436,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12437,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12438,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12445,
+ 0,
+ 0,
+ 0,
+ 12450,
+ 12451,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12452,
+ 12475,
+ 0,
+ 0,
+ 12493,
+ 12494,
+ 0,
+ 0,
+ 0,
+ 12495,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12496,
+ 12502,
+ 12509,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12510,
+ 0,
+ 12512,
+ 12513,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12514,
+ 0,
+ 0,
+ 0,
+ 12515,
+ 0,
+ 12520,
+ 0,
+ 0,
+ 0,
+ 12524,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12527,
+ 0,
+ 0,
+ 0,
+ 12528,
+ 0,
+ 0,
+ 0,
+ 12529,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12530,
+ 0,
+ 12535,
+ 0,
+ 0,
+ 12536,
+ 0,
+ 12538,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12540,
+ 0,
+ 12548,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12550,
+ 0,
+ 0,
+ 0,
+ 12551,
+ 12552,
+ 0,
+ 0,
+ 0,
+ 12554,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12555,
+ 0,
+ 0,
+ 12562,
+ 0,
+ 12565,
+ 0,
+ 12566,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12569,
+ 0,
+ 0,
+ 0,
+ 12571,
+ 12574,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12577,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12578,
+ 12579,
+ 12603,
+ 0,
+ 12608,
+ 0,
+ 0,
+ 12611,
+ 0,
+ 12612,
+ 0,
+ 12615,
+ 0,
+ 12625,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12627,
+ 12646,
+ 0,
+ 12648,
+ 0,
+ 0,
+ 12657,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12670,
+ 0,
+ 0,
+ 12671,
+ 0,
+ 12673,
+ 12677,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12679,
+ 0,
+ 12681,
+ 0,
+ 12682,
+ 12693,
+ 0,
+ 12694,
+ 0,
+ 12697,
+ 0,
+ 12701,
+ 0,
+ 0,
+ 0,
+ 12703,
+ 12704,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12707,
+ 12737,
+ 0,
+ 0,
+ 12739,
+ 0,
+ 0,
+ 12740,
+ 0,
+ 0,
+ 12742,
+ 12743,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12745,
+ 0,
+ 12746,
+ 12747,
+ 0,
+ 12748,
+ 0,
+ 0,
+ 12759,
+ 12767,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12773,
+ 0,
+ 12774,
+ 12778,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12779,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12780,
+ 12793,
+ 0,
+ 12824,
+ 0,
+ 12825,
+ 0,
+ 12836,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12839,
+ 0,
+ 12842,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12843,
+ 12845,
+ 0,
+ 12846,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12847,
+ 0,
+ 0,
+ 12850,
+ 12852,
+ 12853,
+ 0,
+ 0,
+ 0,
+ 12854,
+ 0,
+ 0,
+ 0,
+ 12855,
+ 0,
+ 12856,
+ 0,
+ 12858,
+ 0,
+ 0,
+ 12859,
+ 0,
+ 12862,
+ 0,
+ 12863,
+ 0,
+ 0,
+ 12866,
+ 0,
+ 12869,
+ 12872,
+ 12873,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12875,
+ 0,
+ 12877,
+ 0,
+ 0,
+ 12878,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12884,
+ 12885,
+ 12888,
+ 0,
+ 12889,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12893,
+ 0,
+ 0,
+ 0,
+ 12895,
+ 12896,
+ 12898,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12902,
+ 0,
+ 12909,
+ 12910,
+ 0,
+ 12926,
+ 0,
+ 12928,
+ 0,
+ 0,
+ 0,
+ 12929,
+ 0,
+ 12930,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12931,
+ 0,
+ 12932,
+ 12933,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12934,
+ 0,
+ 12942,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12944,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12946,
+ 0,
+ 0,
+ 12948,
+ 0,
+ 0,
+ 12949,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12950,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12951,
+ 0,
+ 12952,
+ 0,
+ 12953,
+ 0,
+ 0,
+ 0,
+ 12954,
+ 12958,
+ 12959,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12960,
+ 12964,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12966,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12970,
+ 0,
+ 12971,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12972,
+ 0,
+ 0,
+ 12982,
+ 0,
+ 0,
+ 0,
+ 12984,
+ 12985,
+ 0,
+ 12986,
+ 12996,
+ 12997,
+ 13001,
+ 13002,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13004,
+ 0,
+ 0,
+ 13005,
+ 0,
+ 0,
+ 13007,
+ 13009,
+ 0,
+ 13017,
+ 0,
+ 0,
+ 0,
+ 13020,
+ 0,
+ 13021,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13022,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13024,
+ 13027,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13028,
+ 0,
+ 0,
+ 13029,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13032,
+ 0,
+ 13037,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13040,
+ 0,
+ 0,
+ 13041,
+ 0,
+ 0,
+ 0,
+ 13043,
+ 13044,
+ 13046,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13047,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13049,
+ 13054,
+ 0,
+ 13056,
+ 0,
+ 0,
+ 13060,
+ 13061,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13067,
+ 0,
+ 0,
+ 13068,
+ 0,
+ 13071,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13077,
+ 13078,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13079,
+ 13080,
+ 13081,
+ 0,
+ 13082,
+ 0,
+ 0,
+ 0,
+ 13085,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13086,
+ 0,
+ 13087,
+ 13088,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13094,
+ 0,
+ 13099,
+ 0,
+ 13100,
+ 0,
+ 0,
+ 0,
+ 13101,
+ 0,
+ 13125,
+ 13126,
+ 13128,
+ 13129,
+ 0,
+ 0,
+ 13130,
+ 0,
+ 13131,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13134,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13150,
+ 0,
+ 13168,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13169,
+ 0,
+ 0,
+ 13170,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13174,
+ 0,
+ 0,
+ 0,
+ 13176,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13177,
+ 0,
+ 13178,
+ 13183,
+ 13187,
+ 0,
+ 0,
+ 0,
+ 13189,
+ 0,
+ 0,
+ 13190,
+ 0,
+ 0,
+ 13191,
+ 0,
+ 0,
+ 13206,
+ 0,
+ 0,
+ 0,
+ 13207,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13212,
+ 0,
+ 0,
+ 13219,
+ 13232,
+ 0,
+ 0,
+ 0,
+ 13241,
+ 0,
+ 13249,
+ 13253,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13255,
+ 13259,
+ 0,
+ 13260,
+ 13261,
+ 0,
+ 13262,
+ 0,
+ 13272,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13276,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13277,
+ 13299,
+ 0,
+ 0,
+ 13301,
+ 13302,
+ 0,
+ 0,
+ 13303,
+ 0,
+ 0,
+ 13305,
+ 0,
+ 13310,
+ 0,
+ 0,
+ 0,
+ 13311,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13325,
+ 0,
+ 13328,
+ 0,
+ 0,
+ 0,
+ 13329,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13330,
+ 0,
+ 0,
+ 13331,
+ 0,
+ 13335,
+ 0,
+ 0,
+ 13342,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13343,
+ 0,
+ 13354,
+ 0,
+ 13362,
+ 0,
+ 13366,
+ 13367,
+ 13369,
+ 0,
+ 0,
+ 13371,
+ 13372,
+ 0,
+ 13373,
+ 13374,
+ 0,
+ 13376,
+ 0,
+ 13380,
+ 13381,
+ 13386,
+ 0,
+ 13387,
+ 13388,
+ 0,
+ 13389,
+ 13391,
+ 13395,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13401,
+ 13409,
+ 0,
+ 13410,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13420,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13422,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13423,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13425,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13427,
+ 0,
+ 0,
+ 0,
+ 13428,
+ 0,
+ 0,
+ 13430,
+ 13438,
+ 0,
+ 13439,
+ 0,
+ 13445,
+ 0,
+ 13448,
+ 13449,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13451,
+ 0,
+ 13457,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13458,
+ 13459,
+ 0,
+ 13460,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13464,
+ 13465,
+ 13466,
+ 13470,
+ 0,
+ 13471,
+ 13472,
+ 13474,
+ 13475,
+ 0,
+ 13476,
+ 0,
+ 0,
+ 13478,
+ 13479,
+ 0,
+ 13481,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13487,
+ 0,
+ 13490,
+ 0,
+ 13493,
+ 0,
+ 0,
+ 13494,
+ 0,
+ 0,
+ 13495,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13496,
+ 13497,
+ 0,
+ 13500,
+ 0,
+ 0,
+ 13516,
+ 13522,
+ 0,
+ 0,
+ 13525,
+ 13528,
+ 0,
+ 0,
+ 0,
+ 13530,
+ 13535,
+ 0,
+ 13537,
+ 13539,
+ 0,
+ 13540,
+ 0,
+ 13543,
+ 0,
+ 13544,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13545,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13547,
+ 0,
+ 0,
+ 0,
+ 13549,
+ 13555,
+ 0,
+ 0,
+ 0,
+ 13556,
+ 13557,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13558,
+ 0,
+ 13563,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13564,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13566,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13569,
+ 0,
+ 0,
+ 13571,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13573,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13578,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13581,
+ 0,
+ 13586,
+ 0,
+ 13595,
+ 0,
+ 13600,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13601,
+ 13603,
+ 0,
+ 13604,
+ 13605,
+ 13606,
+ 13607,
+ 0,
+ 0,
+ 13617,
+ 13618,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13623,
+ 0,
+ 13625,
+ 13627,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13629,
+ 0,
+ 0,
+ 0,
+ 13634,
+ 0,
+ 0,
+ 0,
+ 13638,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13654,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13656,
+ 0,
+ 13659,
+ 0,
+ 0,
+ 13660,
+ 0,
+ 0,
+ 13662,
+ 0,
+ 0,
+ 0,
+ 13663,
+ 0,
+ 13664,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13668,
+ 0,
+ 13669,
+ 13671,
+ 0,
+ 0,
+ 13672,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13675,
+ 13685,
+ 0,
+ 13686,
+ 0,
+ 0,
+ 0,
+ 13687,
+ 0,
+ 0,
+ 0,
+ 13692,
+ 13694,
+ 13697,
+ 0,
+ 0,
+ 0,
+ 13702,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13705,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13707,
+ 0,
+ 0,
+ 0,
+ 13714,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13715,
+ 0,
+ 13716,
+ 13717,
+ 0,
+ 0,
+ 13719,
+ 13724,
+ 13730,
+ 13731,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13732,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13734,
+ 0,
+ 13736,
+ 0,
+ 0,
+ 13737,
+ 13738,
+ 13747,
+ 0,
+ 13751,
+ 0,
+ 0,
+ 13752,
+ 0,
+ 0,
+ 0,
+ 13753,
+ 0,
+ 13757,
+ 0,
+ 0,
+ 13762,
+ 13763,
+ 0,
+ 13764,
+ 13765,
+ 0,
+ 13766,
+ 0,
+ 0,
+ 13767,
+ 0,
+ 0,
+ 0,
+ 13768,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13769,
+ 0,
+ 0,
+ 13772,
+ 0,
+ 13775,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13776,
+ 13778,
+ 13787,
+ 0,
+ 0,
+ 0,
+ 13797,
+ 0,
+ 13798,
+ 0,
+ 13801,
+ 0,
+ 13804,
+ 13806,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13816,
+ 13817,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13834,
+ 0,
+ 13836,
+ 0,
+ 0,
+ 13838,
+ 0,
+ 0,
+ 13839,
+ 0,
+ 13840,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13842,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13843,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13845,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13858,
+ 0,
+ 0,
+ 13860,
+ 0,
+ 0,
+ 13861,
+ 0,
+ 0,
+ 13862,
+ 13863,
+ 0,
+ 13868,
+ 0,
+ 13869,
+ 13870,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13872,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13873,
+ 13878,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13886,
+ 0,
+ 13888,
+ 13889,
+ 13890,
+ 0,
+ 0,
+ 13891,
+ 13894,
+ 0,
+ 13897,
+ 13899,
+ 13900,
+ 13904,
+ 0,
+ 0,
+ 13906,
+ 0,
+ 0,
+ 0,
+ 13909,
+ 0,
+ 0,
+ 0,
+ 13910,
+ 0,
+ 0,
+ 0,
+ 13911,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13912,
+ 13917,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13918,
+ 0,
+ 13919,
+ 0,
+ 0,
+ 13920,
+ 0,
+ 0,
+ 0,
+ 13921,
+ 0,
+ 0,
+ 13922,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13924,
+ 0,
+ 13927,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13932,
+ 0,
+ 13933,
+ 0,
+ 13934,
+ 0,
+ 0,
+ 13935,
+ 0,
+ 13944,
+ 0,
+ 0,
+ 0,
+ 13954,
+ 0,
+ 0,
+ 13955,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13956,
+ 0,
+ 13957,
+ 0,
+ 13967,
+ 13969,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13970,
+ 13990,
+ 0,
+ 13991,
+ 13994,
+ 0,
+ 13995,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13996,
+ 0,
+ 0,
+ 13999,
+ 0,
+ 0,
+ 0,
+ 14018,
+ 0,
+ 14019,
+ 0,
+ 14021,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14041,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14043,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14046,
+ 0,
+ 0,
+ 0,
+ 14048,
+ 14049,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14051,
+ 0,
+ 0,
+ 14052,
+ 14056,
+ 0,
+ 14063,
+ 0,
+ 14064,
+ 14066,
+ 0,
+ 0,
+ 14067,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14068,
+ 0,
+ 0,
+ 0,
+ 14072,
+ 0,
+ 14074,
+ 14075,
+ 0,
+ 14076,
+ 14079,
+ 14085,
+ 14086,
+ 14087,
+ 14093,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14095,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14096,
+ 14097,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14098,
+ 0,
+ 14102,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14103,
+ 0,
+ 0,
+ 0,
+ 14104,
+ 0,
+ 0,
+ 14105,
+ 0,
+ 0,
+ 0,
+ 14107,
+ 14108,
+ 0,
+ 0,
+ 14109,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14117,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14118,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14119,
+ 0,
+ 0,
+ 14120,
+ 0,
+ 0,
+ 14121,
+ 0,
+ 14122,
+ 14127,
+ 0,
+ 14128,
+ 14136,
+ 0,
+ 0,
+ 14138,
+ 0,
+ 14140,
+ 0,
+ 0,
+ 0,
+ 14141,
+ 14142,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14146,
+ 0,
+ 0,
+ 14149,
+ 0,
+ 14151,
+ 0,
+ 0,
+ 0,
+ 14152,
+ 0,
+ 0,
+ 14153,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14154,
+ 0,
+ 14156,
+ 14157,
+ 0,
+ 0,
+ 14159,
+ 0,
+ 14161,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14162,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14163,
+ 0,
+ 0,
+ 14173,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14174,
+ 0,
+ 0,
+ 14176,
+ 0,
+ 0,
+ 14178,
+ 0,
+ 0,
+ 14179,
+ 14181,
+ 0,
+ 0,
+ 14182,
+ 14185,
+ 14187,
+ 0,
+ 14190,
+ 0,
+ 0,
+ 14197,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14198,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14199,
+ 14200,
+ 0,
+ 0,
+ 0,
+ 14204,
+ 0,
+ 0,
+ 14208,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14231,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14234,
+ 0,
+ 0,
+ 14235,
+ 0,
+ 0,
+ 0,
+ 14240,
+ 14241,
+ 0,
+ 0,
+ 0,
+ 14246,
+ 0,
+ 0,
+ 0,
+ 14247,
+ 0,
+ 14250,
+ 0,
+ 0,
+ 14251,
+ 0,
+ 0,
+ 14254,
+ 0,
+ 0,
+ 14256,
+ 0,
+ 0,
+ 0,
+ 14260,
+ 0,
+ 14261,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14262,
+ 14267,
+ 14269,
+ 0,
+ 0,
+ 14277,
+ 0,
+ 0,
+ 14278,
+ 0,
+ 14279,
+ 14282,
+ 0,
+ 0,
+ 0,
+ 14283,
+ 0,
+ 0,
+ 0,
+ 14284,
+ 14285,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14286,
+ 0,
+ 0,
+ 0,
+ 14288,
+ 0,
+ 0,
+ 0,
+ 14289,
+ 0,
+ 14290,
+ 0,
+ 14293,
+ 14301,
+ 14302,
+ 14304,
+ 14305,
+ 0,
+ 14307,
+ 0,
+ 14308,
+ 14309,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14311,
+ 14312,
+ 0,
+ 0,
+ 14317,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14318,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14320,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14321,
+ 14322,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14326,
+ 14329,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14330,
+ 14331,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14332,
+ 0,
+ 0,
+ 0,
+ 14333,
+ 0,
+ 0,
+ 14337,
+ 14340,
+ 0,
+ 14341,
+ 0,
+ 0,
+ 14342,
+ 0,
+ 14345,
+ 14346,
+ 0,
+ 0,
+ 14347,
+ 0,
+ 14362,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14364,
+ 14365,
+ 14371,
+ 0,
+ 14373,
+ 0,
+ 0,
+ 14374,
+ 0,
+ 14379,
+ 0,
+ 14400,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14401,
+ 0,
+ 0,
+ 14405,
+ 0,
+ 14406,
+ 0,
+ 14408,
+ 14409,
+ 0,
+ 0,
+ 0,
+ 14417,
+ 0,
+ 0,
+ 14424,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14430,
+ 0,
+ 0,
+ 0,
+ 14431,
+ 0,
+ 0,
+ 14435,
+ 0,
+ 14440,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14442,
+ 0,
+ 0,
+ 14443,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14446,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14454,
+ 0,
+ 14457,
+ 0,
+ 14460,
+ 0,
+ 0,
+ 14466,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14467,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14469,
+ 0,
+ 14477,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14478,
+ 14482,
+ 0,
+ 0,
+ 0,
+ 14483,
+ 0,
+ 0,
+ 0,
+ 14485,
+ 14486,
+ 0,
+ 0,
+ 0,
+ 14487,
+ 14488,
+ 14489,
+ 14492,
+ 14493,
+ 14494,
+ 14495,
+ 14496,
+ 14497,
+ 0,
+ 14499,
+ 0,
+ 14501,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14502,
+ 0,
+ 14507,
+ 14512,
+ 14513,
+ 14514,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14515,
+ 14526,
+ 14530,
+ 0,
+ 14537,
+ 0,
+ 14544,
+ 0,
+ 14547,
+ 0,
+ 0,
+ 14548,
+ 14550,
+ 14551,
+ 0,
+ 0,
+ 14552,
+ 0,
+ 0,
+ 0,
+ 14553,
+ 0,
+ 14554,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14556,
+ 14564,
+ 0,
+ 0,
+ 14565,
+ 14566,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14568,
+ 0,
+ 0,
+ 14569,
+ 0,
+ 0,
+ 0,
+ 14571,
+ 14576,
+ 0,
+ 0,
+ 14577,
+ 14578,
+ 14579,
+ 0,
+ 0,
+ 14580,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14582,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14583,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14587,
+ 0,
+ 14588,
+ 0,
+ 0,
+ 14600,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14601,
+ 0,
+ 0,
+ 14604,
+ 14605,
+ 14611,
+ 0,
+ 14613,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14615,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14627,
+ 0,
+ 14628,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14631,
+ 0,
+ 14633,
+ 14634,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14635,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14636,
+ 0,
+ 0,
+ 14639,
+ 14642,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14644,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14645,
+ 14646,
+ 0,
+ 14653,
+ 0,
+ 0,
+ 14654,
+ 0,
+ 14658,
+ 0,
+ 14661,
+ 0,
+ 0,
+ 0,
+ 14665,
+ 0,
+ 0,
+ 0,
+ 14668,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14669,
+ 0,
+ 0,
+ 14670,
+ 0,
+ 0,
+ 0,
+ 14680,
+ 0,
+ 0,
+ 14681,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14682,
+ 14683,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14686,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14687,
+ 14697,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14699,
+ 14705,
+ 14711,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14712,
+ 0,
+ 0,
+ 0,
+ 14713,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14719,
+ 0,
+ 14720,
+ 14721,
+ 14726,
+ 0,
+ 0,
+ 0,
+ 14728,
+ 14729,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14731,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14733,
+ 14736,
+ 14737,
+ 0,
+ 0,
+ 14740,
+ 14742,
+ 0,
+ 0,
+ 0,
+ 14744,
+ 14753,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14755,
+ 14758,
+ 14760,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14761,
+ 14762,
+ 14765,
+ 14771,
+ 0,
+ 14772,
+ 0,
+ 14773,
+ 14774,
+ 0,
+ 0,
+ 14775,
+ 0,
+ 0,
+ 14776,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14777,
+ 0,
+ 14779,
+ 0,
+ 0,
+ 14782,
+ 0,
+ 0,
+ 14785,
+ 14786,
+ 14788,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14795,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14798,
+ 0,
+ 14803,
+ 14804,
+ 14806,
+ 0,
+ 0,
+ 0,
+ 14809,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14810,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14811,
+ 0,
+ 14812,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14815,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14816,
+ 0,
+ 14818,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14819,
+ 0,
+ 14820,
+ 0,
+ 14823,
+ 0,
+ 0,
+ 0,
+ 14824,
+ 0,
+ 0,
+ 14826,
+ 14827,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14830,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14833,
+ 0,
+ 14845,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14846,
+ 0,
+ 0,
+ 14847,
+ 14871,
+ 0,
+ 14873,
+ 0,
+ 14876,
+ 0,
+ 14877,
+ 14878,
+ 14880,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14881,
+ 0,
+ 14882,
+ 14894,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14895,
+ 0,
+ 14907,
+ 0,
+ 14908,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14911,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14920,
+ 0,
+ 0,
+ 14931,
+ 0,
+ 14932,
+ 14934,
+ 14935,
+ 0,
+ 0,
+ 14936,
+ 0,
+ 14945,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14947,
+ 0,
+ 0,
+ 14948,
+ 14949,
+ 14951,
+ 0,
+ 0,
+ 14952,
+ 0,
+ 0,
+ 0,
+ 14964,
+ 14973,
+ 0,
+ 0,
+ 14990,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14995,
+ 0,
+ 0,
+ 14998,
+ 15001,
+ 0,
+ 0,
+ 15002,
+ 15020,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15021,
+ 0,
+ 15022,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15023,
+ 0,
+ 0,
+ 15025,
+ 15029,
+ 15033,
+ 0,
+ 0,
+ 0,
+ 15034,
+ 0,
+ 0,
+ 0,
+ 15035,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15043,
+ 15044,
+ 0,
+ 0,
+ 0,
+ 15045,
+ 15046,
+ 15048,
+ 15050,
+ 0,
+ 15065,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15066,
+ 0,
+ 0,
+ 15075,
+ 15082,
+ 15084,
+ 0,
+ 0,
+ 15085,
+ 15086,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15088,
+ 0,
+ 0,
+ 0,
+ 15089,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15094,
+ 0,
+ 15096,
+ 0,
+ 15097,
+ 0,
+ 15100,
+ 0,
+ 0,
+ 15102,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15105,
+ 0,
+ 0,
+ 15106,
+ 0,
+ 15109,
+ 15113,
+ 0,
+ 0,
+ 0,
+ 15115,
+ 0,
+ 15118,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15119,
+ 0,
+ 0,
+ 15120,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15123,
+ 15129,
+ 0,
+ 0,
+ 0,
+ 15130,
+ 0,
+ 15131,
+ 0,
+ 0,
+ 15134,
+ 0,
+ 15135,
+ 0,
+ 0,
+ 0,
+ 15137,
+ 15138,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15139,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15140,
+ 0,
+ 0,
+ 15154,
+ 15162,
+ 0,
+ 15169,
+ 15170,
+ 0,
+ 15175,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15177,
+ 0,
+ 15178,
+ 15179,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15183,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15185,
+ 15187,
+ 0,
+ 15194,
+ 15195,
+ 15196,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15204,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15206,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15207,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15213,
+ 0,
+ 15214,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15232,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15234,
+ 0,
+ 15238,
+ 15240,
+ 0,
+ 15248,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15250,
+ 15251,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15252,
+ 0,
+ 0,
+ 0,
+ 15255,
+ 15262,
+ 15266,
+ 0,
+ 0,
+ 0,
+ 15267,
+ 0,
+ 0,
+ 0,
+ 15277,
+ 15279,
+ 0,
+ 0,
+ 0,
+ 15280,
+ 15281,
+ 15282,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15285,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15289,
+ 0,
+ 0,
+ 15291,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15296,
+ 15297,
+ 0,
+ 0,
+ 15304,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15306,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15307,
+ 15308,
+ 0,
+ 15309,
+ 0,
+ 0,
+ 15311,
+ 0,
+ 0,
+ 15312,
+ 15313,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15314,
+ 15317,
+ 0,
+ 0,
+ 0,
+ 15318,
+ 15319,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15320,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15321,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15324,
+ 0,
+ 15325,
+ 15326,
+ 0,
+ 15330,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15334,
+ 0,
+ 15335,
+ 0,
+ 15341,
+ 0,
+ 0,
+ 15342,
+ 0,
+ 0,
+ 15343,
+ 15344,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15345,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15347,
+ 0,
+ 0,
+ 15348,
+ 15349,
+ 15350,
+ 0,
+ 15356,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15357,
+ 0,
+ 15358,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15359,
+ 15360,
+ 15364,
+ 0,
+ 15380,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15392,
+ 0,
+ 0,
+ 15393,
+ 0,
+ 15395,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15396,
+ 0,
+ 0,
+ 15397,
+ 15398,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15399,
+ 0,
+ 15400,
+ 0,
+ 0,
+ 0,
+ 15402,
+ 0,
+ 15405,
+ 15410,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15411,
+ 0,
+ 0,
+ 0,
+ 15412,
+ 0,
+ 15416,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15428,
+ 0,
+ 15435,
+ 0,
+ 0,
+ 15438,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15439,
+ 0,
+ 0,
+ 0,
+ 15440,
+ 0,
+ 0,
+ 0,
+ 15441,
+ 15449,
+ 15451,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15452,
+ 0,
+ 0,
+ 15455,
+ 0,
+ 0,
+ 0,
+ 15456,
+ 0,
+ 0,
+ 15458,
+ 0,
+ 15460,
+ 15461,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15462,
+ 15464,
+ 0,
+ 15465,
+ 0,
+ 0,
+ 15466,
+ 0,
+ 0,
+ 15467,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15468,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15481,
+ 0,
+ 0,
+ 15484,
+ 0,
+ 15485,
+ 15486,
+ 0,
+ 0,
+ 0,
+ 15487,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15488,
+ 0,
+ 15492,
+ 15498,
+ 0,
+ 0,
+ 0,
+ 15499,
+ 0,
+ 0,
+ 0,
+ 15500,
+ 0,
+ 15501,
+ 0,
+ 0,
+ 15512,
+ 0,
+ 15522,
+ 0,
+ 0,
+ 0,
+ 15524,
+ 0,
+ 15525,
+ 15526,
+ 0,
+ 0,
+ 15527,
+ 0,
+ 0,
+ 15545,
+ 15546,
+ 0,
+ 15548,
+ 15552,
+ 0,
+ 15553,
+ 0,
+ 0,
+ 0,
+ 15554,
+ 0,
+ 15555,
+ 0,
+ 15557,
+ 15565,
+ 15573,
+ 15577,
+ 15578,
+ 0,
+ 15582,
+ 0,
+ 15583,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15586,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15588,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15589,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15593,
+ 15594,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15595,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15596,
+ 0,
+ 0,
+ 0,
+ 15597,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15600,
+ 0,
+ 0,
+ 15601,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15602,
+ 15603,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15604,
+ 0,
+ 15609,
+ 0,
+ 0,
+ 15612,
+ 0,
+ 0,
+ 15613,
+ 0,
+ 0,
+ 15615,
+ 15617,
+ 15618,
+ 0,
+ 0,
+ 15620,
+ 0,
+ 15636,
+ 15637,
+ 0,
+ 0,
+ 15649,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15650,
+ 0,
+ 0,
+ 15651,
+ 0,
+ 0,
+ 0,
+ 15656,
+ 0,
+ 15658,
+ 0,
+ 0,
+ 0,
+ 15664,
+ 0,
+ 0,
+ 15665,
+ 0,
+ 0,
+ 15668,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15669,
+ 0,
+ 0,
+ 15674,
+ 0,
+ 0,
+ 15675,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15676,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15677,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15678,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15679,
+ 0,
+ 0,
+ 15681,
+ 0,
+ 15686,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15687,
+ 0,
+ 15688,
+ 0,
+ 0,
+ 15690,
+ 0,
+ 0,
+ 0,
+ 15697,
+ 0,
+ 15699,
+ 15700,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15701,
+ 0,
+ 15702,
+ 15703,
+ 0,
+ 15704,
+ 0,
+ 15705,
+ 0,
+ 15707,
+ 0,
+ 15709,
+ 0,
+ 15712,
+ 15716,
+ 0,
+ 15717,
+ 0,
+ 15718,
+ 15720,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15724,
+ 0,
+ 0,
+ 0,
+ 15725,
+ 0,
+ 15726,
+ 0,
+ 0,
+ 0,
+ 15740,
+ 0,
+ 15745,
+ 15746,
+ 0,
+ 0,
+ 15747,
+ 0,
+ 15748,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15749,
+ 0,
+ 0,
+ 0,
+ 15752,
+ 0,
+ 15753,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15759,
+ 0,
+ 0,
+ 0,
+ 15765,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15767,
+ 0,
+ 0,
+ 0,
+ 15771,
+ 0,
+ 0,
+ 15784,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15785,
+ 15790,
+ 15791,
+ 0,
+ 0,
+ 15792,
+ 0,
+ 0,
+ 0,
+ 15807,
+ 0,
+ 15811,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15818,
+ 0,
+ 0,
+ 0,
+ 15819,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15821,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15822,
+ 15824,
+ 0,
+ 0,
+ 15827,
+ 0,
+ 0,
+ 15829,
+ 15831,
+ 0,
+ 15832,
+ 0,
+ 0,
+ 15833,
+ 0,
+ 15835,
+ 15838,
+ 15839,
+ 15843,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15844,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15845,
+ 15851,
+ 15856,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15858,
+ 15860,
+ 0,
+ 15861,
+ 0,
+ 0,
+ 0,
+ 15864,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15865,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15866,
+ 0,
+ 15872,
+ 0,
+ 0,
+ 15876,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15877,
+ 15878,
+ 15883,
+ 15885,
+ 0,
+ 0,
+ 15888,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15889,
+ 15890,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15892,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15893,
+ 0,
+ 0,
+ 15894,
+ 0,
+ 0,
+ 0,
+ 15895,
+ 0,
+ 15896,
+ 15897,
+ 0,
+ 15898,
+ 15901,
+ 15902,
+ 0,
+ 15911,
+ 15915,
+ 0,
+ 15916,
+ 0,
+ 15924,
+ 15935,
+ 0,
+ 15937,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15950,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15958,
+ 0,
+ 0,
+ 0,
+ 15961,
+ 0,
+ 0,
+ 15966,
+ 0,
+ 15967,
+ 0,
+ 0,
+ 15977,
+ 0,
+ 0,
+ 15978,
+ 0,
+ 0,
+ 15981,
+ 15982,
+ 15983,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15986,
+ 0,
+ 0,
+ 0,
+ 15990,
+ 0,
+ 15991,
+ 15995,
+ 15998,
+ 0,
+ 15999,
+ 0,
+ 16000,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16008,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16009,
+ 16011,
+ 0,
+ 16013,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16014,
+ 0,
+ 0,
+ 16015,
+ 16023,
+ 16024,
+ 16025,
+ 0,
+ 0,
+ 16026,
+ 0,
+ 16030,
+ 0,
+ 16032,
+ 0,
+ 16033,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16035,
+ 16036,
+ 16037,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16039,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16041,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16043,
+ 16044,
+ 0,
+ 0,
+ 16047,
+ 0,
+ 0,
+ 0,
+ 16048,
+ 0,
+ 0,
+ 16049,
+ 16050,
+ 16052,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16055,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16056,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16058,
+ 16060,
+ 16061,
+ 0,
+ 0,
+ 16063,
+ 0,
+ 0,
+ 16064,
+ 0,
+ 0,
+ 0,
+ 16067,
+ 16068,
+ 0,
+ 0,
+ 16069,
+ 16078,
+ 0,
+ 0,
+ 0,
+ 16079,
+ 0,
+ 0,
+ 0,
+ 16080,
+ 0,
+ 16081,
+ 0,
+ 0,
+ 0,
+ 16088,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16089,
+ 16093,
+ 0,
+ 16097,
+ 0,
+ 16103,
+ 0,
+ 16104,
+ 16105,
+ 0,
+ 0,
+ 16256,
+ 0,
+ 0,
+ 16259,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16260,
+ 16261,
+ 0,
+ 0,
+ 16262,
+ 0,
+ 0,
+ 16263,
+ 0,
+ 16268,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16269,
+ 0,
+ 0,
+ 16270,
+ 16273,
+ 0,
+ 16274,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16275,
+ 16276,
+ 16277,
+ 16280,
+ 0,
+ 0,
+ 0,
+ 16281,
+ 16284,
+ 0,
+ 0,
+ 0,
+ 16286,
+ 0,
+ 16289,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16290,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16291,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16292,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16293,
+ 16295,
+ 16297,
+ 0,
+ 16302,
+ 0,
+ 16304,
+ 0,
+ 16305,
+ 0,
+ 16306,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16307,
+ 16308,
+ 16312,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16313,
+ 16315,
+ 0,
+ 16318,
+ 0,
+ 0,
+ 0,
+ 16321,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16326,
+ 16333,
+ 16336,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16337,
+ 16340,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16345,
+ 0,
+ 0,
+ 16346,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16347,
+ 0,
+ 0,
+ 16348,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16349,
+ 0,
+ 0,
+ 0,
+ 16350,
+ 0,
+ 16357,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16359,
+ 16360,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16362,
+ 16363,
+ 16364,
+ 16365,
+ 0,
+ 0,
+ 16366,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16367,
+ 16368,
+ 0,
+ 16369,
+ 16374,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16376,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16378,
+ 16379,
+ 0,
+ 16380,
+ 0,
+ 0,
+ 0,
+ 16381,
+ 16383,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16390,
+ 0,
+ 0,
+ 0,
+ 16399,
+ 0,
+ 16402,
+ 16404,
+ 16406,
+ 16407,
+ 0,
+ 0,
+ 0,
+ 16409,
+ 16411,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16412,
+ 0,
+ 16413,
+ 16415,
+ 16423,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16424,
+ 0,
+ 0,
+ 0,
+ 16428,
+ 16434,
+ 16435,
+ 16449,
+ 0,
+ 16450,
+ 16451,
+ 0,
+ 0,
+ 0,
+ 16453,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16454,
+ 0,
+ 0,
+ 16456,
+ 16458,
+ 0,
+ 0,
+ 16459,
+ 0,
+ 0,
+ 16460,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16462,
+ 0,
+ 16463,
+ 0,
+ 0,
+ 16466,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16479,
+ 0,
+ 0,
+ 16480,
+ 0,
+ 16481,
+ 16484,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16485,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16489,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16491,
+ 0,
+ 0,
+ 16498,
+ 0,
+ 0,
+ 16503,
+ 0,
+ 16505,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16506,
+ 0,
+ 0,
+ 0,
+ 16508,
+ 16509,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16511,
+ 16513,
+ 0,
+ 0,
+ 0,
+ 16516,
+ 0,
+ 16517,
+ 0,
+ 16519,
+ 0,
+ 16529,
+ 0,
+ 0,
+ 16531,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16534,
+ 0,
+ 0,
+ 16541,
+ 16542,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16543,
+ 16547,
+ 16548,
+ 0,
+ 0,
+ 0,
+ 16551,
+ 0,
+ 16552,
+ 0,
+ 0,
+ 0,
+ 16553,
+ 0,
+ 0,
+ 16558,
+ 0,
+ 0,
+ 16562,
+ 16565,
+ 0,
+ 0,
+ 0,
+ 16570,
+ 0,
+ 0,
+ 0,
+ 16573,
+ 16585,
+ 0,
+ 0,
+ 0,
+ 16586,
+ 16587,
+ 16595,
+ 0,
+ 16596,
+ 0,
+ 16598,
+ 0,
+ 0,
+ 0,
+ 16600,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16601,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16603,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16604,
+ 16612,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16613,
+ 0,
+ 16618,
+ 0,
+ 0,
+ 0,
+ 16640,
+ 0,
+ 0,
+ 16641,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16645,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16646,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16651,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16653,
+ 16654,
+ 0,
+ 0,
+ 0,
+ 16655,
+ 0,
+ 0,
+ 16656,
+ 16667,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16671,
+ 0,
+ 16672,
+ 0,
+ 0,
+ 0,
+ 16673,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16676,
+ 0,
+ 16686,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16689,
+ 0,
+ 16690,
+ 0,
+ 16692,
+ 0,
+ 16693,
+ 0,
+ 16694,
+ 0,
+ 16696,
+ 0,
+ 0,
+ 0,
+ 16705,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16707,
+ 0,
+ 0,
+ 0,
+ 16709,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16711,
+ 0,
+ 16712,
+ 16713,
+ 0,
+ 0,
+ 0,
+ 16715,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16716,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16718,
+ 16724,
+ 0,
+ 0,
+ 16726,
+ 16727,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16728,
+ 0,
+ 16729,
+ 0,
+ 0,
+ 16730,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16731,
+ 0,
+ 0,
+ 0,
+ 16732,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16734,
+ 16738,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16743,
+ 0,
+ 0,
+ 16745,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16749,
+ 0,
+ 16752,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16756,
+ 0,
+ 0,
+ 16758,
+ 0,
+ 16759,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16760,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16762,
+ 0,
+ 16769,
+ 0,
+ 16770,
+ 0,
+ 16772,
+ 0,
+ 0,
+ 0,
+ 16777,
+ 16780,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16781,
+ 0,
+ 0,
+ 16782,
+ 0,
+ 16784,
+ 0,
+ 0,
+ 16785,
+ 16787,
+ 16792,
+ 0,
+ 0,
+ 16794,
+ 0,
+ 0,
+ 0,
+ 16798,
+ 0,
+ 0,
+ 16809,
+ 0,
+ 0,
+ 16814,
+ 16816,
+ 16817,
+ 0,
+ 16819,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16820,
+ 0,
+ 0,
+ 16836,
+ 16839,
+ 0,
+ 0,
+ 16841,
+ 16851,
+ 16857,
+ 0,
+ 0,
+ 16858,
+ 16859,
+ 0,
+ 0,
+ 16860,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16862,
+ 0,
+ 16863,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16864,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16876,
+ 0,
+ 16881,
+ 16882,
+ 0,
+ 16885,
+ 16886,
+ 0,
+ 16887,
+ 0,
+ 0,
+ 0,
+ 16889,
+ 16891,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16894,
+ 16895,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16897,
+ 0,
+ 16898,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16913,
+ 0,
+ 0,
+ 16924,
+ 16925,
+ 16926,
+ 0,
+ 0,
+ 16927,
+ 0,
+ 0,
+ 0,
+ 16937,
+ 16938,
+ 0,
+ 0,
+ 0,
+ 16940,
+ 16941,
+ 0,
+ 0,
+ 0,
+ 16942,
+ 16945,
+ 0,
+ 16946,
+ 16949,
+ 16950,
+ 0,
+ 0,
+ 0,
+ 16952,
+ 16955,
+ 0,
+ 0,
+ 0,
+ 16965,
+ 0,
+ 16969,
+ 0,
+ 0,
+ 16975,
+ 0,
+ 0,
+ 16976,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16978,
+ 0,
+ 0,
+ 16981,
+ 0,
+ 16983,
+ 16989,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16990,
+ 0,
+ 0,
+ 16991,
+ 0,
+ 0,
+ 0,
+ 16993,
+ 0,
+ 16994,
+ 16996,
+ 17000,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17002,
+ 17004,
+ 0,
+ 17006,
+ 0,
+ 0,
+ 17007,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17008,
+ 17013,
+ 17014,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17021,
+ 0,
+ 17031,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17033,
+ 17036,
+ 0,
+ 17038,
+ 0,
+ 0,
+ 17039,
+ 0,
+ 17045,
+ 0,
+ 0,
+ 17046,
+ 17047,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17048,
+ 0,
+ 17049,
+ 17050,
+ 0,
+ 17051,
+ 17053,
+ 0,
+ 17054,
+ 0,
+ 17055,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17063,
+ 0,
+ 0,
+ 17064,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17065,
+ 0,
+ 0,
+ 17068,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17072,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17073,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17074,
+ 0,
+ 17080,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17081,
+ 17083,
+ 17084,
+ 0,
+ 0,
+ 0,
+ 17085,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17092,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17093,
+ 0,
+ 17095,
+ 17102,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17103,
+ 0,
+ 0,
+ 17105,
+ 0,
+ 17107,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17114,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17115,
+ 17125,
+ 17127,
+ 0,
+ 0,
+ 17128,
+ 0,
+ 0,
+ 0,
+ 17129,
+ 17130,
+ 0,
+ 17131,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17132,
+ 17135,
+ 17145,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17146,
+ 0,
+ 17147,
+ 0,
+ 17148,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17149,
+ 17150,
+ 0,
+ 17151,
+ 17153,
+ 0,
+ 17155,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17163,
+ 17171,
+ 0,
+ 17174,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17179,
+ 0,
+ 0,
+ 17182,
+ 17185,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17186,
+ 0,
+ 0,
+ 17188,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17189,
+ 17191,
+ 0,
+ 17194,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17195,
+ 17196,
+ 17203,
+ 17204,
+ 0,
+ 0,
+ 17205,
+ 17217,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17218,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17219,
+ 0,
+ 17220,
+ 0,
+ 17221,
+ 0,
+ 0,
+ 17230,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17236,
+ 0,
+ 17238,
+ 17239,
+ 0,
+ 0,
+ 0,
+ 17241,
+ 17244,
+ 0,
+ 0,
+ 17245,
+ 0,
+ 17248,
+ 0,
+ 0,
+ 17251,
+ 0,
+ 17252,
+ 0,
+ 0,
+ 17264,
+ 0,
+ 17266,
+ 0,
+ 0,
+ 0,
+ 17268,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17271,
+ 17272,
+ 0,
+ 17273,
+ 0,
+ 17295,
+ 0,
+ 17302,
+ 0,
+ 17305,
+ 0,
+ 0,
+ 0,
+ 17306,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17308,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17309,
+ 0,
+ 17310,
+ 17313,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17314,
+ 17315,
+ 0,
+ 17317,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17318,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17320,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17334,
+ 0,
+ 17344,
+ 17348,
+ 0,
+ 0,
+ 0,
+ 17350,
+ 17351,
+ 0,
+ 0,
+ 17353,
+ 0,
+ 0,
+ 17354,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17355,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17356,
+ 17357,
+ 0,
+ 0,
+ 17359,
+ 0,
+ 0,
+ 0,
+ 17371,
+ 0,
+ 17372,
+ 0,
+ 0,
+ 0,
+ 17393,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17394,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17395,
+ 0,
+ 0,
+ 17399,
+ 0,
+ 0,
+ 0,
+ 17401,
+ 17417,
+ 0,
+ 17418,
+ 0,
+ 17419,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17422,
+ 17423,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17424,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17428,
+ 17429,
+ 17433,
+ 0,
+ 0,
+ 0,
+ 17437,
+ 0,
+ 0,
+ 17441,
+ 0,
+ 0,
+ 17442,
+ 0,
+ 0,
+ 17453,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17454,
+ 17456,
+ 17462,
+ 0,
+ 0,
+ 17466,
+ 0,
+ 0,
+ 17468,
+ 0,
+ 0,
+ 17469,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17470,
+ 0,
+ 17475,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17479,
+ 0,
+ 0,
+ 0,
+ 17483,
+ 17484,
+ 0,
+ 17485,
+ 0,
+ 17486,
+ 0,
+ 17491,
+ 17492,
+ 0,
+ 0,
+ 17493,
+ 0,
+ 17494,
+ 17495,
+ 0,
+ 0,
+ 0,
+ 17496,
+ 0,
+ 0,
+ 0,
+ 17497,
+ 0,
+ 0,
+ 0,
+ 17502,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17503,
+ 0,
+ 17505,
+ 0,
+ 17507,
+ 0,
+ 0,
+ 0,
+ 17512,
+ 17513,
+ 17514,
+ 0,
+ 0,
+ 17515,
+ 0,
+ 0,
+ 0,
+ 17519,
+ 0,
+ 0,
+ 0,
+ 17522,
+ 0,
+ 0,
+ 17523,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17527,
+ 0,
+ 0,
+ 0,
+ 17528,
+ 0,
+ 0,
+ 0,
+ 17534,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17536,
+ 0,
+ 0,
+ 0,
+ 17539,
+ 0,
+ 17540,
+ 17543,
+ 17549,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17556,
+ 0,
+ 0,
+ 17558,
+ 0,
+ 17559,
+ 0,
+ 0,
+ 17560,
+ 0,
+ 0,
+ 0,
+ 17563,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17564,
+ 0,
+ 0,
+ 17565,
+ 17566,
+ 0,
+ 17567,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17569,
+ 17570,
+ 0,
+ 17575,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17581,
+ 0,
+ 0,
+ 0,
+ 17582,
+ 17583,
+ 0,
+ 17586,
+ 0,
+ 0,
+ 17587,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17588,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17596,
+ 17597,
+ 0,
+ 0,
+ 17598,
+ 17600,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17601,
+ 0,
+ 0,
+ 0,
+ 17604,
+ 0,
+ 0,
+ 17605,
+ 0,
+ 0,
+ 17607,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17612,
+ 0,
+ 0,
+ 17618,
+ 0,
+ 17621,
+ 17622,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17623,
+ 0,
+ 0,
+ 17624,
+ 0,
+ 0,
+ 17630,
+ 0,
+ 0,
+ 17631,
+ 17633,
+ 17634,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17635,
+ 0,
+ 0,
+ 17636,
+ 0,
+ 0,
+ 17637,
+ 0,
+ 17638,
+ 0,
+ 17640,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17641,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17643,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17645,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17646,
+ 17662,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17663,
+ 17664,
+ 0,
+ 17665,
+ 17666,
+ 0,
+ 0,
+ 0,
+ 17669,
+ 17671,
+ 17673,
+ 0,
+ 17679,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17684,
+ 0,
+ 0,
+ 0,
+ 17686,
+ 0,
+ 17714,
+ 0,
+ 0,
+ 17720,
+ 17722,
+ 17726,
+ 0,
+ 0,
+ 17728,
+ 0,
+ 0,
+ 17729,
+ 0,
+ 0,
+ 0,
+ 17732,
+ 0,
+ 17733,
+ 0,
+ 17734,
+ 0,
+ 0,
+ 0,
+ 17735,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17737,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17739,
+ 0,
+ 0,
+ 0,
+ 17741,
+ 17742,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17743,
+ 17744,
+ 17745,
+ 0,
+ 0,
+ 0,
+ 17749,
+ 0,
+ 17750,
+ 17751,
+ 17752,
+ 17754,
+ 17761,
+ 17762,
+ 0,
+ 17763,
+ 0,
+ 17766,
+ 0,
+ 17772,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17775,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17776,
+ 0,
+ 0,
+ 17777,
+ 0,
+ 0,
+ 17778,
+ 17779,
+ 0,
+ 17782,
+ 17783,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17784,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17821,
+ 0,
+ 0,
+ 0,
+ 17822,
+ 0,
+ 0,
+ 0,
+ 17823,
+ 17825,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17826,
+ 17831,
+ 17832,
+ 17833,
+ 0,
+ 0,
+ 17845,
+ 0,
+ 0,
+ 0,
+ 17846,
+ 0,
+ 0,
+ 0,
+ 17848,
+ 17850,
+ 17854,
+ 0,
+ 17855,
+ 0,
+ 0,
+ 17859,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17860,
+ 17861,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17870,
+ 17871,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17872,
+ 0,
+ 0,
+ 0,
+ 17879,
+ 0,
+ 0,
+ 0,
+ 17881,
+ 17883,
+ 0,
+ 17884,
+ 0,
+ 17885,
+ 0,
+ 0,
+ 17886,
+ 0,
+ 0,
+ 17887,
+ 17891,
+ 17953,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17954,
+ 0,
+ 0,
+ 17955,
+ 0,
+ 17968,
+ 0,
+ 0,
+ 17972,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17974,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17976,
+ 17978,
+ 0,
+ 0,
+ 17983,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18003,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18007,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18009,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18010,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18012,
+ 0,
+ 0,
+ 18014,
+ 0,
+ 0,
+ 0,
+ 18015,
+ 0,
+ 0,
+ 0,
+ 18016,
+ 0,
+ 18017,
+ 0,
+ 0,
+ 0,
+ 18030,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18031,
+ 0,
+ 0,
+ 18036,
+ 18037,
+ 18038,
+ 0,
+ 0,
+ 18049,
+ 18056,
+ 0,
+ 18057,
+ 18058,
+ 0,
+ 18059,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18062,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18064,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18067,
+ 0,
+ 0,
+ 0,
+ 18068,
+ 0,
+ 0,
+ 18075,
+ 0,
+ 0,
+ 18078,
+ 18093,
+ 18094,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18097,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18098,
+ 18100,
+ 0,
+ 0,
+ 0,
+ 18108,
+ 0,
+ 18111,
+ 0,
+ 0,
+ 18112,
+ 0,
+ 18113,
+ 0,
+ 0,
+ 18115,
+ 18116,
+ 0,
+ 18118,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18121,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18123,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18124,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18125,
+ 18126,
+ 0,
+ 18127,
+ 0,
+ 0,
+ 18128,
+ 18135,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18150,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18151,
+ 18152,
+ 0,
+ 0,
+ 18156,
+ 18164,
+ 0,
+ 18166,
+ 18171,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18172,
+ 18183,
+ 0,
+ 18184,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18185,
+ 0,
+ 18187,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18188,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18189,
+ 0,
+ 0,
+ 18190,
+ 0,
+ 0,
+ 18191,
+ 18192,
+ 0,
+ 0,
+ 18194,
+ 18195,
+ 18196,
+ 0,
+ 0,
+ 0,
+ 18197,
+ 0,
+ 18203,
+ 0,
+ 18204,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18205,
+ 0,
+ 0,
+ 0,
+ 18207,
+ 18208,
+ 0,
+ 0,
+ 18214,
+ 0,
+ 0,
+ 0,
+ 18215,
+ 18216,
+ 0,
+ 0,
+ 0,
+ 18220,
+ 0,
+ 0,
+ 18222,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18223,
+ 0,
+ 18225,
+ 18231,
+ 0,
+ 18234,
+ 0,
+ 18235,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18240,
+ 0,
+ 0,
+ 18241,
+ 18242,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18243,
+ 18251,
+ 0,
+ 18253,
+ 0,
+ 18254,
+ 0,
+ 0,
+ 0,
+ 18266,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18269,
+ 18270,
+ 18271,
+ 18273,
+ 18281,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18282,
+ 0,
+ 18283,
+ 0,
+ 18284,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18285,
+ 0,
+ 18287,
+ 18289,
+ 0,
+ 0,
+ 18290,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18308,
+ 0,
+ 0,
+ 0,
+ 18310,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18311,
+ 0,
+ 18312,
+ 18313,
+ 0,
+ 18315,
+ 0,
+ 0,
+ 18316,
+ 18320,
+ 0,
+ 18331,
+ 0,
+ 18332,
+ 0,
+ 18336,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18337,
+ 0,
+ 18340,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18341,
+ 0,
+ 18344,
+ 18345,
+ 0,
+ 18346,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18348,
+ 0,
+ 18351,
+ 0,
+ 0,
+ 18356,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18357,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18367,
+ 0,
+ 0,
+ 0,
+ 18368,
+ 0,
+ 18369,
+ 0,
+ 18370,
+ 18371,
+ 0,
+ 0,
+ 0,
+ 18437,
+ 18444,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18445,
+ 18450,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18451,
+ 0,
+ 18452,
+ 0,
+ 0,
+ 0,
+ 18453,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18455,
+ 0,
+ 0,
+ 0,
+ 18456,
+ 0,
+ 18457,
+ 0,
+ 18460,
+ 0,
+ 0,
+ 18461,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18466,
+ 0,
+ 0,
+ 18467,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18473,
+ 0,
+ 0,
+ 0,
+ 18476,
+ 0,
+ 18477,
+ 0,
+ 0,
+ 0,
+ 18478,
+ 18479,
+ 18480,
+ 0,
+ 0,
+ 0,
+ 18485,
+ 0,
+ 0,
+ 0,
+ 18486,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18488,
+ 18490,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18491,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18495,
+ 0,
+ 0,
+ 18496,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18505,
+ 0,
+ 18521,
+ 0,
+ 18522,
+ 18523,
+ 0,
+ 0,
+ 0,
+ 18525,
+ 18526,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18527,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18532,
+ 18533,
+ 0,
+ 18534,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18535,
+ 18537,
+ 0,
+ 18538,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18540,
+ 18541,
+ 18542,
+ 18543,
+ 0,
+ 18546,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18553,
+ 18556,
+ 0,
+ 0,
+ 18558,
+ 0,
+ 0,
+ 18569,
+ 18571,
+ 0,
+ 0,
+ 0,
+ 18572,
+ 0,
+ 18574,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18586,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18588,
+ 0,
+ 0,
+ 18589,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18590,
+ 0,
+ 18592,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18594,
+ 0,
+ 0,
+ 0,
+ 18596,
+ 0,
+ 0,
+ 18597,
+ 18598,
+ 0,
+ 0,
+ 18601,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18602,
+ 0,
+ 0,
+ 0,
+ 18603,
+ 18604,
+ 0,
+ 18605,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18608,
+ 0,
+ 0,
+ 18611,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18612,
+ 0,
+ 18616,
+ 0,
+ 0,
+ 18617,
+ 18619,
+ 0,
+ 0,
+ 0,
+ 18628,
+ 0,
+ 0,
+ 0,
+ 18629,
+ 0,
+ 0,
+ 18630,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18631,
+ 0,
+ 18632,
+ 0,
+ 0,
+ 18635,
+ 18637,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18641,
+ 18643,
+ 18648,
+ 0,
+ 18652,
+ 0,
+ 0,
+ 18653,
+ 0,
+ 18655,
+ 18656,
+ 0,
+ 0,
+ 0,
+ 18657,
+ 0,
+ 0,
+ 18666,
+ 18674,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18677,
+ 18684,
+ 18685,
+ 0,
+ 0,
+ 18686,
+ 0,
+ 0,
+ 18690,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18695,
+ 18696,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18697,
+ 0,
+ 0,
+ 18700,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18702,
+ 0,
+ 18708,
+ 0,
+ 0,
+ 18709,
+ 0,
+ 18710,
+ 0,
+ 0,
+ 18711,
+ 0,
+ 18714,
+ 0,
+ 0,
+ 18718,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18719,
+ 0,
+ 0,
+ 18722,
+ 0,
+ 18726,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18731,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18739,
+ 18741,
+ 0,
+ 0,
+ 18742,
+ 0,
+ 18743,
+ 18744,
+ 18746,
+ 18748,
+ 0,
+ 18752,
+ 18753,
+ 0,
+ 0,
+ 18754,
+ 18763,
+ 0,
+ 18765,
+ 0,
+ 0,
+ 0,
+ 18766,
+ 0,
+ 0,
+ 0,
+ 18769,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18773,
+ 18778,
+ 18779,
+ 18781,
+ 0,
+ 0,
+ 18784,
+ 18787,
+ 0,
+ 18788,
+ 0,
+ 18793,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18795,
+ 0,
+ 0,
+ 18800,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18801,
+ 18804,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18806,
+ 0,
+ 0,
+ 0,
+ 18811,
+ 18815,
+ 18816,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18825,
+ 0,
+ 0,
+ 18827,
+ 18829,
+ 0,
+ 0,
+ 18830,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18831,
+ 0,
+ 0,
+ 18832,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18833,
+ 0,
+ 18840,
+ 0,
+ 18841,
+ 0,
+ 18842,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18843,
+ 0,
+ 18844,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18845,
+ 18846,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18848,
+ 0,
+ 0,
+ 0,
+ 18853,
+ 18860,
+ 0,
+ 0,
+ 18862,
+ 18866,
+ 0,
+ 0,
+ 18867,
+ 18869,
+ 0,
+ 0,
+ 18874,
+ 18881,
+ 18891,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18892,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18895,
+ 0,
+ 18896,
+ 0,
+ 0,
+ 0,
+ 18900,
+ 0,
+ 0,
+ 0,
+ 18901,
+ 0,
+ 18902,
+ 18915,
+ 18916,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18919,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18920,
+ 0,
+ 0,
+ 0,
+ 18921,
+ 18929,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18930,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18932,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18934,
+ 18942,
+ 0,
+ 0,
+ 0,
+ 18951,
+ 18957,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18958,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18959,
+ 18960,
+ 0,
+ 0,
+ 18961,
+ 0,
+ 0,
+ 18962,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18963,
+ 18964,
+ 0,
+ 0,
+ 0,
+ 18965,
+ 0,
+ 18967,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18968,
+ 0,
+ 18969,
+ 0,
+ 18970,
+ 18973,
+ 18976,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18977,
+ 0,
+ 0,
+ 0,
+ 18981,
+ 0,
+ 0,
+ 0,
+ 18990,
+ 0,
+ 18998,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18999,
+ 19003,
+ 0,
+ 0,
+ 19005,
+ 0,
+ 0,
+ 0,
+ 19006,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19008,
+ 19011,
+ 0,
+ 0,
+ 19018,
+ 0,
+ 0,
+ 19019,
+ 0,
+ 19024,
+ 0,
+ 19031,
+ 19032,
+ 0,
+ 19039,
+ 0,
+ 19041,
+ 19050,
+ 0,
+ 0,
+ 0,
+ 19051,
+ 19055,
+ 19056,
+ 0,
+ 19059,
+ 19063,
+ 19064,
+ 0,
+ 0,
+ 19088,
+ 0,
+ 0,
+ 0,
+ 19093,
+ 19094,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19095,
+ 0,
+ 19096,
+ 0,
+ 0,
+ 0,
+ 19097,
+ 0,
+ 0,
+ 19098,
+ 0,
+ 19099,
+ 19100,
+ 0,
+ 0,
+ 19103,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19111,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19112,
+ 0,
+ 0,
+ 0,
+ 19116,
+ 19117,
+ 0,
+ 19121,
+ 19122,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19123,
+ 19124,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19125,
+ 19126,
+ 0,
+ 19128,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19129,
+ 19130,
+ 19131,
+ 19132,
+ 0,
+ 0,
+ 19146,
+ 0,
+ 0,
+ 19147,
+ 19156,
+ 19158,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19182,
+ 19185,
+ 0,
+ 0,
+ 19187,
+ 0,
+ 0,
+ 0,
+ 19193,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19194,
+ 0,
+ 19197,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19198,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19202,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19203,
+ 0,
+ 19205,
+ 19210,
+ 0,
+ 0,
+ 0,
+ 19213,
+ 0,
+ 19218,
+ 0,
+ 0,
+ 0,
+ 19223,
+ 19229,
+ 0,
+ 0,
+ 19230,
+ 0,
+ 0,
+ 19231,
+ 19232,
+ 19233,
+ 19239,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19240,
+ 0,
+ 19248,
+ 19249,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19254,
+ 0,
+ 19256,
+ 19258,
+ 19259,
+ 0,
+ 0,
+ 19261,
+ 0,
+ 19266,
+ 0,
+ 0,
+ 0,
+ 19272,
+ 0,
+ 19278,
+ 19281,
+ 19282,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19283,
+ 0,
+ 0,
+ 19284,
+ 0,
+ 0,
+ 19285,
+ 19287,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19288,
+ 19291,
+ 0,
+ 19292,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19297,
+ 0,
+ 19298,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19302,
+ 19303,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19304,
+ 19305,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19314,
+ 0,
+ 0,
+ 19315,
+ 0,
+ 0,
+ 19321,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19322,
+ 0,
+ 19333,
+ 0,
+ 19334,
+ 19335,
+ 0,
+ 19336,
+ 19337,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19346,
+ 0,
+ 0,
+ 19353,
+ 0,
+ 19354,
+ 19362,
+ 0,
+ 19366,
+ 19367,
+ 0,
+ 0,
+ 19369,
+ 0,
+ 19375,
+ 0,
+ 19377,
+ 19380,
+ 19388,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19389,
+ 19390,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19392,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19402,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19412,
+ 0,
+ 0,
+ 19413,
+ 19422,
+ 0,
+ 19424,
+ 0,
+ 0,
+ 0,
+ 19425,
+ 0,
+ 0,
+ 0,
+ 19428,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19431,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19432,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19448,
+ 19459,
+ 0,
+ 0,
+ 19461,
+ 0,
+ 19462,
+ 19463,
+ 0,
+ 19467,
+ 19474,
+ 19482,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19494,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19501,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19502,
+ 19504,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19505,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19506,
+ 19507,
+ 0,
+ 0,
+ 0,
+ 19508,
+ 0,
+ 0,
+ 19511,
+ 0,
+ 0,
+ 19514,
+ 0,
+ 19515,
+ 0,
+ 19516,
+ 0,
+ 19518,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19530,
+ 0,
+ 19537,
+ 19538,
+ 0,
+ 19543,
+ 19546,
+ 0,
+ 19547,
+ 19551,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19552,
+ 19553,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19555,
+ 0,
+ 0,
+ 19556,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19560,
+ 19561,
+ 0,
+ 0,
+ 19562,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19565,
+ 19567,
+ 0,
+ 19568,
+ 0,
+ 0,
+ 0,
+ 19569,
+ 19570,
+ 0,
+ 19578,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19580,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19581,
+ 19584,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19585,
+ 19586,
+ 0,
+ 0,
+ 0,
+ 19587,
+ 19588,
+ 0,
+ 19589,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19592,
+ 19593,
+ 19599,
+ 0,
+ 19600,
+ 0,
+ 0,
+ 19604,
+ 0,
+ 0,
+ 19605,
+ 0,
+ 19606,
+ 19608,
+ 19610,
+ 0,
+ 19613,
+ 19614,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19616,
+ 19617,
+ 0,
+ 0,
+ 19618,
+ 0,
+ 0,
+ 19619,
+ 0,
+ 0,
+ 0,
+ 19620,
+ 19621,
+ 19631,
+ 0,
+ 0,
+ 19632,
+ 19634,
+ 19636,
+ 0,
+ 19643,
+ 0,
+ 0,
+ 19644,
+ 19658,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19659,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19675,
+ 19677,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19679,
+ 0,
+ 19683,
+ 0,
+ 19684,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19687,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19688,
+ 19689,
+ 19692,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19695,
+ 19697,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19698,
+ 19699,
+ 0,
+ 0,
+ 19700,
+ 0,
+ 19702,
+ 0,
+ 0,
+ 19703,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19704,
+ 19708,
+ 0,
+ 19710,
+ 0,
+ 19713,
+ 0,
+ 0,
+ 0,
+ 19715,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19718,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19720,
+ 0,
+ 19722,
+ 0,
+ 0,
+ 19725,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19730,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19731,
+ 0,
+ 19734,
+ 19735,
+ 19739,
+ 0,
+ 0,
+ 19740,
+ 0,
+ 19741,
+ 0,
+ 0,
+ 0,
+ 19746,
+ 0,
+ 0,
+ 19747,
+ 0,
+ 19771,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19772,
+ 19775,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19778,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19779,
+ 0,
+ 0,
+ 19780,
+ 19790,
+ 0,
+ 19791,
+ 0,
+ 0,
+ 19792,
+ 0,
+ 0,
+ 0,
+ 19793,
+ 0,
+ 0,
+ 19796,
+ 19797,
+ 0,
+ 0,
+ 0,
+ 19799,
+ 0,
+ 0,
+ 0,
+ 19801,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19803,
+ 0,
+ 19804,
+ 0,
+ 19805,
+ 0,
+ 0,
+ 19807,
+ 0,
+ 0,
+ 0,
+ 19808,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19809,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19816,
+ 0,
+ 19821,
+ 0,
+ 19822,
+ 19830,
+ 19831,
+ 0,
+ 0,
+ 0,
+ 19833,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19838,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19839,
+ 0,
+ 0,
+ 19843,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19845,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19847,
+ 0,
+ 0,
+ 19848,
+ 0,
+ 19849,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19851,
+ 0,
+ 0,
+ 0,
+ 19854,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19864,
+ 0,
+ 19865,
+ 0,
+ 19866,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19868,
+ 0,
+ 0,
+ 19870,
+ 0,
+ 0,
+ 19871,
+ 0,
+ 0,
+ 19872,
+ 19873,
+ 19875,
+ 0,
+ 19880,
+ 19882,
+ 19884,
+ 0,
+ 0,
+ 19885,
+ 19886,
+ 19888,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19890,
+ 19892,
+ 19893,
+ 0,
+ 0,
+ 19894,
+ 0,
+ 0,
+ 0,
+ 19895,
+ 0,
+ 19896,
+ 19902,
+ 0,
+ 0,
+ 19903,
+ 0,
+ 0,
+ 19905,
+ 0,
+ 0,
+ 0,
+ 19906,
+ 0,
+ 19908,
+ 0,
+ 19909,
+ 19911,
+ 0,
+ 0,
+ 0,
+ 19913,
+ 19920,
+ 0,
+ 19938,
+ 19939,
+ 19940,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19942,
+ 0,
+ 19943,
+ 0,
+ 19945,
+ 0,
+ 0,
+ 0,
+ 19951,
+ 19952,
+ 19954,
+ 19960,
+ 0,
+ 19965,
+ 0,
+ 19971,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19975,
+ 0,
+ 19976,
+ 0,
+ 19990,
+ 0,
+ 0,
+ 19991,
+ 0,
+ 19993,
+ 0,
+ 19995,
+ 0,
+ 0,
+ 0,
+ 19998,
+ 19999,
+ 20001,
+ 0,
+ 20003,
+ 20005,
+ 0,
+ 20011,
+ 20012,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20014,
+ 0,
+ 20020,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20021,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20023,
+ 20024,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20025,
+ 0,
+ 0,
+ 20027,
+ 0,
+ 0,
+ 20029,
+ 0,
+ 0,
+ 20032,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20044,
+ 20045,
+ 0,
+ 20048,
+ 20049,
+ 0,
+ 0,
+ 20050,
+ 0,
+ 20052,
+ 0,
+ 0,
+ 20054,
+ 20057,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20059,
+ 0,
+ 0,
+ 20061,
+ 0,
+ 20062,
+ 0,
+ 20064,
+ 0,
+ 0,
+ 20066,
+ 0,
+ 0,
+ 20067,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20069,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20070,
+ 20071,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20072,
+ 0,
+ 0,
+ 20073,
+ 20074,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20075,
+ 0,
+ 20078,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20080,
+ 0,
+ 20081,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20095,
+ 0,
+ 20098,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20107,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20112,
+ 0,
+ 0,
+ 0,
+ 20113,
+ 20114,
+ 0,
+ 0,
+ 0,
+ 20115,
+ 20123,
+ 20124,
+ 0,
+ 0,
+ 0,
+ 20131,
+ 20133,
+ 20134,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20136,
+ 0,
+ 0,
+ 20137,
+ 20138,
+ 20150,
+ 0,
+ 20152,
+ 0,
+ 0,
+ 0,
+ 20153,
+ 0,
+ 0,
+ 20154,
+ 0,
+ 0,
+ 0,
+ 20158,
+ 0,
+ 20163,
+ 0,
+ 0,
+ 20164,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20166,
+ 0,
+ 20168,
+ 0,
+ 20170,
+ 0,
+ 20175,
+ 0,
+ 0,
+ 20178,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20223,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20224,
+ 0,
+ 20226,
+ 0,
+ 0,
+ 20230,
+ 0,
+ 20231,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20232,
+ 0,
+ 0,
+ 20233,
+ 20234,
+ 0,
+ 20244,
+ 0,
+ 20247,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20249,
+ 0,
+ 0,
+ 0,
+ 20250,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20251,
+ 0,
+ 20253,
+ 0,
+ 20254,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20256,
+ 0,
+ 0,
+ 20264,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20266,
+ 0,
+ 0,
+ 0,
+ 20278,
+ 0,
+ 0,
+ 20279,
+ 20282,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20283,
+ 0,
+ 20284,
+ 0,
+ 20285,
+ 0,
+ 20287,
+ 20290,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20292,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20293,
+ 20297,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20299,
+ 0,
+ 20300,
+ 20303,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20307,
+ 0,
+ 0,
+ 20308,
+ 0,
+ 20309,
+ 0,
+ 20310,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20312,
+ 0,
+ 0,
+ 0,
+ 20314,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20315,
+ 20316,
+ 0,
+ 20322,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20339,
+ 0,
+ 0,
+ 0,
+ 20342,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20352,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20362,
+ 0,
+ 0,
+ 20365,
+ 0,
+ 20375,
+ 20377,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20378,
+ 20379,
+ 0,
+ 20380,
+ 0,
+ 0,
+ 20381,
+ 0,
+ 20382,
+ 0,
+ 20383,
+ 0,
+ 20388,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20390,
+ 20392,
+ 20393,
+ 0,
+ 0,
+ 20395,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20396,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20398,
+ 20415,
+ 0,
+ 0,
+ 0,
+ 20417,
+ 0,
+ 0,
+ 20420,
+ 0,
+ 0,
+ 20426,
+ 20428,
+ 0,
+ 20431,
+ 0,
+ 0,
+ 20432,
+ 0,
+ 20433,
+ 20434,
+ 20435,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20440,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20442,
+ 0,
+ 20443,
+ 0,
+ 20446,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20448,
+ 0,
+ 20451,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20452,
+ 20453,
+ 0,
+ 0,
+ 20454,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20457,
+ 0,
+ 20458,
+ 0,
+ 0,
+ 0,
+ 20465,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20469,
+ 0,
+ 0,
+ 0,
+ 20473,
+ 0,
+ 20476,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20477,
+ 0,
+ 0,
+ 20485,
+ 0,
+ 0,
+ 20486,
+ 0,
+ 0,
+ 20487,
+ 0,
+ 20496,
+ 0,
+ 20497,
+ 0,
+ 0,
+ 20498,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20499,
+ 20500,
+ 0,
+ 20501,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20520,
+ 20527,
+ 0,
+ 20529,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20539,
+ 0,
+ 0,
+ 20540,
+ 0,
+ 0,
+ 0,
+ 20543,
+ 0,
+ 0,
+ 0,
+ 20546,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20548,
+ 0,
+ 0,
+ 20563,
+ 0,
+ 0,
+ 20564,
+ 0,
+ 20566,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20589,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20590,
+ 0,
+ 0,
+ 20593,
+ 20594,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20595,
+ 0,
+ 20597,
+ 20598,
+ 0,
+ 0,
+ 0,
+ 20618,
+ 20620,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20621,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20627,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20628,
+ 0,
+ 0,
+ 0,
+ 20629,
+ 0,
+ 20630,
+ 0,
+ 0,
+ 20639,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20707,
+ 0,
+ 0,
+ 20709,
+ 0,
+ 0,
+ 0,
+ 20713,
+ 20714,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20724,
+ 20725,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20726,
+ 20728,
+ 20729,
+ 0,
+ 20733,
+ 0,
+ 20734,
+ 0,
+ 20735,
+ 20736,
+ 0,
+ 20737,
+ 0,
+ 0,
+ 20744,
+ 0,
+ 20745,
+ 0,
+ 20748,
+ 0,
+ 0,
+ 20749,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20750,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20754,
+ 0,
+ 0,
+ 0,
+ 20761,
+ 0,
+ 0,
+ 20763,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20766,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20767,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20768,
+ 0,
+ 20769,
+ 20777,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20785,
+ 0,
+ 0,
+ 0,
+ 20786,
+ 20795,
+ 20801,
+ 0,
+ 20802,
+ 0,
+ 20807,
+ 0,
+ 0,
+ 20808,
+ 0,
+ 0,
+ 20810,
+ 0,
+ 0,
+ 20811,
+ 0,
+ 20812,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20813,
+ 0,
+ 0,
+ 20818,
+ 20820,
+ 20821,
+ 0,
+ 0,
+ 0,
+ 20822,
+ 0,
+ 20823,
+ 0,
+ 0,
+ 0,
+ 20826,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20829,
+ 20830,
+ 20831,
+ 0,
+ 20832,
+ 20836,
+ 0,
+ 0,
+ 20839,
+ 0,
+ 0,
+ 20840,
+ 20842,
+ 0,
+ 20843,
+ 0,
+ 20844,
+ 0,
+ 20854,
+ 0,
+ 0,
+ 0,
+ 20855,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20856,
+ 0,
+ 0,
+ 0,
+ 20869,
+ 0,
+ 0,
+ 20871,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20873,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20876,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20880,
+ 0,
+ 0,
+ 20882,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20883,
+ 20884,
+ 0,
+ 0,
+ 20890,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20891,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20905,
+ 0,
+ 20906,
+ 20910,
+ 0,
+ 0,
+ 20912,
+ 20915,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20916,
+ 0,
+ 20917,
+ 0,
+ 20919,
+ 20920,
+ 20922,
+ 0,
+ 20927,
+ 0,
+ 20928,
+ 20929,
+ 20930,
+ 0,
+ 0,
+ 20935,
+ 0,
+ 0,
+ 20939,
+ 0,
+ 0,
+ 20941,
+ 0,
+ 0,
+ 0,
+ 20943,
+ 0,
+ 0,
+ 0,
+ 20946,
+ 20947,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20950,
+ 0,
+ 20954,
+ 0,
+ 0,
+ 20955,
+ 20964,
+ 0,
+ 0,
+ 20967,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20973,
+ 20975,
+ 0,
+ 0,
+ 0,
+ 20984,
+ 0,
+ 20987,
+ 20988,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20989,
+ 0,
+ 0,
+ 0,
+ 20995,
+ 0,
+ 20998,
+ 0,
+ 20999,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21000,
+ 21001,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21008,
+ 0,
+ 21010,
+ 0,
+ 21016,
+ 0,
+ 0,
+ 0,
+ 21017,
+ 21018,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21021,
+ 21026,
+ 21027,
+ 21028,
+ 0,
+ 0,
+ 21029,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21030,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21031,
+ 21032,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21037,
+ 0,
+ 0,
+ 21038,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21039,
+ 0,
+ 21041,
+ 0,
+ 21046,
+ 21047,
+ 0,
+ 0,
+ 0,
+ 21049,
+ 21053,
+ 0,
+ 0,
+ 21057,
+ 21064,
+ 21065,
+ 0,
+ 0,
+ 21066,
+ 21067,
+ 0,
+ 0,
+ 0,
+ 21069,
+ 0,
+ 0,
+ 0,
+ 21071,
+ 21072,
+ 0,
+ 0,
+ 21073,
+ 0,
+ 21074,
+ 0,
+ 0,
+ 21078,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21079,
+ 0,
+ 0,
+ 21080,
+ 21081,
+ 0,
+ 0,
+ 21086,
+ 21087,
+ 0,
+ 21089,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21091,
+ 0,
+ 21093,
+ 0,
+ 21094,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21095,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21096,
+ 0,
+ 21098,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21099,
+ 0,
+ 0,
+ 21100,
+ 21101,
+ 21102,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21103,
+ 0,
+ 21104,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21105,
+ 21108,
+ 21109,
+ 0,
+ 0,
+ 21112,
+ 21113,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21115,
+ 21122,
+ 21123,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21125,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21129,
+ 21131,
+ 0,
+ 0,
+ 21134,
+ 0,
+ 0,
+ 0,
+ 21137,
+ 21142,
+ 0,
+ 21143,
+ 0,
+ 0,
+ 21144,
+ 0,
+ 21145,
+ 21146,
+ 0,
+ 21152,
+ 21154,
+ 21155,
+ 21156,
+ 0,
+ 0,
+ 0,
+ 21160,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21161,
+ 0,
+ 21164,
+ 0,
+ 21166,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21170,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21171,
+ 0,
+ 0,
+ 21172,
+ 0,
+ 21174,
+ 0,
+ 21175,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21176,
+ 21179,
+ 21188,
+ 0,
+ 0,
+ 0,
+ 21189,
+ 0,
+ 0,
+ 21190,
+ 0,
+ 0,
+ 0,
+ 21192,
+ 0,
+ 0,
+ 21193,
+ 0,
+ 0,
+ 0,
+ 21198,
+ 0,
+ 21212,
+ 0,
+ 0,
+ 21213,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21215,
+ 21216,
+ 0,
+ 0,
+ 21223,
+ 21225,
+ 0,
+ 21226,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21227,
+ 21228,
+ 0,
+ 0,
+ 21229,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21230,
+ 21236,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21237,
+ 0,
+ 0,
+ 21238,
+ 21239,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21256,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21257,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21259,
+ 0,
+ 0,
+ 0,
+ 21263,
+ 0,
+ 21272,
+ 0,
+ 21274,
+ 0,
+ 21282,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21283,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21294,
+ 0,
+ 0,
+ 21297,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21298,
+ 0,
+ 0,
+ 0,
+ 21299,
+ 0,
+ 21300,
+ 21302,
+ 0,
+ 21316,
+ 0,
+ 21318,
+ 21322,
+ 21323,
+ 0,
+ 21324,
+ 0,
+ 21326,
+ 0,
+ 0,
+ 0,
+ 21327,
+ 21328,
+ 0,
+ 0,
+ 0,
+ 21352,
+ 0,
+ 0,
+ 21354,
+ 21361,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21362,
+ 0,
+ 0,
+ 0,
+ 21363,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21366,
+ 0,
+ 0,
+ 21367,
+ 21372,
+ 21374,
+ 0,
+ 0,
+ 0,
+ 21375,
+ 21377,
+ 0,
+ 21378,
+ 0,
+ 0,
+ 0,
+ 21380,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21381,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21382,
+ 0,
+ 21383,
+ 0,
+ 0,
+ 21384,
+ 0,
+ 0,
+ 21385,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21389,
+ 21390,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21397,
+ 21398,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21399,
+ 0,
+ 21400,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21402,
+ 0,
+ 0,
+ 0,
+ 21403,
+ 21404,
+ 0,
+ 21405,
+ 21406,
+ 0,
+ 0,
+ 0,
+ 21407,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21408,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21409,
+ 0,
+ 21421,
+ 0,
+ 21422,
+ 0,
+ 0,
+ 0,
+ 21425,
+ 21428,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21429,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21433,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21434,
+ 0,
+ 21443,
+ 0,
+ 21444,
+ 21449,
+ 0,
+ 21452,
+ 0,
+ 21453,
+ 21454,
+ 0,
+ 0,
+ 0,
+ 21457,
+ 0,
+ 0,
+ 21458,
+ 0,
+ 0,
+ 0,
+ 21460,
+ 21461,
+ 0,
+ 0,
+ 21464,
+ 0,
+ 0,
+ 0,
+ 21473,
+ 21478,
+ 0,
+ 0,
+ 21479,
+ 0,
+ 0,
+ 21481,
+ 21483,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21484,
+ 0,
+ 0,
+ 21485,
+ 21486,
+ 0,
+ 0,
+ 21488,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21523,
+ 0,
+ 0,
+ 21525,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21526,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21529,
+ 21530,
+ 0,
+ 0,
+ 21531,
+ 0,
+ 0,
+ 21533,
+ 0,
+ 0,
+ 21539,
+ 21564,
+ 0,
+ 21567,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21575,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21577,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21591,
+ 0,
+ 0,
+ 21604,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21605,
+ 0,
+ 21606,
+ 0,
+ 0,
+ 21617,
+ 21618,
+ 21619,
+ 21620,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21623,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21631,
+ 0,
+ 21635,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21639,
+ 21646,
+ 21653,
+ 21662,
+ 0,
+ 0,
+ 21663,
+ 21664,
+ 0,
+ 21666,
+ 0,
+ 0,
+ 21667,
+ 0,
+ 21670,
+ 21672,
+ 21673,
+ 0,
+ 21674,
+ 21683,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21684,
+ 0,
+ 21694,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21695,
+ 21700,
+ 0,
+ 21703,
+ 0,
+ 21704,
+ 0,
+ 0,
+ 21709,
+ 0,
+ 0,
+ 0,
+ 21710,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21711,
+ 0,
+ 0,
+ 0,
+ 21712,
+ 0,
+ 21717,
+ 0,
+ 21730,
+ 0,
+ 0,
+ 0,
+ 21731,
+ 21733,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21737,
+ 21741,
+ 21742,
+ 0,
+ 21747,
+ 0,
+ 0,
+ 0,
+ 21749,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21750,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21752,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21753,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21755,
+ 21756,
+ 0,
+ 21757,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21760,
+ 0,
+ 0,
+ 21763,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21764,
+ 0,
+ 0,
+ 21766,
+ 0,
+ 0,
+ 21767,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21773,
+ 0,
+ 21774,
+ 0,
+ 0,
+ 21775,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21776,
+ 0,
+ 0,
+ 21777,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21780,
+ 21787,
+ 21788,
+ 21791,
+ 0,
+ 0,
+ 0,
+ 21797,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21805,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21806,
+ 0,
+ 21807,
+ 21809,
+ 0,
+ 21810,
+ 21811,
+ 0,
+ 21817,
+ 21819,
+ 21820,
+ 0,
+ 21823,
+ 0,
+ 21824,
+ 0,
+ 0,
+ 21825,
+ 0,
+ 0,
+ 21826,
+ 21832,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21833,
+ 21848,
+ 21849,
+ 0,
+ 0,
+ 21867,
+ 21870,
+ 21871,
+ 21873,
+ 0,
+ 0,
+ 0,
+ 21874,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21875,
+ 0,
+ 21878,
+ 0,
+ 0,
+ 0,
+ 21879,
+ 0,
+ 21881,
+ 21886,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21887,
+ 0,
+ 0,
+ 21888,
+ 21894,
+ 21895,
+ 21897,
+ 0,
+ 21901,
+ 0,
+ 21904,
+ 0,
+ 0,
+ 21906,
+ 0,
+ 0,
+ 0,
+ 21909,
+ 21910,
+ 21911,
+ 0,
+ 0,
+ 21912,
+ 0,
+ 0,
+ 21913,
+ 21914,
+ 21915,
+ 0,
+ 21919,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21921,
+ 0,
+ 0,
+ 21922,
+ 21933,
+ 21939,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21944,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21945,
+ 0,
+ 21947,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21949,
+ 0,
+ 0,
+ 0,
+ 21950,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21951,
+ 0,
+ 21952,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21954,
+ 21957,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21958,
+ 0,
+ 21959,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21962,
+ 21963,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21964,
+ 21965,
+ 0,
+ 0,
+ 21969,
+ 21970,
+ 0,
+ 0,
+ 0,
+ 21974,
+ 0,
+ 0,
+ 21980,
+ 21981,
+ 0,
+ 21982,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21985,
+ 0,
+ 21988,
+ 0,
+ 21992,
+ 0,
+ 21999,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22001,
+ 0,
+ 22002,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22003,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22004,
+ 0,
+ 0,
+ 0,
+ 22008,
+ 0,
+ 22009,
+ 22015,
+ 0,
+ 0,
+ 22016,
+ 0,
+ 0,
+ 0,
+ 22017,
+ 22019,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22020,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22021,
+ 22037,
+ 0,
+ 22039,
+ 0,
+ 0,
+ 0,
+ 22040,
+ 0,
+ 0,
+ 0,
+ 22048,
+ 22049,
+ 0,
+ 0,
+ 22053,
+ 22055,
+ 22056,
+ 22059,
+ 0,
+ 0,
+ 22060,
+ 22061,
+ 0,
+ 0,
+ 22064,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22066,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22073,
+ 0,
+ 0,
+ 0,
+ 22074,
+ 22075,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22076,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22077,
+ 22084,
+ 22099,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22104,
+ 0,
+ 0,
+ 22107,
+ 0,
+ 22108,
+ 0,
+ 22109,
+ 0,
+ 22110,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22111,
+ 22119,
+ 0,
+ 22120,
+ 22122,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22125,
+ 0,
+ 0,
+ 0,
+ 22128,
+ 22129,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22141,
+ 0,
+ 0,
+ 0,
+ 22142,
+ 0,
+ 0,
+ 22144,
+ 22146,
+ 0,
+ 22148,
+ 22149,
+ 22151,
+ 22154,
+ 0,
+ 0,
+ 0,
+ 22162,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22164,
+ 22177,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22179,
+ 0,
+ 22182,
+ 22183,
+ 0,
+ 0,
+ 22184,
+ 22188,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22190,
+ 0,
+ 22194,
+ 22201,
+ 0,
+ 0,
+ 22208,
+ 0,
+ 22209,
+ 0,
+ 22212,
+ 0,
+ 0,
+ 22215,
+ 0,
+ 22223,
+ 22231,
+ 0,
+ 0,
+ 22232,
+ 0,
+ 22234,
+ 0,
+ 0,
+ 22235,
+ 22236,
+ 0,
+ 22237,
+ 0,
+ 22240,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22241,
+ 0,
+ 0,
+ 0,
+ 22242,
+ 22246,
+ 22247,
+ 0,
+ 0,
+ 0,
+ 22259,
+ 22268,
+ 0,
+ 22269,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22270,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22271,
+ 0,
+ 22272,
+ 0,
+ 22277,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22278,
+ 22280,
+ 22283,
+ 22286,
+ 0,
+ 0,
+ 22287,
+ 22289,
+ 0,
+ 0,
+ 22290,
+ 0,
+ 22293,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22295,
+ 0,
+ 22301,
+ 22302,
+ 0,
+ 0,
+ 0,
+ 22305,
+ 0,
+ 22308,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22315,
+ 0,
+ 0,
+ 0,
+ 22317,
+ 0,
+ 22334,
+ 0,
+ 0,
+ 0,
+ 22335,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22336,
+ 0,
+ 22338,
+ 22344,
+ 0,
+ 22347,
+ 22349,
+ 0,
+ 22350,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22357,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22358,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22359,
+ 22360,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22361,
+ 22366,
+ 0,
+ 0,
+ 22369,
+ 0,
+ 22370,
+ 22373,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22375,
+ 0,
+ 22377,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22378,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22381,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22382,
+ 0,
+ 22383,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22391,
+ 0,
+ 0,
+ 22392,
+ 22395,
+ 22396,
+ 22402,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22405,
+ 0,
+ 0,
+ 22406,
+ 0,
+ 0,
+ 22408,
+ 0,
+ 0,
+ 22409,
+ 22410,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22424,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22426,
+ 0,
+ 0,
+ 0,
+ 22427,
+ 0,
+ 22428,
+ 0,
+ 22432,
+ 0,
+ 22435,
+ 22442,
+ 22443,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22444,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22446,
+ 0,
+ 22454,
+ 0,
+ 22455,
+ 0,
+ 0,
+ 0,
+ 22465,
+ 0,
+ 22470,
+ 0,
+ 22471,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22472,
+ 22473,
+ 0,
+ 22487,
+ 0,
+ 0,
+ 0,
+ 22488,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22489,
+ 0,
+ 0,
+ 22499,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22514,
+ 0,
+ 0,
+ 22515,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22516,
+ 0,
+ 0,
+ 0,
+ 22517,
+ 22520,
+ 0,
+ 0,
+ 0,
+ 22534,
+ 0,
+ 0,
+ 22535,
+ 0,
+ 0,
+ 22536,
+ 0,
+ 22540,
+ 22553,
+ 0,
+ 22555,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22561,
+ 0,
+ 0,
+ 22562,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22566,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22567,
+ 22568,
+ 0,
+ 0,
+ 22575,
+ 0,
+ 22579,
+ 0,
+ 22582,
+ 22583,
+ 22585,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22586,
+ 0,
+ 0,
+ 22587,
+ 0,
+ 0,
+ 22590,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22591,
+ 0,
+ 22592,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22593,
+ 0,
+ 22602,
+ 0,
+ 0,
+ 22604,
+ 0,
+ 0,
+ 22609,
+ 0,
+ 0,
+ 22618,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22619,
+ 0,
+ 22624,
+ 22625,
+ 0,
+ 0,
+ 22638,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22639,
+ 0,
+ 0,
+ 22640,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22644,
+ 0,
+ 22645,
+ 22647,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22652,
+ 22653,
+ 0,
+ 0,
+ 0,
+ 22654,
+ 0,
+ 22655,
+ 0,
+ 0,
+ 0,
+ 22656,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22673,
+ 22675,
+ 22676,
+ 0,
+ 0,
+ 22678,
+ 22679,
+ 0,
+ 22691,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22693,
+ 0,
+ 0,
+ 22696,
+ 0,
+ 22699,
+ 22707,
+ 22708,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22718,
+ 0,
+ 22719,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22723,
+ 0,
+ 0,
+ 0,
+ 22724,
+ 22725,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22726,
+ 22728,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22729,
+ 0,
+ 0,
+ 22731,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22732,
+ 22735,
+ 22736,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22739,
+ 0,
+ 22749,
+ 0,
+ 0,
+ 22751,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22758,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22760,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22764,
+ 22765,
+ 22766,
+ 0,
+ 22768,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22769,
+ 22770,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22771,
+ 0,
+ 0,
+ 22772,
+ 22775,
+ 0,
+ 22776,
+ 22777,
+ 22780,
+ 0,
+ 0,
+ 22782,
+ 22784,
+ 0,
+ 22787,
+ 0,
+ 22789,
+ 22796,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22798,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22802,
+ 0,
+ 22803,
+ 22804,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22805,
+ 0,
+ 0,
+ 22810,
+ 22811,
+ 22814,
+ 22816,
+ 0,
+ 22825,
+ 22826,
+ 0,
+ 22831,
+ 22833,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22834,
+ 0,
+ 22836,
+ 22838,
+ 0,
+ 22839,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22840,
+ 0,
+ 22847,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22856,
+ 22857,
+ 0,
+ 22858,
+ 22859,
+ 0,
+ 0,
+ 22862,
+ 0,
+ 0,
+ 22864,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22865,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22866,
+ 0,
+ 22867,
+ 22868,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22869,
+ 0,
+ 22871,
+ 0,
+ 22872,
+ 0,
+ 22873,
+ 22881,
+ 22882,
+ 22884,
+ 22885,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22886,
+ 22887,
+ 0,
+ 22894,
+ 0,
+ 22895,
+ 0,
+ 0,
+ 0,
+ 22900,
+ 0,
+ 22901,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22904,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22905,
+ 22907,
+ 0,
+ 0,
+ 0,
+ 22915,
+ 22917,
+ 0,
+ 0,
+ 22918,
+ 0,
+ 0,
+ 0,
+ 22920,
+ 0,
+ 0,
+ 0,
+ 22929,
+ 22930,
+ 0,
+ 0,
+ 0,
+ 22941,
+ 22942,
+ 0,
+ 0,
+ 0,
+ 22943,
+ 0,
+ 0,
+ 0,
+ 22944,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22946,
+ 0,
+ 22947,
+ 0,
+ 0,
+ 22954,
+ 0,
+ 22956,
+ 0,
+ 0,
+ 22962,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22963,
+ 0,
+ 0,
+ 22964,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22965,
+ 0,
+ 22968,
+ 0,
+ 0,
+ 0,
+ 22969,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22970,
+ 0,
+ 22971,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22978,
+ 0,
+ 0,
+ 22979,
+ 0,
+ 22987,
+ 0,
+ 0,
+ 22989,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22990,
+ 0,
+ 23005,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23006,
+ 23007,
+ 23008,
+ 0,
+ 0,
+ 23023,
+ 23024,
+ 23029,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23030,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23032,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23035,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23038,
+ 0,
+ 0,
+ 0,
+ 23048,
+ 0,
+ 23049,
+ 23052,
+ 23053,
+ 23060,
+ 23061,
+ 0,
+ 23063,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23067,
+ 23068,
+ 0,
+ 0,
+ 0,
+ 23069,
+ 23073,
+ 0,
+ 0,
+ 0,
+ 23127,
+ 0,
+ 23128,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23129,
+ 0,
+ 23138,
+ 23141,
+ 0,
+ 23149,
+ 0,
+ 0,
+ 23150,
+ 0,
+ 0,
+ 0,
+ 23152,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23154,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23157,
+ 23159,
+ 23160,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23180,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23181,
+ 0,
+ 0,
+ 23188,
+ 0,
+ 23189,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23195,
+ 0,
+ 0,
+ 23196,
+ 23199,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23202,
+ 0,
+ 23204,
+ 0,
+ 23207,
+ 0,
+ 23209,
+ 23210,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23227,
+ 23229,
+ 0,
+ 0,
+ 23230,
+ 23234,
+ 23238,
+ 0,
+ 0,
+ 0,
+ 23245,
+ 23246,
+ 23248,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23249,
+ 23254,
+ 0,
+ 0,
+ 0,
+ 23265,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23268,
+ 0,
+ 23276,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23277,
+ 0,
+ 23297,
+ 0,
+ 23298,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23299,
+ 0,
+ 23302,
+ 0,
+ 0,
+ 23303,
+ 23312,
+ 0,
+ 0,
+ 23314,
+ 0,
+ 23320,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23324,
+ 0,
+ 23325,
+ 0,
+ 23328,
+ 0,
+ 23334,
+ 0,
+ 0,
+ 0,
+ 23337,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23343,
+ 23344,
+ 23346,
+ 0,
+ 23348,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23353,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23355,
+ 0,
+ 23356,
+ 23358,
+ 0,
+ 0,
+ 0,
+ 23359,
+ 23360,
+ 0,
+ 23361,
+ 0,
+ 23367,
+ 0,
+ 23369,
+ 0,
+ 0,
+ 23373,
+ 0,
+ 23378,
+ 23379,
+ 0,
+ 23382,
+ 23383,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23387,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23388,
+ 23390,
+ 0,
+ 0,
+ 23393,
+ 23398,
+ 0,
+ 0,
+ 0,
+ 23399,
+ 0,
+ 0,
+ 0,
+ 23400,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23401,
+ 0,
+ 0,
+ 0,
+ 23415,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23416,
+ 0,
+ 23422,
+ 0,
+ 23443,
+ 23444,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23448,
+ 0,
+ 23454,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23456,
+ 0,
+ 0,
+ 23458,
+ 23464,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23465,
+ 0,
+ 0,
+ 0,
+ 23470,
+ 23471,
+ 0,
+ 0,
+ 23472,
+ 0,
+ 0,
+ 0,
+ 23473,
+ 23496,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23497,
+ 0,
+ 23499,
+ 0,
+ 0,
+ 23502,
+ 0,
+ 0,
+ 23503,
+ 0,
+ 0,
+ 23513,
+ 0,
+ 0,
+ 23515,
+ 0,
+ 0,
+ 0,
+ 23517,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23518,
+ 23519,
+ 23521,
+ 23524,
+ 0,
+ 23525,
+ 23528,
+ 23539,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23541,
+ 0,
+ 0,
+ 23544,
+ 0,
+ 0,
+ 23556,
+ 0,
+ 0,
+ 23557,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23559,
+ 0,
+ 23560,
+ 0,
+ 0,
+ 23561,
+ 0,
+ 0,
+ 23566,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23568,
+ 23569,
+ 23570,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23571,
+ 0,
+ 23574,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23575,
+ 0,
+ 23579,
+ 0,
+ 0,
+ 23581,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23587,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23596,
+ 23598,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23602,
+ 23606,
+ 0,
+ 0,
+ 23607,
+ 0,
+ 23608,
+ 0,
+ 0,
+ 0,
+ 23614,
+ 23616,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23618,
+ 0,
+ 0,
+ 23619,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23621,
+ 23626,
+ 0,
+ 23627,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23629,
+ 0,
+ 23630,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23634,
+ 0,
+ 23636,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23638,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23640,
+ 23667,
+ 0,
+ 23669,
+ 0,
+ 0,
+ 0,
+ 23681,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23682,
+ 0,
+ 23683,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23684,
+ 0,
+ 0,
+ 0,
+ 23685,
+ 23689,
+ 0,
+ 23693,
+ 23694,
+ 23700,
+ 0,
+ 23702,
+ 0,
+ 23709,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23712,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23714,
+ 0,
+ 0,
+ 23715,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23718,
+ 0,
+ 0,
+ 23720,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23722,
+ 0,
+ 0,
+ 0,
+ 23726,
+ 23729,
+ 0,
+ 23741,
+ 23746,
+ 0,
+ 23748,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23749,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23750,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23751,
+ 0,
+ 23753,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23757,
+ 23765,
+ 0,
+ 0,
+ 0,
+ 23770,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23771,
+ 0,
+ 23772,
+ 23781,
+ 0,
+ 0,
+ 23796,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23798,
+ 0,
+ 23799,
+ 0,
+ 0,
+ 0,
+ 23802,
+ 0,
+ 0,
+ 23806,
+ 0,
+ 23807,
+ 0,
+ 0,
+ 23808,
+ 0,
+ 23809,
+ 0,
+ 23819,
+ 0,
+ 0,
+ 0,
+ 23821,
+ 0,
+ 23827,
+ 0,
+ 0,
+ 0,
+ 23829,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23830,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23832,
+ 23833,
+ 23834,
+ 23835,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23837,
+ 23838,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23846,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23847,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23879,
+ 23881,
+ 0,
+ 0,
+ 23882,
+ 23883,
+ 23895,
+ 0,
+ 23899,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23901,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23902,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23903,
+ 23905,
+ 0,
+ 23906,
+ 0,
+ 23907,
+ 23918,
+ 23919,
+ 23920,
+ 0,
+ 23922,
+ 0,
+ 23924,
+ 0,
+ 23927,
+ 0,
+ 23934,
+ 0,
+ 23937,
+ 23941,
+ 0,
+ 23942,
+ 23946,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23955,
+ 23956,
+ 23958,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23959,
+ 0,
+ 23962,
+ 23965,
+ 0,
+ 23966,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23967,
+ 23968,
+ 0,
+ 0,
+ 23973,
+ 0,
+ 0,
+ 23974,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23975,
+ 0,
+ 23976,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23977,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23980,
+ 0,
+ 0,
+ 23984,
+ 0,
+ 23985,
+ 0,
+ 0,
+ 23987,
+ 0,
+ 0,
+ 23988,
+ 23990,
+ 23991,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23992,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23994,
+ 0,
+ 0,
+ 0,
+ 23998,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23999,
+ 0,
+ 0,
+ 24003,
+ 0,
+ 24004,
+ 0,
+ 24006,
+ 0,
+ 0,
+ 0,
+ 24007,
+ 0,
+ 0,
+ 24008,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24009,
+ 0,
+ 0,
+ 24010,
+ 0,
+ 0,
+ 24011,
+ 0,
+ 0,
+ 24013,
+ 24014,
+ 0,
+ 0,
+ 24015,
+ 24016,
+ 24027,
+ 0,
+ 24028,
+ 24029,
+ 0,
+ 24030,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24033,
+ 24034,
+ 0,
+ 24035,
+ 0,
+ 0,
+ 24036,
+ 0,
+ 0,
+ 24044,
+ 0,
+ 24048,
+ 24049,
+ 24063,
+ 24067,
+ 0,
+ 24068,
+ 24070,
+ 0,
+ 0,
+ 24071,
+ 24078,
+ 24087,
+ 0,
+ 24090,
+ 0,
+ 0,
+ 0,
+ 24095,
+ 0,
+ 24098,
+ 24101,
+ 24104,
+ 24106,
+ 0,
+ 24107,
+ 0,
+ 0,
+ 0,
+ 24108,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24110,
+ 24111,
+ 0,
+ 24113,
+ 0,
+ 0,
+ 24115,
+ 24120,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24124,
+ 0,
+ 24125,
+ 0,
+ 24126,
+ 0,
+ 24127,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24135,
+ 0,
+ 0,
+ 24136,
+ 0,
+ 24137,
+ 24142,
+ 0,
+ 0,
+ 0,
+ 24146,
+ 0,
+ 0,
+ 24147,
+ 24149,
+ 24154,
+ 0,
+ 24163,
+ 0,
+ 0,
+ 0,
+ 24165,
+ 24166,
+ 24167,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24169,
+ 24170,
+ 24175,
+ 0,
+ 0,
+ 0,
+ 24178,
+ 0,
+ 0,
+ 24179,
+ 0,
+ 0,
+ 24181,
+ 0,
+ 24184,
+ 24197,
+ 0,
+ 24201,
+ 24204,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24206,
+ 24212,
+ 24220,
+ 0,
+ 0,
+ 0,
+ 24224,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24226,
+ 0,
+ 24234,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24235,
+ 0,
+ 24236,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24239,
+ 24240,
+ 24241,
+ 0,
+ 0,
+ 24248,
+ 0,
+ 0,
+ 24249,
+ 0,
+ 24251,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24253,
+ 0,
+ 24268,
+ 0,
+ 0,
+ 0,
+ 24269,
+ 0,
+ 24271,
+ 24272,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24273,
+ 0,
+ 0,
+ 24274,
+ 0,
+ 0,
+ 24279,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24280,
+ 0,
+ 24293,
+ 24294,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24296,
+ 0,
+ 0,
+ 24323,
+ 0,
+ 0,
+ 0,
+ 24329,
+ 24330,
+ 24331,
+ 24339,
+ 0,
+ 24351,
+ 0,
+ 0,
+ 24369,
+ 24370,
+ 0,
+ 0,
+ 0,
+ 24371,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24372,
+ 24373,
+ 24374,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24378,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24379,
+ 0,
+ 24381,
+ 0,
+ 24383,
+ 24389,
+ 0,
+ 24390,
+ 0,
+ 0,
+ 24394,
+ 24395,
+ 24400,
+ 0,
+ 0,
+ 0,
+ 24401,
+ 24402,
+ 0,
+ 24406,
+ 0,
+ 0,
+ 0,
+ 24411,
+ 0,
+ 0,
+ 0,
+ 24415,
+ 0,
+ 24416,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24417,
+ 0,
+ 24419,
+ 0,
+ 24422,
+ 0,
+ 24423,
+ 24428,
+ 0,
+ 24435,
+ 0,
+ 0,
+ 0,
+ 24439,
+ 0,
+ 0,
+ 0,
+ 24440,
+ 24442,
+ 24446,
+ 0,
+ 0,
+ 0,
+ 24447,
+ 24448,
+ 24449,
+ 24452,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24453,
+ 24457,
+ 0,
+ 0,
+ 24458,
+ 24459,
+ 24460,
+ 0,
+ 24465,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24470,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24471,
+ 0,
+ 24473,
+ 24474,
+ 24475,
+ 24476,
+ 0,
+ 24478,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24480,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24481,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24482,
+ 24485,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24486,
+ 0,
+ 0,
+ 0,
+ 24488,
+ 0,
+ 0,
+ 0,
+ 24494,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24497,
+ 0,
+ 0,
+ 24498,
+ 0,
+ 0,
+ 0,
+ 24499,
+ 24506,
+ 0,
+ 0,
+ 0,
+ 24507,
+ 0,
+ 0,
+ 24511,
+ 0,
+ 0,
+ 24513,
+ 24514,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24517,
+ 0,
+ 24518,
+ 0,
+ 24520,
+ 0,
+ 24521,
+ 24524,
+ 24525,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24527,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24528,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24537,
+ 24539,
+ 0,
+ 24540,
+ 0,
+ 0,
+ 0,
+ 24548,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24549,
+ 24550,
+ 0,
+ 0,
+ 0,
+ 24553,
+ 24554,
+ 0,
+ 24555,
+ 0,
+ 24556,
+ 0,
+ 24558,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24560,
+ 0,
+ 0,
+ 0,
+ 24561,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24562,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24567,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24569,
+ 0,
+ 0,
+ 0,
+ 24574,
+ 0,
+ 24575,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24577,
+ 24581,
+ 0,
+ 24584,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24585,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24586,
+ 0,
+ 0,
+ 24587,
+ 0,
+ 24588,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24590,
+ 24591,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24592,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24594,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24596,
+ 24597,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24602,
+ 24603,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24604,
+ 0,
+ 0,
+ 24605,
+ 0,
+ 24610,
+ 0,
+ 0,
+ 24611,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24612,
+ 24615,
+ 24616,
+ 24624,
+ 0,
+ 0,
+ 0,
+ 24627,
+ 0,
+ 24638,
+ 24639,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24640,
+ 0,
+ 0,
+ 0,
+ 24655,
+ 24656,
+ 24657,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24662,
+ 0,
+ 24663,
+ 24664,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24665,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24667,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24668,
+ 24669,
+ 0,
+ 24670,
+ 24674,
+ 0,
+ 0,
+ 0,
+ 24675,
+ 0,
+ 24678,
+ 0,
+ 0,
+ 24679,
+ 0,
+ 0,
+ 0,
+ 24681,
+ 0,
+ 24683,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24684,
+ 0,
+ 24685,
+ 0,
+ 0,
+ 24686,
+ 0,
+ 0,
+ 24688,
+ 24689,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24690,
+ 24691,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24697,
+ 0,
+ 24698,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24709,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24710,
+ 0,
+ 24712,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24713,
+ 24714,
+ 0,
+ 24715,
+ 0,
+ 24716,
+ 24718,
+ 0,
+ 24719,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24720,
+ 0,
+ 0,
+ 24725,
+ 0,
+ 0,
+ 24738,
+ 0,
+ 24749,
+ 24750,
+ 0,
+ 0,
+ 0,
+ 24752,
+ 0,
+ 0,
+ 0,
+ 24753,
+ 0,
+ 0,
+ 0,
+ 24758,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24762,
+ 0,
+ 24763,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24764,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24765,
+ 24767,
+ 24768,
+ 0,
+ 24772,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24773,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24777,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24785,
+ 0,
+ 24786,
+ 24788,
+ 0,
+ 0,
+ 0,
+ 24789,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24794,
+ 24798,
+ 0,
+ 24799,
+ 24800,
+ 0,
+ 0,
+ 0,
+ 24803,
+ 0,
+ 24804,
+ 24806,
+ 0,
+ 24807,
+ 0,
+ 0,
+ 0,
+ 24810,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24827,
+ 24828,
+ 0,
+ 24835,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24836,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24839,
+ 0,
+ 24843,
+ 24844,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24847,
+ 0,
+ 0,
+ 24848,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24849,
+ 0,
+ 24850,
+ 24851,
+ 0,
+ 0,
+ 0,
+ 24852,
+ 0,
+ 24853,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24854,
+ 0,
+ 24855,
+ 0,
+ 0,
+ 24868,
+ 0,
+ 0,
+ 0,
+ 24883,
+ 0,
+ 0,
+ 0,
+ 24884,
+ 0,
+ 24895,
+ 24897,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24899,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24900,
+ 0,
+ 24913,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24914,
+ 0,
+ 0,
+ 24917,
+ 24930,
+ 24931,
+ 0,
+ 0,
+ 0,
+ 24932,
+ 0,
+ 0,
+ 24939,
+ 0,
+ 0,
+ 24942,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24945,
+ 24950,
+ 0,
+ 24951,
+ 0,
+ 0,
+ 24953,
+ 0,
+ 0,
+ 0,
+ 24954,
+ 0,
+ 24959,
+ 0,
+ 0,
+ 0,
+ 24961,
+ 0,
+ 0,
+ 24962,
+ 0,
+ 24964,
+ 24968,
+ 24970,
+ 24972,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24976,
+ 0,
+ 0,
+ 0,
+ 24977,
+ 0,
+ 24982,
+ 0,
+ 0,
+ 24983,
+ 0,
+ 0,
+ 24984,
+ 0,
+ 0,
+ 0,
+ 24993,
+ 0,
+ 0,
+ 0,
+ 24994,
+ 0,
+ 0,
+ 25001,
+ 0,
+ 0,
+ 0,
+ 25003,
+ 0,
+ 0,
+ 25018,
+ 0,
+ 0,
+ 25023,
+ 0,
+ 0,
+ 0,
+ 25034,
+ 0,
+ 0,
+ 25035,
+ 25036,
+ 0,
+ 25037,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25039,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25040,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25042,
+ 0,
+ 0,
+ 25043,
+ 25045,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25049,
+ 0,
+ 0,
+ 25051,
+ 0,
+ 25052,
+ 25053,
+ 0,
+ 0,
+ 25054,
+ 0,
+ 0,
+ 0,
+ 25055,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25057,
+ 25059,
+ 0,
+ 0,
+ 25060,
+ 25064,
+ 0,
+ 25065,
+ 25069,
+ 25070,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25072,
+ 0,
+ 25073,
+ 0,
+ 25090,
+ 0,
+ 0,
+ 25092,
+ 25093,
+ 25101,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25105,
+ 25108,
+ 0,
+ 0,
+ 25113,
+ 0,
+ 0,
+ 25115,
+ 25116,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25117,
+ 0,
+ 0,
+ 0,
+ 25120,
+ 25121,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25125,
+ 0,
+ 0,
+ 0,
+ 25126,
+ 0,
+ 25130,
+ 25134,
+ 0,
+ 25139,
+ 0,
+ 25143,
+ 0,
+ 0,
+ 0,
+ 25151,
+ 0,
+ 25161,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25163,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25174,
+ 0,
+ 25175,
+ 0,
+ 25207,
+ 0,
+ 0,
+ 0,
+ 25209,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25213,
+ 0,
+ 25219,
+ 0,
+ 25223,
+ 0,
+ 25225,
+ 0,
+ 0,
+ 0,
+ 25227,
+ 0,
+ 0,
+ 0,
+ 25228,
+ 0,
+ 0,
+ 0,
+ 25229,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25231,
+ 25233,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25237,
+ 25239,
+ 0,
+ 0,
+ 0,
+ 25243,
+ 0,
+ 0,
+ 0,
+ 25252,
+ 0,
+ 25257,
+ 25258,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25260,
+ 25265,
+ 0,
+ 25268,
+ 0,
+ 0,
+ 25273,
+ 25324,
+ 0,
+ 25325,
+ 0,
+ 25326,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25327,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25328,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25332,
+ 0,
+ 0,
+ 0,
+ 25333,
+ 0,
+ 0,
+ 0,
+ 25336,
+ 25337,
+ 25338,
+ 0,
+ 0,
+ 25343,
+ 0,
+ 25350,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25352,
+ 0,
+ 25354,
+ 0,
+ 25375,
+ 0,
+ 25379,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25384,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25386,
+ 0,
+ 25388,
+ 0,
+ 25390,
+ 0,
+ 0,
+ 25399,
+ 0,
+ 0,
+ 25401,
+ 0,
+ 0,
+ 0,
+ 25402,
+ 0,
+ 0,
+ 0,
+ 25407,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25413,
+ 25415,
+ 0,
+ 0,
+ 25417,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25419,
+ 0,
+ 0,
+ 0,
+ 25421,
+ 0,
+ 0,
+ 0,
+ 25424,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25433,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25435,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25436,
+ 0,
+ 0,
+ 0,
+ 25437,
+ 0,
+ 0,
+ 25440,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25442,
+ 0,
+ 0,
+ 25443,
+ 0,
+ 25446,
+ 0,
+ 0,
+ 25449,
+ 0,
+ 0,
+ 0,
+ 25450,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25452,
+ 0,
+ 25453,
+ 25454,
+ 25455,
+ 0,
+ 0,
+ 0,
+ 25456,
+ 0,
+ 25457,
+ 0,
+ 0,
+ 0,
+ 25459,
+ 0,
+ 25461,
+ 0,
+ 25468,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25469,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25471,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25474,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25475,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25477,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25483,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25484,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25485,
+ 0,
+ 25497,
+ 0,
+ 0,
+ 25498,
+ 0,
+ 25504,
+ 0,
+ 25510,
+ 0,
+ 25512,
+ 0,
+ 0,
+ 25513,
+ 25514,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25517,
+ 25518,
+ 25519,
+ 0,
+ 25520,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25521,
+ 0,
+ 25522,
+ 25527,
+ 25534,
+ 0,
+ 25536,
+ 0,
+ 25537,
+ 0,
+ 0,
+ 25548,
+ 25550,
+ 0,
+ 0,
+ 25551,
+ 0,
+ 25552,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25554,
+ 0,
+ 25555,
+ 0,
+ 25556,
+ 25557,
+ 25568,
+ 0,
+ 0,
+ 0,
+ 25570,
+ 25571,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25574,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25579,
+ 0,
+ 0,
+ 0,
+ 25581,
+ 0,
+ 0,
+ 0,
+ 25582,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25588,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25589,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25590,
+ 0,
+ 25591,
+ 25592,
+ 25593,
+ 0,
+ 25594,
+ 0,
+ 0,
+ 0,
+ 25596,
+ 0,
+ 25597,
+ 25615,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25618,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25619,
+ 25623,
+ 0,
+ 0,
+ 25629,
+ 0,
+ 0,
+ 25631,
+ 0,
+ 0,
+ 0,
+ 25635,
+ 25636,
+ 0,
+ 0,
+ 25649,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25654,
+ 0,
+ 0,
+ 0,
+ 25661,
+ 25663,
+ 0,
+ 0,
+ 25671,
+ 0,
+ 0,
+ 25678,
+ 25698,
+ 0,
+ 25699,
+ 25702,
+ 25703,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25704,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25706,
+ 0,
+ 0,
+ 25710,
+ 0,
+ 25711,
+ 0,
+ 25712,
+ 0,
+ 25715,
+ 25716,
+ 25717,
+ 0,
+ 0,
+ 25718,
+ 25728,
+ 25732,
+ 0,
+ 0,
+ 0,
+ 25734,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25737,
+ 0,
+ 0,
+ 25739,
+ 0,
+ 0,
+ 0,
+ 25740,
+ 0,
+ 25741,
+ 25745,
+ 0,
+ 25746,
+ 0,
+ 25748,
+ 25772,
+ 25778,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25780,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25781,
+ 0,
+ 25782,
+ 25784,
+ 25785,
+ 0,
+ 0,
+ 0,
+ 25789,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25797,
+ 25801,
+ 0,
+ 0,
+ 0,
+ 25808,
+ 25809,
+ 0,
+ 0,
+ 25811,
+ 25814,
+ 25815,
+ 0,
+ 0,
+ 25817,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25820,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25832,
+ 25833,
+ 0,
+ 0,
+ 0,
+ 25846,
+ 0,
+ 0,
+ 0,
+ 25847,
+ 25848,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25849,
+ 25850,
+ 0,
+ 0,
+ 25851,
+ 0,
+ 0,
+ 25852,
+ 0,
+ 25862,
+ 0,
+ 0,
+ 0,
+ 25863,
+ 25865,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25867,
+ 25868,
+ 0,
+ 25869,
+ 25874,
+ 0,
+ 25875,
+ 0,
+ 25876,
+ 25877,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25878,
+ 25902,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25903,
+ 25904,
+ 25905,
+ 0,
+ 0,
+ 0,
+ 25908,
+ 25909,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25910,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25912,
+ 0,
+ 25913,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25914,
+ 0,
+ 0,
+ 25916,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25917,
+ 25927,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25928,
+ 0,
+ 0,
+ 25930,
+ 0,
+ 0,
+ 0,
+ 25933,
+ 0,
+ 0,
+ 25938,
+ 25942,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25945,
+ 0,
+ 25950,
+ 0,
+ 25956,
+ 0,
+ 0,
+ 25961,
+ 25962,
+ 0,
+ 0,
+ 25963,
+ 0,
+ 25964,
+ 25965,
+ 25966,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25967,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25968,
+ 0,
+ 0,
+ 0,
+ 25969,
+ 25971,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25973,
+ 25975,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25978,
+ 0,
+ 25981,
+ 0,
+ 0,
+ 0,
+ 25982,
+ 0,
+ 0,
+ 0,
+ 25984,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25993,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26002,
+ 0,
+ 0,
+ 0,
+ 26005,
+ 0,
+ 0,
+ 0,
+ 26006,
+ 26007,
+ 0,
+ 0,
+ 26014,
+ 26015,
+ 26016,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26017,
+ 26018,
+ 26020,
+ 0,
+ 26022,
+ 26023,
+ 0,
+ 0,
+ 0,
+ 26024,
+ 26028,
+ 0,
+ 26029,
+ 26033,
+ 26034,
+ 26044,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26046,
+ 0,
+ 0,
+ 26047,
+ 0,
+ 0,
+ 26049,
+ 0,
+ 26050,
+ 0,
+ 26051,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26053,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26054,
+ 26059,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26060,
+ 0,
+ 26066,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26067,
+ 0,
+ 26069,
+ 0,
+ 0,
+ 26071,
+ 0,
+ 0,
+ 0,
+ 26073,
+ 0,
+ 26074,
+ 26077,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26078,
+ 0,
+ 0,
+ 0,
+ 26079,
+ 0,
+ 26090,
+ 0,
+ 0,
+ 26094,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26095,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26096,
+ 26101,
+ 0,
+ 26107,
+ 26122,
+ 0,
+ 26124,
+ 0,
+ 0,
+ 26125,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26136,
+ 26141,
+ 26155,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26164,
+ 26166,
+ 0,
+ 0,
+ 0,
+ 26167,
+ 0,
+ 26170,
+ 26171,
+ 0,
+ 0,
+ 26172,
+ 0,
+ 0,
+ 26174,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26175,
+ 0,
+ 0,
+ 0,
+ 26176,
+ 26177,
+ 0,
+ 26321,
+ 26322,
+ 0,
+ 26323,
+ 0,
+ 0,
+ 26324,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26325,
+ 0,
+ 26331,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26335,
+ 0,
+ 0,
+ 0,
+ 26350,
+ 0,
+ 0,
+ 0,
+ 26379,
+ 0,
+ 0,
+ 26382,
+ 26383,
+ 26385,
+ 0,
+ 0,
+ 26392,
+ 26406,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26411,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26412,
+ 0,
+ 0,
+ 26420,
+ 0,
+ 0,
+ 26423,
+ 0,
+ 26424,
+ 26426,
+ 26432,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26435,
+ 0,
+ 26436,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26441,
+ 0,
+ 26444,
+ 0,
+ 0,
+ 0,
+ 26446,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26447,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26449,
+ 0,
+ 26450,
+ 26452,
+ 0,
+ 26453,
+ 26454,
+ 0,
+ 0,
+ 0,
+ 26455,
+ 0,
+ 0,
+ 0,
+ 26456,
+ 0,
+ 0,
+ 26458,
+ 0,
+ 0,
+ 26460,
+ 0,
+ 26463,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26464,
+ 26470,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26473,
+ 0,
+ 0,
+ 26474,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26475,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26477,
+ 0,
+ 26485,
+ 0,
+ 0,
+ 26486,
+ 0,
+ 26487,
+ 0,
+ 0,
+ 26488,
+ 26493,
+ 26494,
+ 0,
+ 0,
+ 26495,
+ 0,
+ 26497,
+ 26504,
+ 26506,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26507,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26509,
+ 0,
+ 0,
+ 26510,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26512,
+ 0,
+ 26513,
+ 26515,
+ 0,
+ 0,
+ 0,
+ 26518,
+ 0,
+ 0,
+ 0,
+ 26519,
+ 0,
+ 26524,
+ 26526,
+ 0,
+ 0,
+ 0,
+ 26527,
+ 0,
+ 26532,
+ 0,
+ 26533,
+ 26537,
+ 26558,
+ 0,
+ 0,
+ 0,
+ 26559,
+ 0,
+ 0,
+ 0,
+ 26571,
+ 0,
+ 0,
+ 26573,
+ 0,
+ 26588,
+ 0,
+ 26593,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26603,
+ 0,
+ 26604,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26606,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26607,
+ 26609,
+ 26611,
+ 26614,
+ 0,
+ 0,
+ 0,
+ 26616,
+ 26620,
+ 0,
+ 26621,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26627,
+ 0,
+ 26629,
+ 0,
+ 0,
+ 26630,
+ 0,
+ 0,
+ 26632,
+ 26643,
+ 0,
+ 0,
+ 0,
+ 26644,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26646,
+ 26647,
+ 0,
+ 0,
+ 0,
+ 26650,
+ 0,
+ 0,
+ 26656,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26663,
+ 26670,
+ 26671,
+ 0,
+ 0,
+ 0,
+ 26685,
+ 26686,
+ 26687,
+ 0,
+ 26689,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26744,
+ 0,
+ 26745,
+ 0,
+ 26747,
+ 26748,
+ 0,
+ 26749,
+ 26750,
+ 26751,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26752,
+ 26755,
+ 0,
+ 0,
+ 0,
+ 26756,
+ 26769,
+ 0,
+ 0,
+ 0,
+ 26774,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26775,
+ 0,
+ 26777,
+ 26778,
+ 0,
+ 26786,
+ 0,
+ 0,
+ 0,
+ 26787,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26788,
+ 0,
+ 0,
+ 26789,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26791,
+ 0,
+ 26792,
+ 26793,
+ 0,
+ 0,
+ 0,
+ 26794,
+ 0,
+ 26797,
+ 26798,
+ 0,
+ 0,
+ 0,
+ 26800,
+ 0,
+ 0,
+ 26803,
+ 0,
+ 26804,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26805,
+ 0,
+ 0,
+ 26808,
+ 0,
+ 0,
+ 26809,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26812,
+ 0,
+ 26825,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26826,
+ 0,
+ 0,
+ 26827,
+ 26829,
+ 26834,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26835,
+ 0,
+ 0,
+ 26849,
+ 0,
+ 26851,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26852,
+ 0,
+ 26853,
+ 26857,
+ 0,
+ 26858,
+ 0,
+ 26859,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26876,
+ 0,
+ 26878,
+ 26882,
+ 26883,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26890,
+ 26894,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26895,
+ 26896,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26900,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26911,
+ 26913,
+ 26914,
+ 26915,
+ 26916,
+ 26919,
+ 0,
+ 0,
+ 0,
+ 26921,
+ 26922,
+ 0,
+ 0,
+ 26925,
+ 0,
+ 0,
+ 0,
+ 26928,
+ 0,
+ 0,
+ 26929,
+ 26930,
+ 0,
+ 0,
+ 0,
+ 26931,
+ 0,
+ 26932,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26933,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26937,
+ 0,
+ 0,
+ 26943,
+ 0,
+ 0,
+ 26944,
+ 0,
+ 0,
+ 0,
+ 26946,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26956,
+ 0,
+ 26958,
+ 0,
+ 0,
+ 26963,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26965,
+ 0,
+ 26969,
+ 26970,
+ 26972,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26973,
+ 0,
+ 26974,
+ 0,
+ 26978,
+ 0,
+ 26980,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26982,
+ 0,
+ 26986,
+ 26987,
+ 0,
+ 26990,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27003,
+ 27006,
+ 0,
+ 0,
+ 27007,
+ 27010,
+ 27012,
+ 27013,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27014,
+ 27015,
+ 27018,
+ 0,
+ 27019,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27025,
+ 0,
+ 0,
+ 0,
+ 27026,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27029,
+ 27030,
+ 27031,
+ 27034,
+ 0,
+ 0,
+ 27036,
+ 27037,
+ 0,
+ 0,
+ 0,
+ 27038,
+ 27042,
+ 0,
+ 0,
+ 0,
+ 27044,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27045,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27046,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27047,
+ 27049,
+ 0,
+ 27050,
+ 0,
+ 0,
+ 0,
+ 27051,
+ 27052,
+ 0,
+ 27055,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27056,
+ 27058,
+ 27059,
+ 0,
+ 27061,
+ 0,
+ 27064,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27069,
+ 0,
+ 0,
+ 27070,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27072,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27076,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27078,
+ 0,
+ 27079,
+ 0,
+ 0,
+ 0,
+ 27081,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27082,
+ 0,
+ 27083,
+ 27086,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27087,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27088,
+ 27090,
+ 0,
+ 27094,
+ 0,
+ 0,
+ 27095,
+ 0,
+ 27099,
+ 27102,
+ 0,
+ 0,
+ 0,
+ 27103,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27105,
+ 0,
+ 0,
+ 0,
+ 27106,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27107,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27108,
+ 27117,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27118,
+ 0,
+ 0,
+ 27124,
+ 0,
+ 27126,
+ 0,
+ 0,
+ 27130,
+ 27131,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27147,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27148,
+ 27149,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27150,
+ 27151,
+ 0,
+ 27152,
+ 0,
+ 27159,
+ 0,
+ 0,
+ 0,
+ 27164,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27175,
+ 0,
+ 27189,
+ 0,
+ 0,
+ 27191,
+ 0,
+ 27193,
+ 0,
+ 27195,
+ 0,
+ 27198,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27200,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27202,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27203,
+ 0,
+ 0,
+ 27204,
+ 0,
+ 0,
+ 27206,
+ 0,
+ 27207,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27209,
+ 0,
+ 0,
+ 0,
+ 27213,
+ 0,
+ 0,
+ 27216,
+ 27219,
+ 27220,
+ 27222,
+ 27223,
+ 0,
+ 27224,
+ 0,
+ 27225,
+ 27226,
+ 0,
+ 0,
+ 27233,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27235,
+ 0,
+ 27237,
+ 0,
+ 27238,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27239,
+ 0,
+ 27242,
+ 27243,
+ 0,
+ 27250,
+ 0,
+ 0,
+ 0,
+ 27251,
+ 0,
+ 27253,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27254,
+ 27255,
+ 27258,
+ 0,
+ 0,
+ 0,
+ 27259,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27267,
+ 0,
+ 27276,
+ 27278,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27296,
+ 27297,
+ 27301,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27302,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27312,
+ 27313,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27318,
+ 0,
+ 27320,
+ 0,
+ 27329,
+ 0,
+ 27330,
+ 27331,
+ 0,
+ 27332,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27340,
+ 0,
+ 0,
+ 0,
+ 27348,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27350,
+ 0,
+ 27351,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27355,
+ 0,
+ 0,
+ 27358,
+ 27359,
+ 27361,
+ 0,
+ 0,
+ 0,
+ 27365,
+ 0,
+ 27367,
+ 0,
+ 27376,
+ 27378,
+ 0,
+ 0,
+ 27379,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27396,
+ 0,
+ 27397,
+ 27404,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27408,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27453,
+ 0,
+ 0,
+ 0,
+ 27456,
+ 0,
+ 0,
+ 0,
+ 27458,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27459,
+ 0,
+ 0,
+ 0,
+ 27460,
+ 0,
+ 0,
+ 27461,
+ 0,
+ 27465,
+ 27467,
+ 0,
+ 0,
+ 27469,
+ 0,
+ 27470,
+ 0,
+ 27471,
+ 0,
+ 27477,
+ 27482,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27484,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27485,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27493,
+ 0,
+ 27494,
+ 27502,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27511,
+ 27532,
+ 0,
+ 0,
+ 0,
+ 27533,
+ 27545,
+ 0,
+ 0,
+ 0,
+ 27546,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27547,
+ 0,
+ 0,
+ 27549,
+ 27550,
+ 0,
+ 27551,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27555,
+ 0,
+ 0,
+ 27571,
+ 0,
+ 27573,
+ 27574,
+ 27575,
+ 27577,
+ 0,
+ 27578,
+ 0,
+ 0,
+ 27579,
+ 27585,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27586,
+ 0,
+ 0,
+ 27588,
+ 27589,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27596,
+ 0,
+ 0,
+ 27600,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27608,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27610,
+ 0,
+ 0,
+ 0,
+ 27618,
+ 0,
+ 0,
+ 27620,
+ 0,
+ 0,
+ 0,
+ 27631,
+ 0,
+ 0,
+ 27632,
+ 27634,
+ 0,
+ 27636,
+ 27638,
+ 0,
+ 0,
+ 0,
+ 27643,
+ 0,
+ 27644,
+ 27649,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27651,
+ 27660,
+ 0,
+ 27661,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27662,
+ 0,
+ 0,
+ 27664,
+ 0,
+ 27665,
+ 0,
+ 0,
+ 0,
+ 27669,
+ 0,
+ 27671,
+ 0,
+ 0,
+ 0,
+ 27673,
+ 27674,
+ 0,
+ 0,
+ 0,
+ 27682,
+ 0,
+ 0,
+ 0,
+ 27711,
+ 0,
+ 27712,
+ 27713,
+ 27719,
+ 27720,
+ 0,
+ 0,
+ 27728,
+ 0,
+ 27729,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27731,
+ 0,
+ 0,
+ 27732,
+ 0,
+ 27733,
+ 0,
+ 27738,
+ 0,
+ 0,
+ 0,
+ 27742,
+ 0,
+ 0,
+ 0,
+ 27743,
+ 27744,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27745,
+ 27746,
+ 0,
+ 0,
+ 0,
+ 27747,
+ 27748,
+ 27751,
+ 27752,
+ 0,
+ 0,
+ 0,
+ 27768,
+ 27770,
+ 0,
+ 0,
+ 0,
+ 27774,
+ 27775,
+ 0,
+ 27776,
+ 27777,
+ 0,
+ 0,
+ 27781,
+ 0,
+ 27784,
+ 0,
+ 27786,
+ 0,
+ 0,
+ 27791,
+ 0,
+ 27792,
+ 27793,
+ 27804,
+ 0,
+ 27812,
+ 27813,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27814,
+ 0,
+ 27825,
+ 0,
+ 27827,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27828,
+ 27861,
+ 27862,
+ 0,
+ 0,
+ 0,
+ 27864,
+ 0,
+ 0,
+ 0,
+ 27865,
+ 27884,
+ 0,
+ 27889,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27890,
+ 0,
+ 27891,
+ 0,
+ 0,
+ 0,
+ 27892,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27897,
+ 27898,
+ 0,
+ 0,
+ 27899,
+ 0,
+ 0,
+ 0,
+ 27901,
+ 27905,
+ 0,
+ 0,
+ 27920,
+ 0,
+ 0,
+ 27921,
+ 0,
+ 27922,
+ 0,
+ 0,
+ 0,
+ 27931,
+ 27934,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27941,
+ 0,
+ 27942,
+ 0,
+ 27945,
+ 0,
+ 27947,
+ 27954,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27960,
+ 27963,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27964,
+ 27965,
+ 0,
+ 0,
+ 0,
+ 27967,
+ 0,
+ 27969,
+ 27975,
+ 0,
+ 27976,
+ 27977,
+ 0,
+ 27981,
+ 0,
+ 27983,
+ 28051,
+ 28052,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28056,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28058,
+ 28059,
+ 0,
+ 0,
+ 28061,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28063,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28066,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28069,
+ 28070,
+ 28072,
+ 0,
+ 28073,
+ 0,
+ 0,
+ 28074,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28075,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28078,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28085,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28086,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28088,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28090,
+ 0,
+ 28097,
+ 28114,
+ 28115,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28116,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28118,
+ 0,
+ 28129,
+ 0,
+ 28131,
+ 0,
+ 0,
+ 28135,
+ 0,
+ 0,
+ 0,
+ 28140,
+ 28141,
+ 0,
+ 0,
+ 0,
+ 28146,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28152,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28155,
+ 28157,
+ 28161,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28166,
+ 0,
+ 28167,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28172,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28173,
+ 0,
+ 0,
+ 28175,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28178,
+ 28188,
+ 0,
+ 28190,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28191,
+ 0,
+ 28193,
+ 28206,
+ 0,
+ 0,
+ 28207,
+ 28209,
+ 0,
+ 28211,
+ 0,
+ 28213,
+ 0,
+ 0,
+ 0,
+ 28215,
+ 28216,
+ 28217,
+ 0,
+ 28222,
+ 0,
+ 28223,
+ 28225,
+ 0,
+ 0,
+ 0,
+ 28226,
+ 0,
+ 28227,
+ 28229,
+ 28232,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28235,
+ 0,
+ 28241,
+ 0,
+ 0,
+ 28242,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28243,
+ 0,
+ 0,
+ 0,
+ 28245,
+ 0,
+ 0,
+ 0,
+ 28248,
+ 28250,
+ 0,
+ 28251,
+ 28252,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28253,
+ 0,
+ 0,
+ 28254,
+ 28255,
+ 0,
+ 0,
+ 28256,
+ 0,
+ 0,
+ 28258,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28259,
+ 0,
+ 0,
+ 28260,
+ 0,
+ 0,
+ 28261,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28262,
+ 28263,
+ 0,
+ 0,
+ 28264,
+ 0,
+ 0,
+ 0,
+ 28266,
+ 0,
+ 28268,
+ 28269,
+ 0,
+ 28270,
+ 28272,
+ 28274,
+ 0,
+ 28277,
+ 28278,
+ 0,
+ 0,
+ 0,
+ 28279,
+ 0,
+ 28280,
+ 28281,
+ 28283,
+ 0,
+ 28292,
+ 0,
+ 28294,
+ 0,
+ 28297,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28299,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28300,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28301,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28302,
+ 28303,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28304,
+ 0,
+ 0,
+ 28305,
+ 0,
+ 28312,
+ 0,
+ 28313,
+ 28314,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28315,
+ 0,
+ 0,
+ 0,
+ 28320,
+ 28321,
+ 0,
+ 0,
+ 28328,
+ 0,
+ 0,
+ 0,
+ 28329,
+ 28338,
+ 0,
+ 28339,
+ 0,
+ 0,
+ 28344,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28347,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28348,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28411,
+ 0,
+ 28412,
+ 28413,
+ 0,
+ 28416,
+ 0,
+ 0,
+ 0,
+ 28420,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28421,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28423,
+ 0,
+ 0,
+ 0,
+ 28424,
+ 0,
+ 0,
+ 28428,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28429,
+ 0,
+ 0,
+ 0,
+ 28431,
+ 28434,
+ 0,
+ 28458,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28464,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28465,
+ 0,
+ 28467,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28471,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28474,
+ 0,
+ 28480,
+ 0,
+ 28481,
+ 0,
+ 0,
+ 28485,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28486,
+ 28488,
+ 0,
+ 0,
+ 28489,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28492,
+ 0,
+ 0,
+ 0,
+ 28495,
+ 0,
+ 28497,
+ 0,
+ 28499,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28500,
+ 0,
+ 0,
+ 28502,
+ 28503,
+ 0,
+ 0,
+ 0,
+ 28508,
+ 0,
+ 0,
+ 0,
+ 28510,
+ 0,
+ 0,
+ 28512,
+ 28513,
+ 28514,
+ 28521,
+ 0,
+ 28526,
+ 0,
+ 28527,
+ 28528,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28529,
+ 0,
+ 0,
+ 28532,
+ 0,
+ 0,
+ 28537,
+ 28538,
+ 0,
+ 0,
+ 0,
+ 28539,
+ 0,
+ 28548,
+ 0,
+ 28553,
+ 28554,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28560,
+ 28563,
+ 0,
+ 0,
+ 28564,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28565,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28566,
+ 28568,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28569,
+ 0,
+ 0,
+ 0,
+ 28570,
+ 0,
+ 28572,
+ 28573,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28575,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28576,
+ 28581,
+ 28588,
+ 0,
+ 0,
+ 28589,
+ 0,
+ 0,
+ 0,
+ 28590,
+ 28595,
+ 0,
+ 28598,
+ 0,
+ 0,
+ 28601,
+ 0,
+ 0,
+ 28605,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28614,
+ 28615,
+ 28619,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28620,
+ 0,
+ 28626,
+ 0,
+ 0,
+ 28628,
+ 0,
+ 28631,
+ 0,
+ 28632,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28635,
+ 0,
+ 0,
+ 0,
+ 28637,
+ 28638,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28639,
+ 0,
+ 28643,
+ 0,
+ 0,
+ 28652,
+ 0,
+ 0,
+ 0,
+ 28662,
+ 0,
+ 28670,
+ 28671,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28672,
+ 28673,
+ 28675,
+ 28676,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28691,
+ 0,
+ 0,
+ 0,
+ 28695,
+ 0,
+ 0,
+ 0,
+ 28696,
+ 0,
+ 28697,
+ 28698,
+ 0,
+ 28705,
+ 0,
+ 28707,
+ 28708,
+ 28710,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28711,
+ 28728,
+ 0,
+ 0,
+ 0,
+ 28736,
+ 0,
+ 0,
+ 0,
+ 28737,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28738,
+ 0,
+ 28739,
+ 0,
+ 28741,
+ 0,
+ 0,
+ 28742,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28745,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28749,
+ 28750,
+ 28752,
+ 28754,
+ 28756,
+ 0,
+ 28757,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28759,
+ 28760,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28762,
+ 0,
+ 0,
+ 0,
+ 28764,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28766,
+ 0,
+ 28767,
+ 28768,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28769,
+ 28770,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28771,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28772,
+ 0,
+ 28773,
+ 0,
+ 28782,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28784,
+ 0,
+ 28785,
+ 0,
+ 28786,
+ 0,
+ 0,
+ 0,
+ 28787,
+ 0,
+ 0,
+ 0,
+ 28797,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28799,
+ 0,
+ 0,
+ 28801,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28802,
+ 0,
+ 28805,
+ 0,
+ 0,
+ 28806,
+ 0,
+ 0,
+ 28807,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28808,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28810,
+ 28812,
+ 0,
+ 0,
+ 28816,
+ 28819,
+ 0,
+ 0,
+ 28821,
+ 0,
+ 28826,
+ 0,
+ 0,
+ 0,
+ 28842,
+ 28852,
+ 0,
+ 0,
+ 28853,
+ 0,
+ 28854,
+ 28855,
+ 0,
+ 0,
+ 0,
+ 28857,
+ 0,
+ 0,
+ 0,
+ 28858,
+ 0,
+ 28867,
+ 28868,
+ 28869,
+ 0,
+ 0,
+ 0,
+ 28874,
+ 28880,
+ 28882,
+ 28890,
+ 28892,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28895,
+ 0,
+ 0,
+ 0,
+ 28898,
+ 28899,
+ 0,
+ 0,
+ 0,
+ 28900,
+ 0,
+ 0,
+ 28904,
+ 0,
+ 28906,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28907,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28908,
+ 0,
+ 0,
+ 0,
+ 28910,
+ 0,
+ 28914,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28915,
+ 28916,
+ 28919,
+ 0,
+ 0,
+ 28920,
+ 0,
+ 28921,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28924,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28926,
+ 28929,
+ 0,
+ 0,
+ 0,
+ 28930,
+ 0,
+ 28936,
+ 0,
+ 28939,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28942,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28956,
+ 0,
+ 0,
+ 0,
+ 28966,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28967,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28968,
+ 0,
+ 28971,
+ 0,
+ 28975,
+ 28976,
+ 0,
+ 28982,
+ 28983,
+ 0,
+ 0,
+ 28984,
+ 28989,
+ 28996,
+ 28997,
+ 28998,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28999,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29000,
+ 0,
+ 29001,
+ 0,
+ 0,
+ 0,
+ 29009,
+ 0,
+ 0,
+ 29011,
+ 0,
+ 0,
+ 29021,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29024,
+ 0,
+ 29025,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29026,
+ 0,
+ 0,
+ 0,
+ 29036,
+ 0,
+ 0,
+ 0,
+ 29037,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29038,
+ 0,
+ 29045,
+ 0,
+ 29047,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29051,
+ 0,
+ 0,
+ 0,
+ 29054,
+ 29056,
+ 29062,
+ 0,
+ 29070,
+ 29082,
+ 0,
+ 0,
+ 0,
+ 29083,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29084,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29085,
+ 29088,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29090,
+ 29097,
+ 0,
+ 0,
+ 0,
+ 29103,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29105,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29107,
+ 0,
+ 29109,
+ 0,
+ 0,
+ 0,
+ 29115,
+ 0,
+ 0,
+ 29120,
+ 0,
+ 0,
+ 29138,
+ 29140,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29152,
+ 0,
+ 29160,
+ 29174,
+ 0,
+ 29176,
+ 0,
+ 0,
+ 29180,
+ 0,
+ 29181,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29228,
+ 0,
+ 0,
+ 29229,
+ 0,
+ 0,
+ 29230,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29234,
+ 0,
+ 0,
+ 0,
+ 29241,
+ 0,
+ 29245,
+ 0,
+ 29248,
+ 0,
+ 29250,
+ 29256,
+ 29280,
+ 0,
+ 29282,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29285,
+ 0,
+ 0,
+ 29286,
+ 29291,
+ 29292,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29294,
+ 0,
+ 29295,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29296,
+ 29297,
+ 29298,
+ 29300,
+ 0,
+ 29302,
+ 0,
+ 0,
+ 29304,
+ 29307,
+ 0,
+ 29312,
+ 0,
+ 0,
+ 0,
+ 29322,
+ 0,
+ 0,
+ 29323,
+ 0,
+ 0,
+ 29324,
+ 29326,
+ 29328,
+ 0,
+ 29335,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29338,
+ 29339,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29341,
+ 29343,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29344,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29345,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29346,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29347,
+ 29348,
+ 29349,
+ 0,
+ 0,
+ 29354,
+ 0,
+ 0,
+ 29355,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29357,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29364,
+ 0,
+ 29365,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29366,
+ 0,
+ 0,
+ 29368,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29378,
+ 0,
+ 29381,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29386,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29389,
+ 0,
+ 0,
+ 0,
+ 29390,
+ 0,
+ 0,
+ 29391,
+ 29397,
+ 0,
+ 29398,
+ 29412,
+ 29414,
+ 29418,
+ 29419,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29420,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29423,
+ 0,
+ 0,
+ 0,
+ 29435,
+ 0,
+ 0,
+ 0,
+ 29437,
+ 0,
+ 0,
+ 29439,
+ 0,
+ 29441,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29443,
+ 0,
+ 29446,
+ 29450,
+ 29452,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29456,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29461,
+ 0,
+ 0,
+ 0,
+ 29464,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29468,
+ 0,
+ 29473,
+ 0,
+ 0,
+ 0,
+ 29486,
+ 0,
+ 0,
+ 0,
+ 29490,
+ 0,
+ 0,
+ 0,
+ 29491,
+ 29492,
+ 0,
+ 0,
+ 29497,
+ 0,
+ 0,
+ 0,
+ 29498,
+ 0,
+ 29499,
+ 0,
+ 29502,
+ 29505,
+ 0,
+ 29509,
+ 0,
+ 0,
+ 0,
+ 29510,
+ 0,
+ 0,
+ 0,
+ 29512,
+ 0,
+ 0,
+ 0,
+ 29516,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29518,
+ 0,
+ 29519,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29520,
+ 29521,
+ 29529,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29530,
+ 0,
+ 0,
+ 29531,
+ 29538,
+ 0,
+ 29540,
+ 0,
+ 0,
+ 0,
+ 29542,
+ 0,
+ 29543,
+ 29544,
+ 29547,
+ 0,
+ 0,
+ 29548,
+ 0,
+ 0,
+ 0,
+ 29549,
+ 0,
+ 0,
+ 0,
+ 29550,
+ 0,
+ 0,
+ 29552,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29558,
+ 29561,
+ 0,
+ 29562,
+ 29564,
+ 0,
+ 0,
+ 29565,
+ 0,
+ 0,
+ 29566,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29578,
+ 29584,
+ 29586,
+ 29591,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29593,
+ 29594,
+ 0,
+ 0,
+ 29597,
+ 0,
+ 0,
+ 29613,
+ 0,
+ 29614,
+ 0,
+ 29615,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29616,
+ 29617,
+ 0,
+ 0,
+ 29625,
+ 0,
+ 0,
+ 0,
+ 29632,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29633,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29634,
+ 29635,
+ 29637,
+ 0,
+ 29638,
+ 0,
+ 29641,
+ 29643,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29644,
+ 0,
+ 29645,
+ 0,
+ 29649,
+ 0,
+ 0,
+ 0,
+ 29650,
+ 0,
+ 29653,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29656,
+ 29659,
+ 0,
+ 0,
+ 29660,
+ 0,
+ 0,
+ 0,
+ 29661,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29664,
+ 0,
+ 0,
+ 0,
+ 29671,
+ 29673,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29675,
+ 0,
+ 29677,
+ 29679,
+ 0,
+ 0,
+ 29684,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29685,
+ 0,
+ 0,
+ 0,
+ 29687,
+ 0,
+ 0,
+ 0,
+ 29688,
+ 0,
+ 29689,
+ 29690,
+ 29700,
+ 0,
+ 29701,
+ 0,
+ 0,
+ 0,
+ 29702,
+ 0,
+ 29706,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29720,
+ 0,
+ 29721,
+ 0,
+ 29727,
+ 0,
+ 29733,
+ 29734,
+ 0,
+ 29750,
+ 29761,
+ 0,
+ 29763,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29764,
+ 0,
+ 0,
+ 29765,
+ 0,
+ 0,
+ 0,
+ 29771,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29772,
+ 0,
+ 0,
+ 0,
+ 29773,
+ 29774,
+ 29775,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29822,
+ 0,
+ 0,
+ 0,
+ 29824,
+ 0,
+ 29825,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29827,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29829,
+ 0,
+ 29832,
+ 29834,
+ 0,
+ 0,
+ 29835,
+ 0,
+ 0,
+ 29837,
+ 29838,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29843,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29844,
+ 29845,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29849,
+ 0,
+ 0,
+ 29869,
+ 29872,
+ 29890,
+ 29905,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29907,
+ 29921,
+ 0,
+ 29922,
+ 0,
+ 0,
+ 29923,
+ 29926,
+ 29944,
+ 29946,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29947,
+ 29948,
+ 0,
+ 0,
+ 0,
+ 29951,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29953,
+ 0,
+ 0,
+ 29956,
+ 0,
+ 29957,
+ 0,
+ 0,
+ 29962,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29971,
+ 0,
+ 0,
+ 0,
+ 29972,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29978,
+ 0,
+ 29979,
+ 29992,
+ 30007,
+ 30008,
+ 30010,
+ 0,
+ 0,
+ 0,
+ 30013,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30014,
+ 30016,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30017,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30023,
+ 30031,
+ 0,
+ 0,
+ 30033,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30034,
+ 0,
+ 30038,
+ 0,
+ 30039,
+ 0,
+ 30040,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30067,
+ 30068,
+ 0,
+ 0,
+ 0,
+ 30069,
+ 0,
+ 30072,
+ 0,
+ 0,
+ 0,
+ 30073,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30075,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30079,
+ 0,
+ 0,
+ 30080,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30082,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30084,
+ 30090,
+ 0,
+ 0,
+ 30091,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30098,
+ 30118,
+ 0,
+ 30119,
+ 0,
+ 30121,
+ 30130,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30131,
+ 30132,
+ 30133,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30135,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30136,
+ 0,
+ 0,
+ 30137,
+ 30138,
+ 0,
+ 0,
+ 0,
+ 30139,
+ 30146,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30147,
+ 0,
+ 0,
+ 30148,
+ 30151,
+ 0,
+ 0,
+ 0,
+ 30168,
+ 0,
+ 30172,
+ 30173,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30180,
+ 30181,
+ 0,
+ 30192,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30194,
+ 30196,
+ 0,
+ 0,
+ 30199,
+ 0,
+ 0,
+ 30202,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30203,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30213,
+ 0,
+ 0,
+ 0,
+ 30216,
+ 0,
+ 0,
+ 30217,
+ 0,
+ 0,
+ 0,
+ 30218,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30219,
+ 0,
+ 30220,
+ 0,
+ 30222,
+ 30227,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30231,
+ 0,
+ 0,
+ 30233,
+ 30235,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30238,
+ 0,
+ 30240,
+ 30243,
+ 30245,
+ 0,
+ 30250,
+ 30252,
+ 0,
+ 0,
+ 0,
+ 30269,
+ 0,
+ 0,
+ 30271,
+ 30272,
+ 0,
+ 0,
+ 0,
+ 30278,
+ 30280,
+ 0,
+ 0,
+ 30282,
+ 0,
+ 30284,
+ 0,
+ 30294,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30295,
+ 30296,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30298,
+ 30299,
+ 30302,
+ 30304,
+ 30306,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30316,
+ 30317,
+ 0,
+ 0,
+ 0,
+ 30318,
+ 0,
+ 0,
+ 0,
+ 30319,
+ 0,
+ 30320,
+ 30322,
+ 30326,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30327,
+ 0,
+ 30332,
+ 30348,
+ 30349,
+ 0,
+ 0,
+ 30356,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30357,
+ 0,
+ 30358,
+ 0,
+ 30359,
+ 30360,
+ 0,
+ 0,
+ 30365,
+ 30366,
+ 30378,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30379,
+ 0,
+ 0,
+ 30381,
+ 0,
+ 30385,
+ 0,
+ 30388,
+ 30397,
+ 0,
+ 0,
+ 0,
+ 30401,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30403,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30404,
+ 0,
+ 0,
+ 30405,
+ 0,
+ 30406,
+ 30408,
+ 0,
+ 30409,
+ 0,
+ 30410,
+ 0,
+ 0,
+ 0,
+ 30417,
+ 0,
+ 0,
+ 30418,
+ 30419,
+ 0,
+ 30420,
+ 0,
+ 30424,
+ 0,
+ 0,
+ 0,
+ 30427,
+ 30430,
+ 30432,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30433,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30436,
+ 0,
+ 30437,
+ 30438,
+ 0,
+ 30441,
+ 30442,
+ 0,
+ 0,
+ 0,
+ 30445,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30452,
+ 30456,
+ 30457,
+ 0,
+ 0,
+ 0,
+ 30458,
+ 0,
+ 30464,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30467,
+ 0,
+ 30469,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30477,
+ 0,
+ 0,
+ 30484,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30485,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30486,
+ 30487,
+ 30497,
+ 30498,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30505,
+ 0,
+ 30508,
+ 0,
+ 0,
+ 0,
+ 30509,
+ 30510,
+ 0,
+ 30514,
+ 30516,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30523,
+ 0,
+ 30524,
+ 0,
+ 30525,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30537,
+ 0,
+ 0,
+ 30538,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30553,
+ 0,
+ 0,
+ 30555,
+ 30556,
+ 30558,
+ 30559,
+ 30560,
+ 0,
+ 0,
+ 30561,
+ 0,
+ 30562,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30563,
+ 30570,
+ 30571,
+ 0,
+ 30586,
+ 30587,
+ 0,
+ 0,
+ 30590,
+ 0,
+ 0,
+ 30594,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30611,
+ 30612,
+ 30623,
+ 30634,
+ 0,
+ 0,
+ 30636,
+ 30640,
+ 30655,
+ 30656,
+ 0,
+ 30657,
+ 0,
+ 0,
+ 30658,
+ 30669,
+ 0,
+ 30670,
+ 0,
+ 30676,
+ 30678,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30679,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30695,
+ 0,
+ 0,
+ 30698,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30700,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30701,
+ 0,
+ 30702,
+ 30703,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30707,
+ 0,
+ 0,
+ 0,
+ 30709,
+ 0,
+ 0,
+ 30710,
+ 30719,
+ 30729,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30731,
+ 0,
+ 0,
+ 30733,
+ 0,
+ 0,
+ 0,
+ 30734,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30736,
+ 30737,
+ 0,
+ 0,
+ 0,
+ 30740,
+ 0,
+ 0,
+ 0,
+ 30743,
+ 0,
+ 30746,
+ 0,
+ 30747,
+ 30748,
+ 0,
+ 0,
+ 30751,
+ 30752,
+ 30753,
+ 0,
+ 0,
+ 0,
+ 30754,
+ 0,
+ 0,
+ 30760,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30763,
+ 0,
+ 30764,
+ 0,
+ 0,
+ 30766,
+ 0,
+ 30769,
+ 30770,
+ 30771,
+ 30774,
+ 30777,
+ 0,
+ 0,
+ 30779,
+ 30780,
+ 30781,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30790,
+ 0,
+ 0,
+ 0,
+ 30792,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30810,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30812,
+ 30819,
+ 0,
+ 0,
+ 30823,
+ 30824,
+ 0,
+ 30825,
+ 0,
+ 30827,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30828,
+ 0,
+ 0,
+ 30830,
+ 0,
+ 0,
+ 0,
+ 30834,
+ 0,
+ 30835,
+ 0,
+ 30837,
+ 30838,
+ 0,
+ 30845,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30846,
+ 30847,
+ 0,
+ 0,
+ 30849,
+ 0,
+ 30851,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30852,
+ 30858,
+ 0,
+ 0,
+ 30859,
+ 0,
+ 30865,
+ 0,
+ 0,
+ 30866,
+ 0,
+ 0,
+ 30868,
+ 0,
+ 0,
+ 30869,
+ 0,
+ 0,
+ 0,
+ 30881,
+ 30883,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30889,
+ 0,
+ 30891,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30894,
+ 0,
+ 30895,
+ 0,
+ 30897,
+ 0,
+ 30898,
+ 0,
+ 0,
+ 0,
+ 30904,
+ 30906,
+ 0,
+ 30909,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30910,
+ 0,
+ 0,
+ 0,
+ 30915,
+ 30933,
+ 30942,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30943,
+ 0,
+ 0,
+ 30945,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30946,
+ 0,
+ 0,
+ 30947,
+ 0,
+ 0,
+ 30955,
+ 30956,
+ 0,
+ 0,
+ 30960,
+ 0,
+ 0,
+ 30961,
+ 30962,
+ 30966,
+ 0,
+ 0,
+ 30969,
+ 30974,
+ 0,
+ 0,
+ 0,
+ 30976,
+ 0,
+ 0,
+ 30977,
+ 0,
+ 30978,
+ 30982,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30994,
+ 30995,
+ 30998,
+ 0,
+ 31000,
+ 0,
+ 0,
+ 31001,
+ 0,
+ 0,
+ 31003,
+ 31005,
+ 0,
+ 0,
+ 31006,
+ 31011,
+ 0,
+ 0,
+ 31014,
+ 0,
+ 31016,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31018,
+ 0,
+ 0,
+ 31020,
+ 31023,
+ 31024,
+ 31025,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31027,
+ 31028,
+ 31029,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31032,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31036,
+ 31037,
+ 31038,
+ 0,
+ 0,
+ 0,
+ 31041,
+ 31043,
+ 31045,
+ 0,
+ 31047,
+ 0,
+ 0,
+ 0,
+ 31048,
+ 0,
+ 31049,
+ 0,
+ 0,
+ 0,
+ 31053,
+ 31054,
+ 31055,
+ 0,
+ 0,
+ 31063,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31066,
+ 0,
+ 31068,
+ 31071,
+ 0,
+ 0,
+ 0,
+ 31072,
+ 31073,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31075,
+ 0,
+ 0,
+ 31076,
+ 0,
+ 0,
+ 0,
+ 31077,
+ 31079,
+ 0,
+ 31080,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31087,
+ 0,
+ 31142,
+ 0,
+ 31144,
+ 0,
+ 0,
+ 31145,
+ 31146,
+ 31147,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31149,
+ 0,
+ 31151,
+ 31152,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31162,
+ 31171,
+ 31174,
+ 31175,
+ 0,
+ 0,
+ 0,
+ 31176,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31179,
+ 0,
+ 0,
+ 0,
+ 31186,
+ 0,
+ 0,
+ 0,
+ 31192,
+ 31195,
+ 0,
+ 0,
+ 31196,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31198,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31199,
+ 0,
+ 0,
+ 0,
+ 31205,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31211,
+ 31215,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31231,
+ 0,
+ 31232,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31233,
+ 31236,
+ 31253,
+ 0,
+ 31254,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31255,
+ 0,
+ 0,
+ 31257,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31258,
+ 31259,
+ 0,
+ 0,
+ 31260,
+ 0,
+ 31261,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31262,
+ 31263,
+ 0,
+ 0,
+ 31264,
+ 0,
+ 31266,
+ 0,
+ 31267,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31281,
+ 0,
+ 31282,
+ 0,
+ 31284,
+ 0,
+ 0,
+ 31285,
+ 31287,
+ 31288,
+ 0,
+ 0,
+ 31290,
+ 0,
+ 0,
+ 0,
+ 31292,
+ 31295,
+ 0,
+ 31299,
+ 0,
+ 31300,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31302,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31303,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31304,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31305,
+ 31308,
+ 31309,
+ 31315,
+ 0,
+ 31317,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31323,
+ 0,
+ 31324,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31325,
+ 31327,
+ 0,
+ 0,
+ 31331,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31333,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31336,
+ 0,
+ 0,
+ 31337,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31338,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31339,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31342,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31345,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31347,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31348,
+ 0,
+ 0,
+ 31350,
+ 31351,
+ 0,
+ 31352,
+ 0,
+ 0,
+ 31354,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31355,
+ 0,
+ 0,
+ 31356,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31363,
+ 0,
+ 31372,
+ 0,
+ 0,
+ 31373,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31376,
+ 0,
+ 31388,
+ 0,
+ 31389,
+ 0,
+ 31392,
+ 0,
+ 31401,
+ 0,
+ 31405,
+ 31407,
+ 31408,
+ 0,
+ 31409,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31413,
+ 31415,
+ 0,
+ 0,
+ 0,
+ 31416,
+ 31418,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31422,
+ 31423,
+ 0,
+ 0,
+ 31424,
+ 0,
+ 31425,
+ 31432,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31433,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31434,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31435,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31438,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31442,
+ 0,
+ 31444,
+ 0,
+ 31448,
+ 0,
+ 0,
+ 31451,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31452,
+ 0,
+ 31461,
+ 31465,
+ 0,
+ 0,
+ 31466,
+ 0,
+ 0,
+ 31467,
+ 0,
+ 0,
+ 31468,
+ 0,
+ 0,
+ 0,
+ 31469,
+ 31473,
+ 0,
+ 31476,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31489,
+ 31490,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31492,
+ 31493,
+ 31494,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31501,
+ 31504,
+ 31505,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31509,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31510,
+ 0,
+ 0,
+ 31511,
+ 0,
+ 0,
+ 31513,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31514,
+ 0,
+ 31522,
+ 31536,
+ 31539,
+ 31540,
+ 0,
+ 31541,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31546,
+ 31553,
+ 31559,
+ 0,
+ 0,
+ 0,
+ 31560,
+ 31561,
+ 31562,
+ 0,
+ 0,
+ 31564,
+ 31567,
+ 0,
+ 31569,
+ 0,
+ 0,
+ 0,
+ 31570,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31571,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31572,
+ 31574,
+ 31580,
+ 31581,
+ 0,
+ 0,
+ 31582,
+ 31584,
+ 31585,
+ 31586,
+ 31595,
+ 0,
+ 31596,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31597,
+ 0,
+ 31599,
+ 0,
+ 31600,
+ 31601,
+ 0,
+ 0,
+ 31603,
+ 31604,
+ 0,
+ 0,
+ 31608,
+ 31610,
+ 0,
+ 0,
+ 0,
+ 31611,
+ 0,
+ 31615,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31616,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31617,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31618,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31621,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31622,
+ 31625,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31627,
+ 0,
+ 31641,
+ 0,
+ 0,
+ 31642,
+ 0,
+ 0,
+ 31643,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31644,
+ 0,
+ 31646,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31648,
+ 0,
+ 0,
+ 0,
+ 31652,
+ 0,
+ 0,
+ 0,
+ 31657,
+ 0,
+ 0,
+ 31676,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31689,
+ 31691,
+ 31692,
+ 0,
+ 31694,
+ 0,
+ 0,
+ 0,
+ 31696,
+ 0,
+ 31702,
+ 0,
+ 31703,
+ 0,
+}
+
+var kStaticDictionaryWords = [31705]dictWord{
+ dictWord{0, 0, 0},
+ dictWord{8, 0, 1002},
+ dictWord{136, 0, 1015},
+ dictWord{4, 0, 683},
+ dictWord{4, 10, 325},
+ dictWord{138, 10, 125},
+ dictWord{7, 11, 572},
+ dictWord{
+ 9,
+ 11,
+ 592,
+ },
+ dictWord{11, 11, 680},
+ dictWord{11, 11, 842},
+ dictWord{11, 11, 924},
+ dictWord{12, 11, 356},
+ dictWord{12, 11, 550},
+ dictWord{13, 11, 317},
+ dictWord{13, 11, 370},
+ dictWord{13, 11, 469},
+ dictWord{13, 11, 471},
+ dictWord{14, 11, 397},
+ dictWord{18, 11, 69},
+ dictWord{146, 11, 145},
+ dictWord{
+ 134,
+ 0,
+ 1265,
+ },
+ dictWord{136, 11, 534},
+ dictWord{134, 0, 1431},
+ dictWord{11, 0, 138},
+ dictWord{140, 0, 40},
+ dictWord{4, 0, 155},
+ dictWord{7, 0, 1689},
+ dictWord{
+ 4,
+ 10,
+ 718,
+ },
+ dictWord{135, 10, 1216},
+ dictWord{4, 0, 245},
+ dictWord{5, 0, 151},
+ dictWord{5, 0, 741},
+ dictWord{6, 0, 1147},
+ dictWord{7, 0, 498},
+ dictWord{7, 0, 870},
+ dictWord{7, 0, 1542},
+ dictWord{12, 0, 213},
+ dictWord{14, 0, 36},
+ dictWord{14, 0, 391},
+ dictWord{17, 0, 111},
+ dictWord{18, 0, 6},
+ dictWord{18, 0, 46},
+ dictWord{
+ 18,
+ 0,
+ 151,
+ },
+ dictWord{19, 0, 36},
+ dictWord{20, 0, 32},
+ dictWord{20, 0, 56},
+ dictWord{20, 0, 69},
+ dictWord{20, 0, 102},
+ dictWord{21, 0, 4},
+ dictWord{22, 0, 8},
+ dictWord{
+ 22,
+ 0,
+ 10,
+ },
+ dictWord{22, 0, 14},
+ dictWord{150, 0, 31},
+ dictWord{4, 0, 624},
+ dictWord{135, 0, 1752},
+ dictWord{5, 10, 124},
+ dictWord{5, 10, 144},
+ dictWord{6, 10, 548},
+ dictWord{7, 10, 15},
+ dictWord{7, 10, 153},
+ dictWord{137, 10, 629},
+ dictWord{6, 0, 503},
+ dictWord{9, 0, 586},
+ dictWord{13, 0, 468},
+ dictWord{14, 0, 66},
+ dictWord{
+ 16,
+ 0,
+ 58,
+ },
+ dictWord{7, 10, 1531},
+ dictWord{8, 10, 416},
+ dictWord{9, 10, 275},
+ dictWord{10, 10, 100},
+ dictWord{11, 10, 658},
+ dictWord{11, 10, 979},
+ dictWord{
+ 12,
+ 10,
+ 86,
+ },
+ dictWord{14, 10, 207},
+ dictWord{15, 10, 20},
+ dictWord{143, 10, 25},
+ dictWord{5, 0, 603},
+ dictWord{7, 0, 1212},
+ dictWord{9, 0, 565},
+ dictWord{
+ 14,
+ 0,
+ 301,
+ },
+ dictWord{5, 10, 915},
+ dictWord{6, 10, 1783},
+ dictWord{7, 10, 211},
+ dictWord{7, 10, 1353},
+ dictWord{9, 10, 83},
+ dictWord{10, 10, 376},
+ dictWord{
+ 10,
+ 10,
+ 431,
+ },
+ dictWord{11, 10, 543},
+ dictWord{12, 10, 664},
+ dictWord{13, 10, 280},
+ dictWord{13, 10, 428},
+ dictWord{14, 10, 128},
+ dictWord{17, 10, 52},
+ dictWord{
+ 145,
+ 10,
+ 81,
+ },
+ dictWord{4, 0, 492},
+ dictWord{133, 0, 451},
+ dictWord{135, 0, 835},
+ dictWord{141, 0, 70},
+ dictWord{132, 0, 539},
+ dictWord{7, 11, 748},
+ dictWord{
+ 139,
+ 11,
+ 700,
+ },
+ dictWord{7, 11, 1517},
+ dictWord{11, 11, 597},
+ dictWord{14, 11, 76},
+ dictWord{14, 11, 335},
+ dictWord{148, 11, 33},
+ dictWord{6, 0, 113},
+ dictWord{135, 0, 436},
+ dictWord{4, 10, 338},
+ dictWord{133, 10, 400},
+ dictWord{136, 0, 718},
+ dictWord{133, 11, 127},
+ dictWord{133, 11, 418},
+ dictWord{
+ 6,
+ 0,
+ 1505,
+ },
+ dictWord{7, 0, 520},
+ dictWord{6, 11, 198},
+ dictWord{11, 10, 892},
+ dictWord{140, 11, 83},
+ dictWord{4, 10, 221},
+ dictWord{5, 10, 659},
+ dictWord{
+ 5,
+ 10,
+ 989,
+ },
+ dictWord{7, 10, 697},
+ dictWord{7, 10, 1211},
+ dictWord{138, 10, 284},
+ dictWord{135, 0, 1070},
+ dictWord{5, 11, 276},
+ dictWord{6, 11, 55},
+ dictWord{
+ 135,
+ 11,
+ 1369,
+ },
+ dictWord{134, 0, 1515},
+ dictWord{6, 11, 1752},
+ dictWord{136, 11, 726},
+ dictWord{138, 10, 507},
+ dictWord{15, 0, 78},
+ dictWord{4, 10, 188},
+ dictWord{135, 10, 805},
+ dictWord{5, 10, 884},
+ dictWord{139, 10, 991},
+ dictWord{133, 11, 764},
+ dictWord{134, 10, 1653},
+ dictWord{6, 11, 309},
+ dictWord{
+ 7,
+ 11,
+ 331,
+ },
+ dictWord{138, 11, 550},
+ dictWord{135, 11, 1861},
+ dictWord{132, 11, 348},
+ dictWord{135, 11, 986},
+ dictWord{135, 11, 1573},
+ dictWord{
+ 12,
+ 0,
+ 610,
+ },
+ dictWord{13, 0, 431},
+ dictWord{144, 0, 59},
+ dictWord{9, 11, 799},
+ dictWord{140, 10, 166},
+ dictWord{134, 0, 1530},
+ dictWord{132, 0, 750},
+ dictWord{132, 0, 307},
+ dictWord{133, 0, 964},
+ dictWord{6, 11, 194},
+ dictWord{7, 11, 133},
+ dictWord{10, 11, 493},
+ dictWord{10, 11, 570},
+ dictWord{139, 11, 664},
+ dictWord{5, 11, 24},
+ dictWord{5, 11, 569},
+ dictWord{6, 11, 3},
+ dictWord{6, 11, 119},
+ dictWord{6, 11, 143},
+ dictWord{6, 11, 440},
+ dictWord{7, 11, 295},
+ dictWord{
+ 7,
+ 11,
+ 599,
+ },
+ dictWord{7, 11, 1686},
+ dictWord{7, 11, 1854},
+ dictWord{8, 11, 424},
+ dictWord{9, 11, 43},
+ dictWord{9, 11, 584},
+ dictWord{9, 11, 760},
+ dictWord{
+ 10,
+ 11,
+ 148,
+ },
+ dictWord{10, 11, 328},
+ dictWord{11, 11, 159},
+ dictWord{11, 11, 253},
+ dictWord{11, 11, 506},
+ dictWord{12, 11, 487},
+ dictWord{12, 11, 531},
+ dictWord{144, 11, 33},
+ dictWord{136, 10, 760},
+ dictWord{5, 11, 14},
+ dictWord{5, 11, 892},
+ dictWord{6, 11, 283},
+ dictWord{7, 11, 234},
+ dictWord{136, 11, 537},
+ dictWord{135, 11, 1251},
+ dictWord{4, 11, 126},
+ dictWord{8, 11, 635},
+ dictWord{147, 11, 34},
+ dictWord{4, 11, 316},
+ dictWord{135, 11, 1561},
+ dictWord{
+ 6,
+ 0,
+ 999,
+ },
+ dictWord{6, 0, 1310},
+ dictWord{137, 11, 861},
+ dictWord{4, 11, 64},
+ dictWord{5, 11, 352},
+ dictWord{5, 11, 720},
+ dictWord{6, 11, 368},
+ dictWord{
+ 139,
+ 11,
+ 359,
+ },
+ dictWord{4, 0, 75},
+ dictWord{5, 0, 180},
+ dictWord{6, 0, 500},
+ dictWord{7, 0, 58},
+ dictWord{7, 0, 710},
+ dictWord{10, 0, 645},
+ dictWord{136, 10, 770},
+ dictWord{133, 0, 649},
+ dictWord{6, 0, 276},
+ dictWord{7, 0, 282},
+ dictWord{7, 0, 879},
+ dictWord{7, 0, 924},
+ dictWord{8, 0, 459},
+ dictWord{9, 0, 599},
+ dictWord{9, 0, 754},
+ dictWord{11, 0, 574},
+ dictWord{12, 0, 128},
+ dictWord{12, 0, 494},
+ dictWord{13, 0, 52},
+ dictWord{13, 0, 301},
+ dictWord{15, 0, 30},
+ dictWord{143, 0, 132},
+ dictWord{132, 0, 200},
+ dictWord{4, 10, 89},
+ dictWord{5, 10, 489},
+ dictWord{6, 10, 315},
+ dictWord{7, 10, 553},
+ dictWord{7, 10, 1745},
+ dictWord{138, 10, 243},
+ dictWord{135, 11, 1050},
+ dictWord{7, 0, 1621},
+ dictWord{6, 10, 1658},
+ dictWord{9, 10, 3},
+ dictWord{10, 10, 154},
+ dictWord{11, 10, 641},
+ dictWord{13, 10, 85},
+ dictWord{13, 10, 201},
+ dictWord{141, 10, 346},
+ dictWord{6, 11, 175},
+ dictWord{137, 11, 289},
+ dictWord{5, 11, 432},
+ dictWord{133, 11, 913},
+ dictWord{
+ 6,
+ 0,
+ 225,
+ },
+ dictWord{137, 0, 211},
+ dictWord{7, 0, 718},
+ dictWord{8, 0, 687},
+ dictWord{139, 0, 374},
+ dictWord{4, 10, 166},
+ dictWord{133, 10, 505},
+ dictWord{
+ 9,
+ 0,
+ 110,
+ },
+ dictWord{134, 10, 1670},
+ dictWord{8, 0, 58},
+ dictWord{9, 0, 724},
+ dictWord{11, 0, 809},
+ dictWord{13, 0, 113},
+ dictWord{145, 0, 72},
+ dictWord{6, 0, 345},
+ dictWord{7, 0, 1247},
+ dictWord{144, 11, 82},
+ dictWord{5, 11, 931},
+ dictWord{134, 11, 1698},
+ dictWord{8, 0, 767},
+ dictWord{8, 0, 803},
+ dictWord{9, 0, 301},
+ dictWord{137, 0, 903},
+ dictWord{139, 0, 203},
+ dictWord{134, 0, 1154},
+ dictWord{7, 0, 1949},
+ dictWord{136, 0, 674},
+ dictWord{134, 0, 259},
+ dictWord{
+ 135,
+ 0,
+ 1275,
+ },
+ dictWord{5, 11, 774},
+ dictWord{6, 11, 1637},
+ dictWord{6, 11, 1686},
+ dictWord{134, 11, 1751},
+ dictWord{134, 0, 1231},
+ dictWord{7, 10, 445},
+ dictWord{8, 10, 307},
+ dictWord{8, 10, 704},
+ dictWord{10, 10, 41},
+ dictWord{10, 10, 439},
+ dictWord{11, 10, 237},
+ dictWord{11, 10, 622},
+ dictWord{140, 10, 201},
+ dictWord{136, 0, 254},
+ dictWord{6, 11, 260},
+ dictWord{135, 11, 1484},
+ dictWord{139, 0, 277},
+ dictWord{135, 10, 1977},
+ dictWord{4, 10, 189},
+ dictWord{
+ 5,
+ 10,
+ 713,
+ },
+ dictWord{6, 11, 573},
+ dictWord{136, 10, 57},
+ dictWord{138, 10, 371},
+ dictWord{132, 10, 552},
+ dictWord{134, 11, 344},
+ dictWord{133, 0, 248},
+ dictWord{9, 0, 800},
+ dictWord{10, 0, 693},
+ dictWord{11, 0, 482},
+ dictWord{11, 0, 734},
+ dictWord{11, 0, 789},
+ dictWord{134, 11, 240},
+ dictWord{4, 0, 116},
+ dictWord{
+ 5,
+ 0,
+ 95,
+ },
+ dictWord{5, 0, 445},
+ dictWord{7, 0, 1688},
+ dictWord{8, 0, 29},
+ dictWord{9, 0, 272},
+ dictWord{11, 0, 509},
+ dictWord{11, 0, 915},
+ dictWord{4, 11, 292},
+ dictWord{4, 11, 736},
+ dictWord{5, 11, 871},
+ dictWord{6, 11, 171},
+ dictWord{6, 11, 1689},
+ dictWord{7, 11, 1324},
+ dictWord{7, 11, 1944},
+ dictWord{9, 11, 415},
+ dictWord{9, 11, 580},
+ dictWord{14, 11, 230},
+ dictWord{146, 11, 68},
+ dictWord{7, 0, 490},
+ dictWord{13, 0, 100},
+ dictWord{143, 0, 75},
+ dictWord{135, 0, 1641},
+ dictWord{133, 0, 543},
+ dictWord{7, 11, 209},
+ dictWord{8, 11, 661},
+ dictWord{10, 11, 42},
+ dictWord{11, 11, 58},
+ dictWord{12, 11, 58},
+ dictWord{12, 11, 118},
+ dictWord{141, 11, 32},
+ dictWord{5, 0, 181},
+ dictWord{8, 0, 41},
+ dictWord{6, 11, 63},
+ dictWord{135, 11, 920},
+ dictWord{133, 0, 657},
+ dictWord{133, 11, 793},
+ dictWord{138, 0, 709},
+ dictWord{7, 0, 25},
+ dictWord{8, 0, 202},
+ dictWord{138, 0, 536},
+ dictWord{5, 11, 665},
+ dictWord{135, 10, 1788},
+ dictWord{145, 10, 49},
+ dictWord{9, 0, 423},
+ dictWord{140, 0, 89},
+ dictWord{5, 11, 67},
+ dictWord{6, 11, 62},
+ dictWord{6, 11, 374},
+ dictWord{135, 11, 1391},
+ dictWord{8, 0, 113},
+ dictWord{
+ 9,
+ 0,
+ 877,
+ },
+ dictWord{10, 0, 554},
+ dictWord{11, 0, 83},
+ dictWord{12, 0, 136},
+ dictWord{19, 0, 109},
+ dictWord{9, 11, 790},
+ dictWord{140, 11, 47},
+ dictWord{
+ 138,
+ 10,
+ 661,
+ },
+ dictWord{4, 0, 963},
+ dictWord{10, 0, 927},
+ dictWord{14, 0, 442},
+ dictWord{135, 10, 1945},
+ dictWord{133, 0, 976},
+ dictWord{132, 0, 206},
+ dictWord{
+ 4,
+ 11,
+ 391,
+ },
+ dictWord{135, 11, 1169},
+ dictWord{134, 0, 2002},
+ dictWord{6, 0, 696},
+ dictWord{134, 0, 1008},
+ dictWord{134, 0, 1170},
+ dictWord{132, 11, 271},
+ dictWord{7, 0, 13},
+ dictWord{8, 0, 226},
+ dictWord{10, 0, 537},
+ dictWord{11, 0, 570},
+ dictWord{11, 0, 605},
+ dictWord{11, 0, 799},
+ dictWord{11, 0, 804},
+ dictWord{
+ 12,
+ 0,
+ 85,
+ },
+ dictWord{12, 0, 516},
+ dictWord{12, 0, 623},
+ dictWord{13, 0, 112},
+ dictWord{13, 0, 361},
+ dictWord{14, 0, 77},
+ dictWord{14, 0, 78},
+ dictWord{17, 0, 28},
+ dictWord{19, 0, 110},
+ dictWord{140, 11, 314},
+ dictWord{132, 0, 769},
+ dictWord{134, 0, 1544},
+ dictWord{4, 0, 551},
+ dictWord{137, 0, 678},
+ dictWord{5, 10, 84},
+ dictWord{134, 10, 163},
+ dictWord{9, 0, 57},
+ dictWord{9, 0, 459},
+ dictWord{10, 0, 425},
+ dictWord{11, 0, 119},
+ dictWord{12, 0, 184},
+ dictWord{12, 0, 371},
+ dictWord{
+ 13,
+ 0,
+ 358,
+ },
+ dictWord{145, 0, 51},
+ dictWord{5, 0, 188},
+ dictWord{5, 0, 814},
+ dictWord{8, 0, 10},
+ dictWord{9, 0, 421},
+ dictWord{9, 0, 729},
+ dictWord{10, 0, 609},
+ dictWord{11, 0, 689},
+ dictWord{4, 11, 253},
+ dictWord{5, 10, 410},
+ dictWord{5, 11, 544},
+ dictWord{7, 11, 300},
+ dictWord{137, 11, 340},
+ dictWord{134, 0, 624},
+ dictWord{138, 11, 321},
+ dictWord{135, 0, 1941},
+ dictWord{18, 0, 130},
+ dictWord{5, 10, 322},
+ dictWord{8, 10, 186},
+ dictWord{9, 10, 262},
+ dictWord{10, 10, 187},
+ dictWord{142, 10, 208},
+ dictWord{5, 11, 53},
+ dictWord{5, 11, 541},
+ dictWord{6, 11, 94},
+ dictWord{6, 11, 499},
+ dictWord{7, 11, 230},
+ dictWord{139, 11, 321},
+ dictWord{133, 10, 227},
+ dictWord{4, 0, 378},
+ dictWord{4, 11, 920},
+ dictWord{5, 11, 25},
+ dictWord{5, 11, 790},
+ dictWord{6, 11, 457},
+ dictWord{135, 11, 853},
+ dictWord{137, 0, 269},
+ dictWord{132, 0, 528},
+ dictWord{134, 0, 1146},
+ dictWord{7, 10, 1395},
+ dictWord{8, 10, 486},
+ dictWord{9, 10, 236},
+ dictWord{9, 10, 878},
+ dictWord{10, 10, 218},
+ dictWord{11, 10, 95},
+ dictWord{19, 10, 17},
+ dictWord{147, 10, 31},
+ dictWord{7, 10, 2043},
+ dictWord{8, 10, 672},
+ dictWord{
+ 141,
+ 10,
+ 448,
+ },
+ dictWord{134, 0, 1105},
+ dictWord{134, 0, 1616},
+ dictWord{134, 11, 1765},
+ dictWord{140, 11, 163},
+ dictWord{5, 10, 412},
+ dictWord{133, 11, 822},
+ dictWord{132, 11, 634},
+ dictWord{6, 0, 656},
+ dictWord{134, 11, 1730},
+ dictWord{134, 0, 1940},
+ dictWord{5, 0, 104},
+ dictWord{6, 0, 173},
+ dictWord{
+ 135,
+ 0,
+ 1631,
+ },
+ dictWord{136, 10, 562},
+ dictWord{6, 11, 36},
+ dictWord{7, 11, 658},
+ dictWord{8, 11, 454},
+ dictWord{147, 11, 86},
+ dictWord{5, 0, 457},
+ dictWord{
+ 134,
+ 10,
+ 1771,
+ },
+ dictWord{7, 0, 810},
+ dictWord{8, 0, 138},
+ dictWord{8, 0, 342},
+ dictWord{9, 0, 84},
+ dictWord{10, 0, 193},
+ dictWord{11, 0, 883},
+ dictWord{140, 0, 359},
+ dictWord{9, 0, 620},
+ dictWord{135, 10, 1190},
+ dictWord{137, 10, 132},
+ dictWord{7, 11, 975},
+ dictWord{137, 11, 789},
+ dictWord{6, 0, 95},
+ dictWord{6, 0, 1934},
+ dictWord{136, 0, 967},
+ dictWord{141, 11, 335},
+ dictWord{6, 0, 406},
+ dictWord{10, 0, 409},
+ dictWord{10, 0, 447},
+ dictWord{11, 0, 44},
+ dictWord{140, 0, 100},
+ dictWord{4, 10, 317},
+ dictWord{135, 10, 1279},
+ dictWord{132, 0, 477},
+ dictWord{134, 0, 1268},
+ dictWord{6, 0, 1941},
+ dictWord{8, 0, 944},
+ dictWord{5, 10, 63},
+ dictWord{133, 10, 509},
+ dictWord{132, 0, 629},
+ dictWord{132, 11, 104},
+ dictWord{4, 0, 246},
+ dictWord{133, 0, 375},
+ dictWord{6, 0, 1636},
+ dictWord{
+ 132,
+ 10,
+ 288,
+ },
+ dictWord{135, 11, 1614},
+ dictWord{9, 0, 49},
+ dictWord{10, 0, 774},
+ dictWord{8, 10, 89},
+ dictWord{8, 10, 620},
+ dictWord{11, 10, 628},
+ dictWord{
+ 12,
+ 10,
+ 322,
+ },
+ dictWord{143, 10, 124},
+ dictWord{4, 0, 282},
+ dictWord{7, 0, 1034},
+ dictWord{11, 0, 398},
+ dictWord{11, 0, 634},
+ dictWord{12, 0, 1},
+ dictWord{12, 0, 79},
+ dictWord{12, 0, 544},
+ dictWord{14, 0, 237},
+ dictWord{17, 0, 10},
+ dictWord{146, 0, 20},
+ dictWord{132, 0, 824},
+ dictWord{7, 11, 45},
+ dictWord{9, 11, 542},
+ dictWord{
+ 9,
+ 11,
+ 566,
+ },
+ dictWord{138, 11, 728},
+ dictWord{5, 0, 118},
+ dictWord{5, 0, 499},
+ dictWord{6, 0, 476},
+ dictWord{6, 0, 665},
+ dictWord{6, 0, 1176},
+ dictWord{
+ 6,
+ 0,
+ 1196,
+ },
+ dictWord{7, 0, 600},
+ dictWord{7, 0, 888},
+ dictWord{135, 0, 1096},
+ dictWord{7, 0, 296},
+ dictWord{7, 0, 596},
+ dictWord{8, 0, 560},
+ dictWord{8, 0, 586},
+ dictWord{9, 0, 612},
+ dictWord{11, 0, 304},
+ dictWord{12, 0, 46},
+ dictWord{13, 0, 89},
+ dictWord{14, 0, 112},
+ dictWord{145, 0, 122},
+ dictWord{5, 0, 894},
+ dictWord{
+ 6,
+ 0,
+ 1772,
+ },
+ dictWord{9, 0, 1009},
+ dictWord{138, 10, 120},
+ dictWord{5, 11, 533},
+ dictWord{7, 11, 755},
+ dictWord{138, 11, 780},
+ dictWord{151, 10, 1},
+ dictWord{
+ 6,
+ 0,
+ 1474,
+ },
+ dictWord{7, 11, 87},
+ dictWord{142, 11, 288},
+ dictWord{139, 0, 366},
+ dictWord{137, 10, 461},
+ dictWord{7, 11, 988},
+ dictWord{7, 11, 1939},
+ dictWord{
+ 9,
+ 11,
+ 64,
+ },
+ dictWord{9, 11, 502},
+ dictWord{12, 11, 7},
+ dictWord{12, 11, 34},
+ dictWord{13, 11, 12},
+ dictWord{13, 11, 234},
+ dictWord{147, 11, 77},
+ dictWord{
+ 7,
+ 0,
+ 1599,
+ },
+ dictWord{7, 0, 1723},
+ dictWord{8, 0, 79},
+ dictWord{8, 0, 106},
+ dictWord{8, 0, 190},
+ dictWord{8, 0, 302},
+ dictWord{8, 0, 383},
+ dictWord{8, 0, 713},
+ dictWord{
+ 9,
+ 0,
+ 119,
+ },
+ dictWord{9, 0, 233},
+ dictWord{9, 0, 419},
+ dictWord{9, 0, 471},
+ dictWord{10, 0, 181},
+ dictWord{10, 0, 406},
+ dictWord{11, 0, 57},
+ dictWord{11, 0, 85},
+ dictWord{11, 0, 120},
+ dictWord{11, 0, 177},
+ dictWord{11, 0, 296},
+ dictWord{11, 0, 382},
+ dictWord{11, 0, 454},
+ dictWord{11, 0, 758},
+ dictWord{11, 0, 999},
+ dictWord{
+ 12,
+ 0,
+ 27,
+ },
+ dictWord{12, 0, 98},
+ dictWord{12, 0, 131},
+ dictWord{12, 0, 245},
+ dictWord{12, 0, 312},
+ dictWord{12, 0, 446},
+ dictWord{12, 0, 454},
+ dictWord{13, 0, 25},
+ dictWord{13, 0, 98},
+ dictWord{13, 0, 426},
+ dictWord{13, 0, 508},
+ dictWord{14, 0, 70},
+ dictWord{14, 0, 163},
+ dictWord{14, 0, 272},
+ dictWord{14, 0, 277},
+ dictWord{
+ 14,
+ 0,
+ 370,
+ },
+ dictWord{15, 0, 95},
+ dictWord{15, 0, 138},
+ dictWord{15, 0, 167},
+ dictWord{17, 0, 38},
+ dictWord{148, 0, 96},
+ dictWord{135, 10, 1346},
+ dictWord{
+ 10,
+ 0,
+ 200,
+ },
+ dictWord{19, 0, 2},
+ dictWord{151, 0, 22},
+ dictWord{135, 11, 141},
+ dictWord{134, 10, 85},
+ dictWord{134, 0, 1759},
+ dictWord{138, 0, 372},
+ dictWord{
+ 145,
+ 0,
+ 16,
+ },
+ dictWord{8, 0, 943},
+ dictWord{132, 11, 619},
+ dictWord{139, 11, 88},
+ dictWord{5, 11, 246},
+ dictWord{8, 11, 189},
+ dictWord{9, 11, 355},
+ dictWord{
+ 9,
+ 11,
+ 512,
+ },
+ dictWord{10, 11, 124},
+ dictWord{10, 11, 453},
+ dictWord{11, 11, 143},
+ dictWord{11, 11, 416},
+ dictWord{11, 11, 859},
+ dictWord{141, 11, 341},
+ dictWord{
+ 5,
+ 0,
+ 258,
+ },
+ dictWord{134, 0, 719},
+ dictWord{6, 0, 1798},
+ dictWord{6, 0, 1839},
+ dictWord{8, 0, 900},
+ dictWord{10, 0, 874},
+ dictWord{10, 0, 886},
+ dictWord{
+ 12,
+ 0,
+ 698,
+ },
+ dictWord{12, 0, 732},
+ dictWord{12, 0, 770},
+ dictWord{16, 0, 106},
+ dictWord{18, 0, 163},
+ dictWord{18, 0, 170},
+ dictWord{18, 0, 171},
+ dictWord{152, 0, 20},
+ dictWord{9, 0, 707},
+ dictWord{11, 0, 326},
+ dictWord{11, 0, 339},
+ dictWord{12, 0, 423},
+ dictWord{12, 0, 502},
+ dictWord{20, 0, 62},
+ dictWord{9, 11, 707},
+ dictWord{
+ 11,
+ 11,
+ 326,
+ },
+ dictWord{11, 11, 339},
+ dictWord{12, 11, 423},
+ dictWord{12, 11, 502},
+ dictWord{148, 11, 62},
+ dictWord{5, 0, 30},
+ dictWord{7, 0, 495},
+ dictWord{
+ 8,
+ 0,
+ 134,
+ },
+ dictWord{9, 0, 788},
+ dictWord{140, 0, 438},
+ dictWord{133, 11, 678},
+ dictWord{5, 10, 279},
+ dictWord{6, 10, 235},
+ dictWord{7, 10, 468},
+ dictWord{
+ 8,
+ 10,
+ 446,
+ },
+ dictWord{9, 10, 637},
+ dictWord{10, 10, 717},
+ dictWord{11, 10, 738},
+ dictWord{140, 10, 514},
+ dictWord{5, 11, 35},
+ dictWord{6, 11, 287},
+ dictWord{
+ 7,
+ 11,
+ 862,
+ },
+ dictWord{7, 11, 1886},
+ dictWord{138, 11, 179},
+ dictWord{7, 0, 1948},
+ dictWord{7, 0, 2004},
+ dictWord{132, 11, 517},
+ dictWord{5, 10, 17},
+ dictWord{
+ 6,
+ 10,
+ 371,
+ },
+ dictWord{137, 10, 528},
+ dictWord{4, 0, 115},
+ dictWord{5, 0, 669},
+ dictWord{6, 0, 407},
+ dictWord{8, 0, 311},
+ dictWord{11, 0, 10},
+ dictWord{141, 0, 5},
+ dictWord{137, 0, 381},
+ dictWord{5, 0, 50},
+ dictWord{6, 0, 439},
+ dictWord{7, 0, 780},
+ dictWord{135, 0, 1040},
+ dictWord{136, 11, 667},
+ dictWord{11, 11, 403},
+ dictWord{146, 11, 83},
+ dictWord{5, 0, 1},
+ dictWord{6, 0, 81},
+ dictWord{138, 0, 520},
+ dictWord{134, 0, 738},
+ dictWord{5, 0, 482},
+ dictWord{8, 0, 98},
+ dictWord{9, 0, 172},
+ dictWord{10, 0, 360},
+ dictWord{10, 0, 700},
+ dictWord{10, 0, 822},
+ dictWord{11, 0, 302},
+ dictWord{11, 0, 778},
+ dictWord{12, 0, 50},
+ dictWord{12, 0, 127},
+ dictWord{
+ 12,
+ 0,
+ 396,
+ },
+ dictWord{13, 0, 62},
+ dictWord{13, 0, 328},
+ dictWord{14, 0, 122},
+ dictWord{147, 0, 72},
+ dictWord{9, 11, 157},
+ dictWord{10, 11, 131},
+ dictWord{
+ 140,
+ 11,
+ 72,
+ },
+ dictWord{135, 11, 714},
+ dictWord{135, 11, 539},
+ dictWord{5, 0, 2},
+ dictWord{6, 0, 512},
+ dictWord{7, 0, 797},
+ dictWord{7, 0, 1494},
+ dictWord{8, 0, 253},
+ dictWord{8, 0, 589},
+ dictWord{9, 0, 77},
+ dictWord{10, 0, 1},
+ dictWord{10, 0, 129},
+ dictWord{10, 0, 225},
+ dictWord{11, 0, 118},
+ dictWord{11, 0, 226},
+ dictWord{
+ 11,
+ 0,
+ 251,
+ },
+ dictWord{11, 0, 430},
+ dictWord{11, 0, 701},
+ dictWord{11, 0, 974},
+ dictWord{11, 0, 982},
+ dictWord{12, 0, 64},
+ dictWord{12, 0, 260},
+ dictWord{12, 0, 488},
+ dictWord{140, 0, 690},
+ dictWord{5, 11, 394},
+ dictWord{7, 11, 367},
+ dictWord{7, 11, 487},
+ dictWord{7, 11, 857},
+ dictWord{7, 11, 1713},
+ dictWord{8, 11, 246},
+ dictWord{9, 11, 537},
+ dictWord{10, 11, 165},
+ dictWord{12, 11, 219},
+ dictWord{140, 11, 561},
+ dictWord{136, 0, 557},
+ dictWord{5, 10, 779},
+ dictWord{5, 10, 807},
+ dictWord{6, 10, 1655},
+ dictWord{134, 10, 1676},
+ dictWord{4, 10, 196},
+ dictWord{5, 10, 558},
+ dictWord{133, 10, 949},
+ dictWord{11, 11, 827},
+ dictWord{
+ 12,
+ 11,
+ 56,
+ },
+ dictWord{14, 11, 34},
+ dictWord{143, 11, 148},
+ dictWord{137, 0, 347},
+ dictWord{133, 0, 572},
+ dictWord{134, 0, 832},
+ dictWord{4, 0, 12},
+ dictWord{
+ 7,
+ 0,
+ 504,
+ },
+ dictWord{7, 0, 522},
+ dictWord{7, 0, 809},
+ dictWord{8, 0, 797},
+ dictWord{141, 0, 88},
+ dictWord{4, 10, 752},
+ dictWord{133, 11, 449},
+ dictWord{7, 11, 86},
+ dictWord{8, 11, 103},
+ dictWord{145, 11, 69},
+ dictWord{7, 11, 2028},
+ dictWord{138, 11, 641},
+ dictWord{5, 0, 528},
+ dictWord{6, 11, 1},
+ dictWord{142, 11, 2},
+ dictWord{134, 0, 861},
+ dictWord{10, 0, 294},
+ dictWord{4, 10, 227},
+ dictWord{5, 10, 159},
+ dictWord{5, 10, 409},
+ dictWord{7, 10, 80},
+ dictWord{10, 10, 479},
+ dictWord{
+ 12,
+ 10,
+ 418,
+ },
+ dictWord{14, 10, 50},
+ dictWord{14, 10, 249},
+ dictWord{142, 10, 295},
+ dictWord{7, 10, 1470},
+ dictWord{8, 10, 66},
+ dictWord{8, 10, 137},
+ dictWord{
+ 8,
+ 10,
+ 761,
+ },
+ dictWord{9, 10, 638},
+ dictWord{11, 10, 80},
+ dictWord{11, 10, 212},
+ dictWord{11, 10, 368},
+ dictWord{11, 10, 418},
+ dictWord{12, 10, 8},
+ dictWord{
+ 13,
+ 10,
+ 15,
+ },
+ dictWord{16, 10, 61},
+ dictWord{17, 10, 59},
+ dictWord{19, 10, 28},
+ dictWord{148, 10, 84},
+ dictWord{20, 0, 109},
+ dictWord{135, 11, 1148},
+ dictWord{
+ 6,
+ 11,
+ 277,
+ },
+ dictWord{7, 11, 1274},
+ dictWord{7, 11, 1386},
+ dictWord{7, 11, 1392},
+ dictWord{12, 11, 129},
+ dictWord{146, 11, 87},
+ dictWord{6, 11, 187},
+ dictWord{7, 11, 39},
+ dictWord{7, 11, 1203},
+ dictWord{8, 11, 380},
+ dictWord{8, 11, 542},
+ dictWord{14, 11, 117},
+ dictWord{149, 11, 28},
+ dictWord{134, 0, 1187},
+ dictWord{5, 0, 266},
+ dictWord{9, 0, 290},
+ dictWord{9, 0, 364},
+ dictWord{10, 0, 293},
+ dictWord{11, 0, 606},
+ dictWord{142, 0, 45},
+ dictWord{6, 11, 297},
+ dictWord{
+ 7,
+ 11,
+ 793,
+ },
+ dictWord{139, 11, 938},
+ dictWord{4, 0, 50},
+ dictWord{6, 0, 594},
+ dictWord{9, 0, 121},
+ dictWord{10, 0, 49},
+ dictWord{10, 0, 412},
+ dictWord{139, 0, 834},
+ dictWord{136, 0, 748},
+ dictWord{7, 11, 464},
+ dictWord{8, 11, 438},
+ dictWord{11, 11, 105},
+ dictWord{11, 11, 363},
+ dictWord{12, 11, 231},
+ dictWord{
+ 14,
+ 11,
+ 386,
+ },
+ dictWord{15, 11, 102},
+ dictWord{148, 11, 75},
+ dictWord{132, 0, 466},
+ dictWord{13, 0, 399},
+ dictWord{14, 0, 337},
+ dictWord{6, 10, 38},
+ dictWord{
+ 7,
+ 10,
+ 1220,
+ },
+ dictWord{8, 10, 185},
+ dictWord{8, 10, 256},
+ dictWord{9, 10, 22},
+ dictWord{9, 10, 331},
+ dictWord{10, 10, 738},
+ dictWord{11, 10, 205},
+ dictWord{
+ 11,
+ 10,
+ 540,
+ },
+ dictWord{11, 10, 746},
+ dictWord{13, 10, 465},
+ dictWord{142, 10, 194},
+ dictWord{9, 0, 378},
+ dictWord{141, 0, 162},
+ dictWord{137, 0, 519},
+ dictWord{
+ 4,
+ 10,
+ 159,
+ },
+ dictWord{6, 10, 115},
+ dictWord{7, 10, 252},
+ dictWord{7, 10, 257},
+ dictWord{7, 10, 1928},
+ dictWord{8, 10, 69},
+ dictWord{9, 10, 384},
+ dictWord{
+ 10,
+ 10,
+ 91,
+ },
+ dictWord{10, 10, 615},
+ dictWord{12, 10, 375},
+ dictWord{14, 10, 235},
+ dictWord{18, 10, 117},
+ dictWord{147, 10, 123},
+ dictWord{5, 11, 604},
+ dictWord{
+ 5,
+ 10,
+ 911,
+ },
+ dictWord{136, 10, 278},
+ dictWord{132, 0, 667},
+ dictWord{8, 0, 351},
+ dictWord{9, 0, 322},
+ dictWord{4, 10, 151},
+ dictWord{135, 10, 1567},
+ dictWord{134, 0, 902},
+ dictWord{133, 10, 990},
+ dictWord{12, 0, 180},
+ dictWord{5, 10, 194},
+ dictWord{7, 10, 1662},
+ dictWord{137, 10, 90},
+ dictWord{4, 0, 869},
+ dictWord{134, 0, 1996},
+ dictWord{134, 0, 813},
+ dictWord{133, 10, 425},
+ dictWord{137, 11, 761},
+ dictWord{132, 0, 260},
+ dictWord{133, 10, 971},
+ dictWord{
+ 5,
+ 11,
+ 20,
+ },
+ dictWord{6, 11, 298},
+ dictWord{7, 11, 659},
+ dictWord{7, 11, 1366},
+ dictWord{137, 11, 219},
+ dictWord{4, 0, 39},
+ dictWord{5, 0, 36},
+ dictWord{
+ 7,
+ 0,
+ 1843,
+ },
+ dictWord{8, 0, 407},
+ dictWord{11, 0, 144},
+ dictWord{140, 0, 523},
+ dictWord{4, 0, 510},
+ dictWord{10, 0, 587},
+ dictWord{139, 10, 752},
+ dictWord{7, 0, 29},
+ dictWord{7, 0, 66},
+ dictWord{7, 0, 1980},
+ dictWord{10, 0, 487},
+ dictWord{138, 0, 809},
+ dictWord{13, 0, 260},
+ dictWord{14, 0, 82},
+ dictWord{18, 0, 63},
+ dictWord{
+ 137,
+ 10,
+ 662,
+ },
+ dictWord{5, 10, 72},
+ dictWord{6, 10, 264},
+ dictWord{7, 10, 21},
+ dictWord{7, 10, 46},
+ dictWord{7, 10, 2013},
+ dictWord{8, 10, 215},
+ dictWord{
+ 8,
+ 10,
+ 513,
+ },
+ dictWord{10, 10, 266},
+ dictWord{139, 10, 22},
+ dictWord{134, 0, 570},
+ dictWord{6, 0, 565},
+ dictWord{7, 0, 1667},
+ dictWord{4, 11, 439},
+ dictWord{
+ 10,
+ 10,
+ 95,
+ },
+ dictWord{11, 10, 603},
+ dictWord{12, 11, 242},
+ dictWord{13, 10, 443},
+ dictWord{14, 10, 160},
+ dictWord{143, 10, 4},
+ dictWord{134, 0, 1464},
+ dictWord{
+ 134,
+ 10,
+ 431,
+ },
+ dictWord{9, 0, 372},
+ dictWord{15, 0, 2},
+ dictWord{19, 0, 10},
+ dictWord{19, 0, 18},
+ dictWord{5, 10, 874},
+ dictWord{6, 10, 1677},
+ dictWord{143, 10, 0},
+ dictWord{132, 0, 787},
+ dictWord{6, 0, 380},
+ dictWord{12, 0, 399},
+ dictWord{21, 0, 19},
+ dictWord{7, 10, 939},
+ dictWord{7, 10, 1172},
+ dictWord{7, 10, 1671},
+ dictWord{9, 10, 540},
+ dictWord{10, 10, 696},
+ dictWord{11, 10, 265},
+ dictWord{11, 10, 732},
+ dictWord{11, 10, 928},
+ dictWord{11, 10, 937},
+ dictWord{
+ 141,
+ 10,
+ 438,
+ },
+ dictWord{137, 0, 200},
+ dictWord{132, 11, 233},
+ dictWord{132, 0, 516},
+ dictWord{134, 11, 577},
+ dictWord{132, 0, 844},
+ dictWord{11, 0, 887},
+ dictWord{14, 0, 365},
+ dictWord{142, 0, 375},
+ dictWord{132, 11, 482},
+ dictWord{8, 0, 821},
+ dictWord{140, 0, 44},
+ dictWord{7, 0, 1655},
+ dictWord{136, 0, 305},
+ dictWord{5, 10, 682},
+ dictWord{135, 10, 1887},
+ dictWord{135, 11, 346},
+ dictWord{132, 10, 696},
+ dictWord{4, 0, 10},
+ dictWord{7, 0, 917},
+ dictWord{139, 0, 786},
+ dictWord{5, 11, 795},
+ dictWord{6, 11, 1741},
+ dictWord{8, 11, 417},
+ dictWord{137, 11, 782},
+ dictWord{4, 0, 1016},
+ dictWord{134, 0, 2031},
+ dictWord{5, 0, 684},
+ dictWord{4, 10, 726},
+ dictWord{133, 10, 630},
+ dictWord{6, 0, 1021},
+ dictWord{134, 0, 1480},
+ dictWord{8, 10, 802},
+ dictWord{136, 10, 838},
+ dictWord{
+ 134,
+ 0,
+ 27,
+ },
+ dictWord{134, 0, 395},
+ dictWord{135, 11, 622},
+ dictWord{7, 11, 625},
+ dictWord{135, 11, 1750},
+ dictWord{4, 11, 203},
+ dictWord{135, 11, 1936},
+ dictWord{6, 10, 118},
+ dictWord{7, 10, 215},
+ dictWord{7, 10, 1521},
+ dictWord{140, 10, 11},
+ dictWord{132, 0, 813},
+ dictWord{136, 0, 511},
+ dictWord{7, 10, 615},
+ dictWord{138, 10, 251},
+ dictWord{135, 10, 1044},
+ dictWord{145, 0, 56},
+ dictWord{133, 10, 225},
+ dictWord{6, 0, 342},
+ dictWord{6, 0, 496},
+ dictWord{8, 0, 275},
+ dictWord{137, 0, 206},
+ dictWord{4, 0, 909},
+ dictWord{133, 0, 940},
+ dictWord{132, 0, 891},
+ dictWord{7, 11, 311},
+ dictWord{9, 11, 308},
+ dictWord{
+ 140,
+ 11,
+ 255,
+ },
+ dictWord{4, 10, 370},
+ dictWord{5, 10, 756},
+ dictWord{135, 10, 1326},
+ dictWord{4, 0, 687},
+ dictWord{134, 0, 1596},
+ dictWord{134, 0, 1342},
+ dictWord{
+ 6,
+ 10,
+ 1662,
+ },
+ dictWord{7, 10, 48},
+ dictWord{8, 10, 771},
+ dictWord{10, 10, 116},
+ dictWord{13, 10, 104},
+ dictWord{14, 10, 105},
+ dictWord{14, 10, 184},
+ dictWord{15, 10, 168},
+ dictWord{19, 10, 92},
+ dictWord{148, 10, 68},
+ dictWord{138, 10, 209},
+ dictWord{4, 11, 400},
+ dictWord{5, 11, 267},
+ dictWord{135, 11, 232},
+ dictWord{151, 11, 12},
+ dictWord{6, 0, 41},
+ dictWord{141, 0, 160},
+ dictWord{141, 11, 314},
+ dictWord{134, 0, 1718},
+ dictWord{136, 0, 778},
+ dictWord{
+ 142,
+ 11,
+ 261,
+ },
+ dictWord{134, 0, 1610},
+ dictWord{133, 0, 115},
+ dictWord{132, 0, 294},
+ dictWord{14, 0, 314},
+ dictWord{132, 10, 120},
+ dictWord{132, 0, 983},
+ dictWord{5, 0, 193},
+ dictWord{140, 0, 178},
+ dictWord{138, 10, 429},
+ dictWord{5, 10, 820},
+ dictWord{135, 10, 931},
+ dictWord{6, 0, 994},
+ dictWord{6, 0, 1051},
+ dictWord{6, 0, 1439},
+ dictWord{7, 0, 174},
+ dictWord{133, 11, 732},
+ dictWord{4, 11, 100},
+ dictWord{7, 11, 679},
+ dictWord{8, 11, 313},
+ dictWord{138, 10, 199},
+ dictWord{6, 10, 151},
+ dictWord{6, 10, 1675},
+ dictWord{7, 10, 383},
+ dictWord{151, 10, 10},
+ dictWord{6, 0, 1796},
+ dictWord{8, 0, 848},
+ dictWord{8, 0, 867},
+ dictWord{
+ 8,
+ 0,
+ 907,
+ },
+ dictWord{10, 0, 855},
+ dictWord{140, 0, 703},
+ dictWord{140, 0, 221},
+ dictWord{4, 0, 122},
+ dictWord{5, 0, 796},
+ dictWord{5, 0, 952},
+ dictWord{6, 0, 1660},
+ dictWord{6, 0, 1671},
+ dictWord{8, 0, 567},
+ dictWord{9, 0, 687},
+ dictWord{9, 0, 742},
+ dictWord{10, 0, 686},
+ dictWord{11, 0, 682},
+ dictWord{11, 0, 909},
+ dictWord{
+ 140,
+ 0,
+ 281,
+ },
+ dictWord{5, 11, 362},
+ dictWord{5, 11, 443},
+ dictWord{6, 11, 318},
+ dictWord{7, 11, 1019},
+ dictWord{139, 11, 623},
+ dictWord{5, 11, 463},
+ dictWord{136, 11, 296},
+ dictWord{11, 0, 583},
+ dictWord{13, 0, 262},
+ dictWord{6, 10, 1624},
+ dictWord{12, 10, 422},
+ dictWord{142, 10, 360},
+ dictWord{5, 0, 179},
+ dictWord{7, 0, 1095},
+ dictWord{135, 0, 1213},
+ dictWord{4, 10, 43},
+ dictWord{4, 11, 454},
+ dictWord{5, 10, 344},
+ dictWord{133, 10, 357},
+ dictWord{4, 0, 66},
+ dictWord{7, 0, 722},
+ dictWord{135, 0, 904},
+ dictWord{134, 0, 773},
+ dictWord{7, 0, 352},
+ dictWord{133, 10, 888},
+ dictWord{5, 11, 48},
+ dictWord{5, 11, 404},
+ dictWord{
+ 6,
+ 11,
+ 557,
+ },
+ dictWord{7, 11, 458},
+ dictWord{8, 11, 597},
+ dictWord{10, 11, 455},
+ dictWord{10, 11, 606},
+ dictWord{11, 11, 49},
+ dictWord{11, 11, 548},
+ dictWord{
+ 12,
+ 11,
+ 476,
+ },
+ dictWord{13, 11, 18},
+ dictWord{141, 11, 450},
+ dictWord{134, 11, 418},
+ dictWord{132, 10, 711},
+ dictWord{5, 11, 442},
+ dictWord{
+ 135,
+ 11,
+ 1984,
+ },
+ dictWord{141, 0, 35},
+ dictWord{137, 0, 152},
+ dictWord{134, 0, 1197},
+ dictWord{135, 11, 1093},
+ dictWord{137, 11, 203},
+ dictWord{137, 10, 440},
+ dictWord{10, 0, 592},
+ dictWord{10, 0, 753},
+ dictWord{12, 0, 317},
+ dictWord{12, 0, 355},
+ dictWord{12, 0, 465},
+ dictWord{12, 0, 469},
+ dictWord{12, 0, 560},
+ dictWord{12, 0, 578},
+ dictWord{141, 0, 243},
+ dictWord{133, 0, 564},
+ dictWord{134, 0, 797},
+ dictWord{5, 10, 958},
+ dictWord{133, 10, 987},
+ dictWord{5, 11, 55},
+ dictWord{7, 11, 376},
+ dictWord{140, 11, 161},
+ dictWord{133, 11, 450},
+ dictWord{134, 0, 556},
+ dictWord{134, 0, 819},
+ dictWord{11, 10, 276},
+ dictWord{
+ 142,
+ 10,
+ 293,
+ },
+ dictWord{7, 0, 544},
+ dictWord{138, 0, 61},
+ dictWord{8, 0, 719},
+ dictWord{4, 10, 65},
+ dictWord{5, 10, 479},
+ dictWord{5, 10, 1004},
+ dictWord{7, 10, 1913},
+ dictWord{8, 10, 317},
+ dictWord{9, 10, 302},
+ dictWord{10, 10, 612},
+ dictWord{141, 10, 22},
+ dictWord{4, 0, 5},
+ dictWord{5, 0, 498},
+ dictWord{8, 0, 637},
+ dictWord{
+ 9,
+ 0,
+ 521,
+ },
+ dictWord{4, 11, 213},
+ dictWord{4, 10, 261},
+ dictWord{7, 11, 223},
+ dictWord{7, 10, 510},
+ dictWord{136, 11, 80},
+ dictWord{5, 0, 927},
+ dictWord{7, 0, 101},
+ dictWord{4, 10, 291},
+ dictWord{7, 11, 381},
+ dictWord{7, 11, 806},
+ dictWord{7, 11, 820},
+ dictWord{8, 11, 354},
+ dictWord{8, 11, 437},
+ dictWord{8, 11, 787},
+ dictWord{9, 10, 515},
+ dictWord{9, 11, 657},
+ dictWord{10, 11, 58},
+ dictWord{10, 11, 339},
+ dictWord{10, 11, 749},
+ dictWord{11, 11, 914},
+ dictWord{12, 10, 152},
+ dictWord{12, 11, 162},
+ dictWord{12, 10, 443},
+ dictWord{13, 11, 75},
+ dictWord{13, 10, 392},
+ dictWord{14, 11, 106},
+ dictWord{14, 11, 198},
+ dictWord{
+ 14,
+ 11,
+ 320,
+ },
+ dictWord{14, 10, 357},
+ dictWord{14, 11, 413},
+ dictWord{146, 11, 43},
+ dictWord{6, 0, 1153},
+ dictWord{7, 0, 1441},
+ dictWord{136, 11, 747},
+ dictWord{
+ 4,
+ 0,
+ 893,
+ },
+ dictWord{5, 0, 780},
+ dictWord{133, 0, 893},
+ dictWord{138, 11, 654},
+ dictWord{133, 11, 692},
+ dictWord{133, 0, 238},
+ dictWord{134, 11, 191},
+ dictWord{4, 10, 130},
+ dictWord{135, 10, 843},
+ dictWord{6, 0, 1296},
+ dictWord{5, 10, 42},
+ dictWord{5, 10, 879},
+ dictWord{7, 10, 245},
+ dictWord{7, 10, 324},
+ dictWord{
+ 7,
+ 10,
+ 1532,
+ },
+ dictWord{11, 10, 463},
+ dictWord{11, 10, 472},
+ dictWord{13, 10, 363},
+ dictWord{144, 10, 52},
+ dictWord{134, 0, 1729},
+ dictWord{6, 0, 1999},
+ dictWord{136, 0, 969},
+ dictWord{4, 10, 134},
+ dictWord{133, 10, 372},
+ dictWord{4, 0, 60},
+ dictWord{7, 0, 941},
+ dictWord{7, 0, 1800},
+ dictWord{8, 0, 314},
+ dictWord{
+ 9,
+ 0,
+ 700,
+ },
+ dictWord{139, 0, 487},
+ dictWord{134, 0, 1144},
+ dictWord{6, 11, 162},
+ dictWord{7, 11, 1960},
+ dictWord{136, 11, 831},
+ dictWord{132, 11, 706},
+ dictWord{135, 0, 1147},
+ dictWord{138, 11, 426},
+ dictWord{138, 11, 89},
+ dictWord{7, 0, 1853},
+ dictWord{138, 0, 437},
+ dictWord{136, 0, 419},
+ dictWord{
+ 135,
+ 10,
+ 1634,
+ },
+ dictWord{133, 0, 828},
+ dictWord{5, 0, 806},
+ dictWord{7, 0, 176},
+ dictWord{7, 0, 178},
+ dictWord{7, 0, 1240},
+ dictWord{7, 0, 1976},
+ dictWord{
+ 132,
+ 10,
+ 644,
+ },
+ dictWord{135, 11, 1877},
+ dictWord{5, 11, 420},
+ dictWord{135, 11, 1449},
+ dictWord{4, 0, 51},
+ dictWord{5, 0, 39},
+ dictWord{6, 0, 4},
+ dictWord{7, 0, 591},
+ dictWord{7, 0, 849},
+ dictWord{7, 0, 951},
+ dictWord{7, 0, 1613},
+ dictWord{7, 0, 1760},
+ dictWord{7, 0, 1988},
+ dictWord{9, 0, 434},
+ dictWord{10, 0, 754},
+ dictWord{
+ 11,
+ 0,
+ 25,
+ },
+ dictWord{139, 0, 37},
+ dictWord{10, 11, 57},
+ dictWord{138, 11, 277},
+ dictWord{135, 10, 540},
+ dictWord{132, 11, 204},
+ dictWord{135, 0, 159},
+ dictWord{139, 11, 231},
+ dictWord{133, 0, 902},
+ dictWord{7, 0, 928},
+ dictWord{7, 11, 366},
+ dictWord{9, 11, 287},
+ dictWord{12, 11, 199},
+ dictWord{12, 11, 556},
+ dictWord{140, 11, 577},
+ dictWord{6, 10, 623},
+ dictWord{136, 10, 789},
+ dictWord{4, 10, 908},
+ dictWord{5, 10, 359},
+ dictWord{5, 10, 508},
+ dictWord{6, 10, 1723},
+ dictWord{7, 10, 343},
+ dictWord{7, 10, 1996},
+ dictWord{135, 10, 2026},
+ dictWord{134, 0, 270},
+ dictWord{4, 10, 341},
+ dictWord{135, 10, 480},
+ dictWord{
+ 5,
+ 11,
+ 356,
+ },
+ dictWord{135, 11, 224},
+ dictWord{11, 11, 588},
+ dictWord{11, 11, 864},
+ dictWord{11, 11, 968},
+ dictWord{143, 11, 160},
+ dictWord{132, 0, 556},
+ dictWord{137, 0, 801},
+ dictWord{132, 0, 416},
+ dictWord{142, 0, 372},
+ dictWord{5, 0, 152},
+ dictWord{5, 0, 197},
+ dictWord{7, 0, 340},
+ dictWord{7, 0, 867},
+ dictWord{
+ 10,
+ 0,
+ 548,
+ },
+ dictWord{10, 0, 581},
+ dictWord{11, 0, 6},
+ dictWord{12, 0, 3},
+ dictWord{12, 0, 19},
+ dictWord{14, 0, 110},
+ dictWord{142, 0, 289},
+ dictWord{139, 0, 369},
+ dictWord{7, 11, 630},
+ dictWord{9, 11, 567},
+ dictWord{11, 11, 150},
+ dictWord{11, 11, 444},
+ dictWord{141, 11, 119},
+ dictWord{134, 11, 539},
+ dictWord{
+ 7,
+ 10,
+ 1995,
+ },
+ dictWord{8, 10, 299},
+ dictWord{11, 10, 890},
+ dictWord{140, 10, 674},
+ dictWord{7, 0, 34},
+ dictWord{7, 0, 190},
+ dictWord{8, 0, 28},
+ dictWord{8, 0, 141},
+ dictWord{8, 0, 444},
+ dictWord{8, 0, 811},
+ dictWord{9, 0, 468},
+ dictWord{11, 0, 334},
+ dictWord{12, 0, 24},
+ dictWord{12, 0, 386},
+ dictWord{140, 0, 576},
+ dictWord{
+ 133,
+ 0,
+ 757,
+ },
+ dictWord{7, 0, 1553},
+ dictWord{136, 0, 898},
+ dictWord{133, 0, 721},
+ dictWord{136, 0, 1012},
+ dictWord{4, 0, 789},
+ dictWord{5, 0, 647},
+ dictWord{
+ 135,
+ 0,
+ 1102,
+ },
+ dictWord{132, 0, 898},
+ dictWord{10, 0, 183},
+ dictWord{4, 10, 238},
+ dictWord{5, 10, 503},
+ dictWord{6, 10, 179},
+ dictWord{7, 10, 2003},
+ dictWord{
+ 8,
+ 10,
+ 381,
+ },
+ dictWord{8, 10, 473},
+ dictWord{9, 10, 149},
+ dictWord{10, 10, 788},
+ dictWord{15, 10, 45},
+ dictWord{15, 10, 86},
+ dictWord{20, 10, 110},
+ dictWord{
+ 150,
+ 10,
+ 57,
+ },
+ dictWord{9, 0, 136},
+ dictWord{19, 0, 107},
+ dictWord{4, 10, 121},
+ dictWord{5, 10, 156},
+ dictWord{5, 10, 349},
+ dictWord{10, 10, 605},
+ dictWord{
+ 142,
+ 10,
+ 342,
+ },
+ dictWord{4, 11, 235},
+ dictWord{135, 11, 255},
+ dictWord{4, 11, 194},
+ dictWord{5, 11, 584},
+ dictWord{6, 11, 384},
+ dictWord{7, 11, 583},
+ dictWord{
+ 10,
+ 11,
+ 761,
+ },
+ dictWord{11, 11, 760},
+ dictWord{139, 11, 851},
+ dictWord{6, 10, 80},
+ dictWord{6, 10, 1694},
+ dictWord{7, 10, 173},
+ dictWord{7, 10, 1974},
+ dictWord{
+ 9,
+ 10,
+ 547,
+ },
+ dictWord{10, 10, 730},
+ dictWord{14, 10, 18},
+ dictWord{150, 10, 39},
+ dictWord{4, 10, 923},
+ dictWord{134, 10, 1711},
+ dictWord{5, 0, 277},
+ dictWord{141, 0, 247},
+ dictWord{132, 0, 435},
+ dictWord{133, 11, 562},
+ dictWord{134, 0, 1311},
+ dictWord{5, 11, 191},
+ dictWord{137, 11, 271},
+ dictWord{
+ 132,
+ 10,
+ 595,
+ },
+ dictWord{7, 11, 1537},
+ dictWord{14, 11, 96},
+ dictWord{143, 11, 73},
+ dictWord{5, 0, 437},
+ dictWord{7, 0, 502},
+ dictWord{7, 0, 519},
+ dictWord{7, 0, 1122},
+ dictWord{7, 0, 1751},
+ dictWord{14, 0, 211},
+ dictWord{6, 10, 459},
+ dictWord{7, 10, 1753},
+ dictWord{7, 10, 1805},
+ dictWord{8, 10, 658},
+ dictWord{9, 10, 1},
+ dictWord{11, 10, 959},
+ dictWord{141, 10, 446},
+ dictWord{6, 0, 814},
+ dictWord{4, 11, 470},
+ dictWord{5, 11, 473},
+ dictWord{6, 11, 153},
+ dictWord{7, 11, 1503},
+ dictWord{7, 11, 1923},
+ dictWord{10, 11, 701},
+ dictWord{11, 11, 132},
+ dictWord{11, 11, 168},
+ dictWord{11, 11, 227},
+ dictWord{11, 11, 320},
+ dictWord{
+ 11,
+ 11,
+ 436,
+ },
+ dictWord{11, 11, 525},
+ dictWord{11, 11, 855},
+ dictWord{12, 11, 41},
+ dictWord{12, 11, 286},
+ dictWord{13, 11, 103},
+ dictWord{13, 11, 284},
+ dictWord{
+ 14,
+ 11,
+ 255,
+ },
+ dictWord{14, 11, 262},
+ dictWord{15, 11, 117},
+ dictWord{143, 11, 127},
+ dictWord{5, 0, 265},
+ dictWord{6, 0, 212},
+ dictWord{135, 0, 28},
+ dictWord{
+ 138,
+ 0,
+ 750,
+ },
+ dictWord{133, 11, 327},
+ dictWord{6, 11, 552},
+ dictWord{7, 11, 1754},
+ dictWord{137, 11, 604},
+ dictWord{134, 0, 2012},
+ dictWord{132, 0, 702},
+ dictWord{5, 11, 80},
+ dictWord{6, 11, 405},
+ dictWord{7, 11, 403},
+ dictWord{7, 11, 1502},
+ dictWord{7, 11, 1626},
+ dictWord{8, 11, 456},
+ dictWord{9, 11, 487},
+ dictWord{9, 11, 853},
+ dictWord{9, 11, 889},
+ dictWord{10, 11, 309},
+ dictWord{11, 11, 721},
+ dictWord{11, 11, 994},
+ dictWord{12, 11, 430},
+ dictWord{
+ 141,
+ 11,
+ 165,
+ },
+ dictWord{5, 0, 808},
+ dictWord{135, 0, 2045},
+ dictWord{5, 0, 166},
+ dictWord{8, 0, 739},
+ dictWord{140, 0, 511},
+ dictWord{134, 10, 490},
+ dictWord{
+ 4,
+ 11,
+ 453,
+ },
+ dictWord{5, 11, 887},
+ dictWord{6, 11, 535},
+ dictWord{8, 11, 6},
+ dictWord{136, 11, 543},
+ dictWord{4, 0, 119},
+ dictWord{5, 0, 170},
+ dictWord{5, 0, 447},
+ dictWord{7, 0, 1708},
+ dictWord{7, 0, 1889},
+ dictWord{9, 0, 357},
+ dictWord{9, 0, 719},
+ dictWord{12, 0, 486},
+ dictWord{140, 0, 596},
+ dictWord{137, 0, 500},
+ dictWord{
+ 7,
+ 10,
+ 250,
+ },
+ dictWord{136, 10, 507},
+ dictWord{132, 10, 158},
+ dictWord{6, 0, 809},
+ dictWord{134, 0, 1500},
+ dictWord{9, 0, 327},
+ dictWord{11, 0, 350},
+ dictWord{11, 0, 831},
+ dictWord{13, 0, 352},
+ dictWord{4, 10, 140},
+ dictWord{7, 10, 362},
+ dictWord{8, 10, 209},
+ dictWord{9, 10, 10},
+ dictWord{9, 10, 503},
+ dictWord{
+ 9,
+ 10,
+ 614,
+ },
+ dictWord{10, 10, 689},
+ dictWord{11, 10, 327},
+ dictWord{11, 10, 725},
+ dictWord{12, 10, 252},
+ dictWord{12, 10, 583},
+ dictWord{13, 10, 192},
+ dictWord{14, 10, 269},
+ dictWord{14, 10, 356},
+ dictWord{148, 10, 50},
+ dictWord{135, 11, 741},
+ dictWord{4, 0, 450},
+ dictWord{7, 0, 1158},
+ dictWord{19, 10, 1},
+ dictWord{19, 10, 26},
+ dictWord{150, 10, 9},
+ dictWord{6, 0, 597},
+ dictWord{135, 0, 1318},
+ dictWord{134, 0, 1602},
+ dictWord{6, 10, 228},
+ dictWord{7, 10, 1341},
+ dictWord{9, 10, 408},
+ dictWord{138, 10, 343},
+ dictWord{7, 0, 1375},
+ dictWord{7, 0, 1466},
+ dictWord{138, 0, 331},
+ dictWord{132, 0, 754},
+ dictWord{
+ 132,
+ 10,
+ 557,
+ },
+ dictWord{5, 11, 101},
+ dictWord{6, 11, 88},
+ dictWord{6, 11, 543},
+ dictWord{7, 11, 1677},
+ dictWord{9, 11, 100},
+ dictWord{10, 11, 677},
+ dictWord{
+ 14,
+ 11,
+ 169,
+ },
+ dictWord{14, 11, 302},
+ dictWord{14, 11, 313},
+ dictWord{15, 11, 48},
+ dictWord{143, 11, 84},
+ dictWord{134, 0, 1368},
+ dictWord{4, 11, 310},
+ dictWord{
+ 9,
+ 11,
+ 795,
+ },
+ dictWord{10, 11, 733},
+ dictWord{11, 11, 451},
+ dictWord{12, 11, 249},
+ dictWord{14, 11, 115},
+ dictWord{14, 11, 286},
+ dictWord{143, 11, 100},
+ dictWord{132, 10, 548},
+ dictWord{10, 0, 557},
+ dictWord{7, 10, 197},
+ dictWord{8, 10, 142},
+ dictWord{8, 10, 325},
+ dictWord{9, 10, 150},
+ dictWord{9, 10, 596},
+ dictWord{10, 10, 353},
+ dictWord{11, 10, 74},
+ dictWord{11, 10, 315},
+ dictWord{12, 10, 662},
+ dictWord{12, 10, 681},
+ dictWord{14, 10, 423},
+ dictWord{
+ 143,
+ 10,
+ 141,
+ },
+ dictWord{133, 11, 587},
+ dictWord{5, 0, 850},
+ dictWord{136, 0, 799},
+ dictWord{10, 0, 908},
+ dictWord{12, 0, 701},
+ dictWord{12, 0, 757},
+ dictWord{
+ 142,
+ 0,
+ 466,
+ },
+ dictWord{4, 0, 62},
+ dictWord{5, 0, 275},
+ dictWord{18, 0, 19},
+ dictWord{6, 10, 399},
+ dictWord{6, 10, 579},
+ dictWord{7, 10, 692},
+ dictWord{7, 10, 846},
+ dictWord{
+ 7,
+ 10,
+ 1015,
+ },
+ dictWord{7, 10, 1799},
+ dictWord{8, 10, 403},
+ dictWord{9, 10, 394},
+ dictWord{10, 10, 133},
+ dictWord{12, 10, 4},
+ dictWord{12, 10, 297},
+ dictWord{12, 10, 452},
+ dictWord{16, 10, 81},
+ dictWord{18, 10, 25},
+ dictWord{21, 10, 14},
+ dictWord{22, 10, 12},
+ dictWord{151, 10, 18},
+ dictWord{12, 0, 459},
+ dictWord{
+ 7,
+ 10,
+ 1546,
+ },
+ dictWord{11, 10, 299},
+ dictWord{142, 10, 407},
+ dictWord{132, 10, 177},
+ dictWord{132, 11, 498},
+ dictWord{7, 11, 217},
+ dictWord{
+ 8,
+ 11,
+ 140,
+ },
+ dictWord{138, 11, 610},
+ dictWord{5, 10, 411},
+ dictWord{135, 10, 653},
+ dictWord{134, 0, 1802},
+ dictWord{7, 10, 439},
+ dictWord{10, 10, 727},
+ dictWord{11, 10, 260},
+ dictWord{139, 10, 684},
+ dictWord{133, 11, 905},
+ dictWord{11, 11, 580},
+ dictWord{142, 11, 201},
+ dictWord{134, 0, 1397},
+ dictWord{
+ 5,
+ 10,
+ 208,
+ },
+ dictWord{7, 10, 753},
+ dictWord{135, 10, 1528},
+ dictWord{7, 0, 238},
+ dictWord{7, 0, 2033},
+ dictWord{8, 0, 120},
+ dictWord{8, 0, 188},
+ dictWord{8, 0, 659},
+ dictWord{9, 0, 598},
+ dictWord{10, 0, 466},
+ dictWord{12, 0, 342},
+ dictWord{12, 0, 588},
+ dictWord{13, 0, 503},
+ dictWord{14, 0, 246},
+ dictWord{143, 0, 92},
+ dictWord{135, 11, 1041},
+ dictWord{4, 11, 456},
+ dictWord{7, 11, 105},
+ dictWord{7, 11, 358},
+ dictWord{7, 11, 1637},
+ dictWord{8, 11, 643},
+ dictWord{139, 11, 483},
+ dictWord{6, 0, 1318},
+ dictWord{134, 0, 1324},
+ dictWord{4, 0, 201},
+ dictWord{7, 0, 1744},
+ dictWord{8, 0, 602},
+ dictWord{11, 0, 247},
+ dictWord{11, 0, 826},
+ dictWord{17, 0, 65},
+ dictWord{133, 10, 242},
+ dictWord{8, 0, 164},
+ dictWord{146, 0, 62},
+ dictWord{133, 10, 953},
+ dictWord{139, 10, 802},
+ dictWord{133, 0, 615},
+ dictWord{7, 11, 1566},
+ dictWord{8, 11, 269},
+ dictWord{9, 11, 212},
+ dictWord{9, 11, 718},
+ dictWord{14, 11, 15},
+ dictWord{14, 11, 132},
+ dictWord{142, 11, 227},
+ dictWord{133, 10, 290},
+ dictWord{132, 10, 380},
+ dictWord{5, 10, 52},
+ dictWord{7, 10, 277},
+ dictWord{9, 10, 368},
+ dictWord{139, 10, 791},
+ dictWord{
+ 135,
+ 0,
+ 1243,
+ },
+ dictWord{133, 11, 539},
+ dictWord{11, 11, 919},
+ dictWord{141, 11, 409},
+ dictWord{136, 0, 968},
+ dictWord{133, 11, 470},
+ dictWord{134, 0, 882},
+ dictWord{132, 0, 907},
+ dictWord{5, 0, 100},
+ dictWord{10, 0, 329},
+ dictWord{12, 0, 416},
+ dictWord{149, 0, 29},
+ dictWord{10, 10, 138},
+ dictWord{139, 10, 476},
+ dictWord{5, 10, 725},
+ dictWord{5, 10, 727},
+ dictWord{6, 11, 91},
+ dictWord{7, 11, 435},
+ dictWord{135, 10, 1811},
+ dictWord{4, 11, 16},
+ dictWord{5, 11, 316},
+ dictWord{5, 11, 842},
+ dictWord{6, 11, 370},
+ dictWord{6, 11, 1778},
+ dictWord{8, 11, 166},
+ dictWord{11, 11, 812},
+ dictWord{12, 11, 206},
+ dictWord{12, 11, 351},
+ dictWord{14, 11, 418},
+ dictWord{16, 11, 15},
+ dictWord{16, 11, 34},
+ dictWord{18, 11, 3},
+ dictWord{19, 11, 3},
+ dictWord{19, 11, 7},
+ dictWord{20, 11, 4},
+ dictWord{
+ 149,
+ 11,
+ 21,
+ },
+ dictWord{132, 0, 176},
+ dictWord{5, 0, 636},
+ dictWord{5, 0, 998},
+ dictWord{7, 0, 9},
+ dictWord{7, 0, 1508},
+ dictWord{8, 0, 26},
+ dictWord{9, 0, 317},
+ dictWord{
+ 9,
+ 0,
+ 358,
+ },
+ dictWord{10, 0, 210},
+ dictWord{10, 0, 292},
+ dictWord{10, 0, 533},
+ dictWord{11, 0, 555},
+ dictWord{12, 0, 526},
+ dictWord{12, 0, 607},
+ dictWord{
+ 13,
+ 0,
+ 263,
+ },
+ dictWord{13, 0, 459},
+ dictWord{142, 0, 271},
+ dictWord{6, 0, 256},
+ dictWord{8, 0, 265},
+ dictWord{4, 10, 38},
+ dictWord{7, 10, 307},
+ dictWord{7, 10, 999},
+ dictWord{7, 10, 1481},
+ dictWord{7, 10, 1732},
+ dictWord{7, 10, 1738},
+ dictWord{9, 10, 414},
+ dictWord{11, 10, 316},
+ dictWord{12, 10, 52},
+ dictWord{13, 10, 420},
+ dictWord{147, 10, 100},
+ dictWord{135, 10, 1296},
+ dictWord{4, 11, 611},
+ dictWord{133, 11, 606},
+ dictWord{4, 0, 643},
+ dictWord{142, 11, 21},
+ dictWord{
+ 133,
+ 11,
+ 715,
+ },
+ dictWord{133, 10, 723},
+ dictWord{6, 0, 610},
+ dictWord{135, 11, 597},
+ dictWord{10, 0, 127},
+ dictWord{141, 0, 27},
+ dictWord{6, 0, 1995},
+ dictWord{
+ 6,
+ 0,
+ 2001,
+ },
+ dictWord{8, 0, 119},
+ dictWord{136, 0, 973},
+ dictWord{4, 11, 149},
+ dictWord{138, 11, 368},
+ dictWord{12, 0, 522},
+ dictWord{4, 11, 154},
+ dictWord{
+ 5,
+ 10,
+ 109,
+ },
+ dictWord{6, 10, 1784},
+ dictWord{7, 11, 1134},
+ dictWord{7, 10, 1895},
+ dictWord{8, 11, 105},
+ dictWord{12, 10, 296},
+ dictWord{140, 10, 302},
+ dictWord{4, 11, 31},
+ dictWord{6, 11, 429},
+ dictWord{7, 11, 962},
+ dictWord{9, 11, 458},
+ dictWord{139, 11, 691},
+ dictWord{10, 0, 553},
+ dictWord{11, 0, 876},
+ dictWord{13, 0, 193},
+ dictWord{13, 0, 423},
+ dictWord{14, 0, 166},
+ dictWord{19, 0, 84},
+ dictWord{4, 11, 312},
+ dictWord{5, 10, 216},
+ dictWord{7, 10, 1879},
+ dictWord{
+ 9,
+ 10,
+ 141,
+ },
+ dictWord{9, 10, 270},
+ dictWord{9, 10, 679},
+ dictWord{10, 10, 159},
+ dictWord{11, 10, 197},
+ dictWord{12, 10, 538},
+ dictWord{12, 10, 559},
+ dictWord{14, 10, 144},
+ dictWord{14, 10, 167},
+ dictWord{143, 10, 67},
+ dictWord{134, 0, 1582},
+ dictWord{7, 0, 1578},
+ dictWord{135, 11, 1578},
+ dictWord{
+ 137,
+ 10,
+ 81,
+ },
+ dictWord{132, 11, 236},
+ dictWord{134, 10, 391},
+ dictWord{134, 0, 795},
+ dictWord{7, 10, 322},
+ dictWord{136, 10, 249},
+ dictWord{5, 11, 836},
+ dictWord{
+ 5,
+ 11,
+ 857,
+ },
+ dictWord{6, 11, 1680},
+ dictWord{7, 11, 59},
+ dictWord{147, 11, 53},
+ dictWord{135, 0, 432},
+ dictWord{10, 11, 68},
+ dictWord{139, 11, 494},
+ dictWord{4, 11, 81},
+ dictWord{139, 11, 867},
+ dictWord{7, 0, 126},
+ dictWord{136, 0, 84},
+ dictWord{142, 11, 280},
+ dictWord{5, 11, 282},
+ dictWord{8, 11, 650},
+ dictWord{
+ 9,
+ 11,
+ 295,
+ },
+ dictWord{9, 11, 907},
+ dictWord{138, 11, 443},
+ dictWord{136, 0, 790},
+ dictWord{5, 10, 632},
+ dictWord{138, 10, 526},
+ dictWord{6, 0, 64},
+ dictWord{12, 0, 377},
+ dictWord{13, 0, 309},
+ dictWord{14, 0, 141},
+ dictWord{14, 0, 429},
+ dictWord{14, 11, 141},
+ dictWord{142, 11, 429},
+ dictWord{134, 0, 1529},
+ dictWord{6, 0, 321},
+ dictWord{7, 0, 1857},
+ dictWord{9, 0, 530},
+ dictWord{19, 0, 99},
+ dictWord{7, 10, 948},
+ dictWord{7, 10, 1042},
+ dictWord{8, 10, 235},
+ dictWord{
+ 8,
+ 10,
+ 461,
+ },
+ dictWord{9, 10, 453},
+ dictWord{10, 10, 354},
+ dictWord{145, 10, 77},
+ dictWord{7, 0, 1104},
+ dictWord{11, 0, 269},
+ dictWord{11, 0, 539},
+ dictWord{
+ 11,
+ 0,
+ 627,
+ },
+ dictWord{11, 0, 706},
+ dictWord{11, 0, 975},
+ dictWord{12, 0, 248},
+ dictWord{12, 0, 434},
+ dictWord{12, 0, 600},
+ dictWord{12, 0, 622},
+ dictWord{
+ 13,
+ 0,
+ 297,
+ },
+ dictWord{13, 0, 485},
+ dictWord{14, 0, 69},
+ dictWord{14, 0, 409},
+ dictWord{143, 0, 108},
+ dictWord{4, 10, 362},
+ dictWord{7, 10, 52},
+ dictWord{7, 10, 303},
+ dictWord{10, 11, 70},
+ dictWord{12, 11, 26},
+ dictWord{14, 11, 17},
+ dictWord{14, 11, 178},
+ dictWord{15, 11, 34},
+ dictWord{149, 11, 12},
+ dictWord{11, 0, 977},
+ dictWord{141, 0, 507},
+ dictWord{9, 0, 34},
+ dictWord{139, 0, 484},
+ dictWord{5, 10, 196},
+ dictWord{6, 10, 486},
+ dictWord{7, 10, 212},
+ dictWord{8, 10, 309},
+ dictWord{136, 10, 346},
+ dictWord{6, 0, 1700},
+ dictWord{7, 0, 26},
+ dictWord{7, 0, 293},
+ dictWord{7, 0, 382},
+ dictWord{7, 0, 1026},
+ dictWord{7, 0, 1087},
+ dictWord{
+ 7,
+ 0,
+ 2027,
+ },
+ dictWord{8, 0, 24},
+ dictWord{8, 0, 114},
+ dictWord{8, 0, 252},
+ dictWord{8, 0, 727},
+ dictWord{8, 0, 729},
+ dictWord{9, 0, 30},
+ dictWord{9, 0, 199},
+ dictWord{
+ 9,
+ 0,
+ 231,
+ },
+ dictWord{9, 0, 251},
+ dictWord{9, 0, 334},
+ dictWord{9, 0, 361},
+ dictWord{9, 0, 712},
+ dictWord{10, 0, 55},
+ dictWord{10, 0, 60},
+ dictWord{10, 0, 232},
+ dictWord{
+ 10,
+ 0,
+ 332,
+ },
+ dictWord{10, 0, 384},
+ dictWord{10, 0, 396},
+ dictWord{10, 0, 504},
+ dictWord{10, 0, 542},
+ dictWord{10, 0, 652},
+ dictWord{11, 0, 20},
+ dictWord{11, 0, 48},
+ dictWord{11, 0, 207},
+ dictWord{11, 0, 291},
+ dictWord{11, 0, 298},
+ dictWord{11, 0, 342},
+ dictWord{11, 0, 365},
+ dictWord{11, 0, 394},
+ dictWord{11, 0, 620},
+ dictWord{11, 0, 705},
+ dictWord{11, 0, 1017},
+ dictWord{12, 0, 123},
+ dictWord{12, 0, 340},
+ dictWord{12, 0, 406},
+ dictWord{12, 0, 643},
+ dictWord{13, 0, 61},
+ dictWord{
+ 13,
+ 0,
+ 269,
+ },
+ dictWord{13, 0, 311},
+ dictWord{13, 0, 319},
+ dictWord{13, 0, 486},
+ dictWord{14, 0, 234},
+ dictWord{15, 0, 62},
+ dictWord{15, 0, 85},
+ dictWord{16, 0, 71},
+ dictWord{18, 0, 119},
+ dictWord{20, 0, 105},
+ dictWord{135, 10, 1912},
+ dictWord{4, 11, 71},
+ dictWord{5, 11, 376},
+ dictWord{7, 11, 119},
+ dictWord{138, 11, 665},
+ dictWord{10, 0, 918},
+ dictWord{10, 0, 926},
+ dictWord{4, 10, 686},
+ dictWord{136, 11, 55},
+ dictWord{138, 10, 625},
+ dictWord{136, 10, 706},
+ dictWord{
+ 132,
+ 11,
+ 479,
+ },
+ dictWord{4, 10, 30},
+ dictWord{133, 10, 43},
+ dictWord{6, 0, 379},
+ dictWord{7, 0, 270},
+ dictWord{8, 0, 176},
+ dictWord{8, 0, 183},
+ dictWord{9, 0, 432},
+ dictWord{
+ 9,
+ 0,
+ 661,
+ },
+ dictWord{12, 0, 247},
+ dictWord{12, 0, 617},
+ dictWord{18, 0, 125},
+ dictWord{7, 11, 607},
+ dictWord{8, 11, 99},
+ dictWord{152, 11, 4},
+ dictWord{
+ 5,
+ 0,
+ 792,
+ },
+ dictWord{133, 0, 900},
+ dictWord{4, 11, 612},
+ dictWord{133, 11, 561},
+ dictWord{4, 11, 41},
+ dictWord{4, 10, 220},
+ dictWord{5, 11, 74},
+ dictWord{
+ 7,
+ 10,
+ 1535,
+ },
+ dictWord{7, 11, 1627},
+ dictWord{11, 11, 871},
+ dictWord{140, 11, 619},
+ dictWord{135, 0, 1920},
+ dictWord{7, 11, 94},
+ dictWord{11, 11, 329},
+ dictWord{11, 11, 965},
+ dictWord{12, 11, 241},
+ dictWord{14, 11, 354},
+ dictWord{15, 11, 22},
+ dictWord{148, 11, 63},
+ dictWord{9, 11, 209},
+ dictWord{137, 11, 300},
+ dictWord{134, 0, 771},
+ dictWord{135, 0, 1979},
+ dictWord{4, 0, 901},
+ dictWord{133, 0, 776},
+ dictWord{142, 0, 254},
+ dictWord{133, 11, 98},
+ dictWord{
+ 9,
+ 11,
+ 16,
+ },
+ dictWord{141, 11, 386},
+ dictWord{133, 11, 984},
+ dictWord{4, 11, 182},
+ dictWord{6, 11, 205},
+ dictWord{135, 11, 220},
+ dictWord{7, 10, 1725},
+ dictWord{
+ 7,
+ 10,
+ 1774,
+ },
+ dictWord{138, 10, 393},
+ dictWord{5, 10, 263},
+ dictWord{134, 10, 414},
+ dictWord{4, 11, 42},
+ dictWord{9, 11, 205},
+ dictWord{9, 11, 786},
+ dictWord{138, 11, 659},
+ dictWord{14, 0, 140},
+ dictWord{148, 0, 41},
+ dictWord{8, 0, 440},
+ dictWord{10, 0, 359},
+ dictWord{6, 10, 178},
+ dictWord{6, 11, 289},
+ dictWord{
+ 6,
+ 10,
+ 1750,
+ },
+ dictWord{7, 11, 1670},
+ dictWord{9, 10, 690},
+ dictWord{10, 10, 155},
+ dictWord{10, 10, 373},
+ dictWord{11, 10, 698},
+ dictWord{12, 11, 57},
+ dictWord{13, 10, 155},
+ dictWord{20, 10, 93},
+ dictWord{151, 11, 4},
+ dictWord{4, 0, 37},
+ dictWord{5, 0, 334},
+ dictWord{7, 0, 1253},
+ dictWord{151, 11, 25},
+ dictWord{
+ 4,
+ 0,
+ 508,
+ },
+ dictWord{4, 11, 635},
+ dictWord{5, 10, 97},
+ dictWord{137, 10, 393},
+ dictWord{139, 11, 533},
+ dictWord{4, 0, 640},
+ dictWord{133, 0, 513},
+ dictWord{
+ 134,
+ 10,
+ 1639,
+ },
+ dictWord{132, 11, 371},
+ dictWord{4, 11, 272},
+ dictWord{7, 11, 836},
+ dictWord{7, 11, 1651},
+ dictWord{145, 11, 89},
+ dictWord{5, 11, 825},
+ dictWord{6, 11, 444},
+ dictWord{6, 11, 1640},
+ dictWord{136, 11, 308},
+ dictWord{4, 10, 191},
+ dictWord{7, 10, 934},
+ dictWord{8, 10, 647},
+ dictWord{145, 10, 97},
+ dictWord{12, 0, 246},
+ dictWord{15, 0, 162},
+ dictWord{19, 0, 64},
+ dictWord{20, 0, 8},
+ dictWord{20, 0, 95},
+ dictWord{22, 0, 24},
+ dictWord{152, 0, 17},
+ dictWord{4, 0, 533},
+ dictWord{5, 10, 165},
+ dictWord{9, 10, 346},
+ dictWord{138, 10, 655},
+ dictWord{5, 11, 737},
+ dictWord{139, 10, 885},
+ dictWord{133, 10, 877},
+ dictWord{
+ 8,
+ 10,
+ 128,
+ },
+ dictWord{139, 10, 179},
+ dictWord{137, 11, 307},
+ dictWord{140, 0, 752},
+ dictWord{133, 0, 920},
+ dictWord{135, 0, 1048},
+ dictWord{5, 0, 153},
+ dictWord{
+ 6,
+ 0,
+ 580,
+ },
+ dictWord{6, 10, 1663},
+ dictWord{7, 10, 132},
+ dictWord{7, 10, 1154},
+ dictWord{7, 10, 1415},
+ dictWord{7, 10, 1507},
+ dictWord{12, 10, 493},
+ dictWord{15, 10, 105},
+ dictWord{151, 10, 15},
+ dictWord{5, 10, 459},
+ dictWord{7, 10, 1073},
+ dictWord{8, 10, 241},
+ dictWord{136, 10, 334},
+ dictWord{138, 0, 391},
+ dictWord{135, 0, 1952},
+ dictWord{133, 11, 525},
+ dictWord{8, 11, 641},
+ dictWord{11, 11, 388},
+ dictWord{140, 11, 580},
+ dictWord{142, 0, 126},
+ dictWord{
+ 134,
+ 0,
+ 640,
+ },
+ dictWord{132, 0, 483},
+ dictWord{7, 0, 1616},
+ dictWord{9, 0, 69},
+ dictWord{6, 10, 324},
+ dictWord{6, 10, 520},
+ dictWord{7, 10, 338},
+ dictWord{
+ 7,
+ 10,
+ 1729,
+ },
+ dictWord{8, 10, 228},
+ dictWord{139, 10, 750},
+ dictWord{5, 11, 493},
+ dictWord{134, 11, 528},
+ dictWord{135, 0, 734},
+ dictWord{4, 11, 174},
+ dictWord{135, 11, 911},
+ dictWord{138, 0, 480},
+ dictWord{9, 0, 495},
+ dictWord{146, 0, 104},
+ dictWord{135, 10, 705},
+ dictWord{9, 0, 472},
+ dictWord{4, 10, 73},
+ dictWord{6, 10, 612},
+ dictWord{7, 10, 927},
+ dictWord{7, 10, 1330},
+ dictWord{7, 10, 1822},
+ dictWord{8, 10, 217},
+ dictWord{9, 10, 765},
+ dictWord{9, 10, 766},
+ dictWord{10, 10, 408},
+ dictWord{11, 10, 51},
+ dictWord{11, 10, 793},
+ dictWord{12, 10, 266},
+ dictWord{15, 10, 158},
+ dictWord{20, 10, 89},
+ dictWord{150, 10, 32},
+ dictWord{7, 11, 548},
+ dictWord{137, 11, 58},
+ dictWord{4, 11, 32},
+ dictWord{5, 11, 215},
+ dictWord{6, 11, 269},
+ dictWord{7, 11, 1782},
+ dictWord{7, 11, 1892},
+ dictWord{10, 11, 16},
+ dictWord{11, 11, 822},
+ dictWord{11, 11, 954},
+ dictWord{141, 11, 481},
+ dictWord{132, 0, 874},
+ dictWord{9, 0, 229},
+ dictWord{5, 10, 389},
+ dictWord{136, 10, 636},
+ dictWord{7, 11, 1749},
+ dictWord{136, 11, 477},
+ dictWord{134, 0, 948},
+ dictWord{5, 11, 308},
+ dictWord{135, 11, 1088},
+ dictWord{
+ 4,
+ 0,
+ 748,
+ },
+ dictWord{139, 0, 1009},
+ dictWord{136, 10, 21},
+ dictWord{6, 0, 555},
+ dictWord{135, 0, 485},
+ dictWord{5, 11, 126},
+ dictWord{8, 11, 297},
+ dictWord{
+ 9,
+ 11,
+ 366,
+ },
+ dictWord{9, 11, 445},
+ dictWord{12, 11, 53},
+ dictWord{12, 11, 374},
+ dictWord{141, 11, 492},
+ dictWord{7, 11, 1551},
+ dictWord{139, 11, 361},
+ dictWord{136, 0, 193},
+ dictWord{136, 0, 472},
+ dictWord{8, 0, 653},
+ dictWord{13, 0, 93},
+ dictWord{147, 0, 14},
+ dictWord{132, 0, 984},
+ dictWord{132, 11, 175},
+ dictWord{5, 0, 172},
+ dictWord{6, 0, 1971},
+ dictWord{132, 11, 685},
+ dictWord{149, 11, 8},
+ dictWord{133, 11, 797},
+ dictWord{13, 0, 83},
+ dictWord{5, 10, 189},
+ dictWord{
+ 7,
+ 10,
+ 442,
+ },
+ dictWord{7, 10, 443},
+ dictWord{8, 10, 281},
+ dictWord{12, 10, 174},
+ dictWord{141, 10, 261},
+ dictWord{134, 0, 1568},
+ dictWord{133, 11, 565},
+ dictWord{139, 0, 384},
+ dictWord{133, 0, 260},
+ dictWord{7, 0, 758},
+ dictWord{7, 0, 880},
+ dictWord{7, 0, 1359},
+ dictWord{9, 0, 164},
+ dictWord{9, 0, 167},
+ dictWord{
+ 10,
+ 0,
+ 156,
+ },
+ dictWord{10, 0, 588},
+ dictWord{12, 0, 101},
+ dictWord{14, 0, 48},
+ dictWord{15, 0, 70},
+ dictWord{6, 10, 2},
+ dictWord{7, 10, 1262},
+ dictWord{
+ 7,
+ 10,
+ 1737,
+ },
+ dictWord{8, 10, 22},
+ dictWord{8, 10, 270},
+ dictWord{8, 10, 612},
+ dictWord{9, 10, 312},
+ dictWord{9, 10, 436},
+ dictWord{10, 10, 311},
+ dictWord{
+ 10,
+ 10,
+ 623,
+ },
+ dictWord{11, 10, 72},
+ dictWord{11, 10, 330},
+ dictWord{11, 10, 455},
+ dictWord{12, 10, 321},
+ dictWord{12, 10, 504},
+ dictWord{12, 10, 530},
+ dictWord{
+ 12,
+ 10,
+ 543,
+ },
+ dictWord{13, 10, 17},
+ dictWord{13, 10, 156},
+ dictWord{13, 10, 334},
+ dictWord{17, 10, 60},
+ dictWord{148, 10, 64},
+ dictWord{4, 11, 252},
+ dictWord{
+ 7,
+ 11,
+ 1068,
+ },
+ dictWord{10, 11, 434},
+ dictWord{11, 11, 228},
+ dictWord{11, 11, 426},
+ dictWord{13, 11, 231},
+ dictWord{18, 11, 106},
+ dictWord{148, 11, 87},
+ dictWord{7, 10, 354},
+ dictWord{10, 10, 410},
+ dictWord{139, 10, 815},
+ dictWord{6, 0, 367},
+ dictWord{7, 10, 670},
+ dictWord{7, 10, 1327},
+ dictWord{8, 10, 411},
+ dictWord{8, 10, 435},
+ dictWord{9, 10, 653},
+ dictWord{9, 10, 740},
+ dictWord{10, 10, 385},
+ dictWord{11, 10, 222},
+ dictWord{11, 10, 324},
+ dictWord{11, 10, 829},
+ dictWord{140, 10, 611},
+ dictWord{7, 0, 1174},
+ dictWord{6, 10, 166},
+ dictWord{135, 10, 374},
+ dictWord{146, 0, 121},
+ dictWord{132, 0, 828},
+ dictWord{
+ 5,
+ 11,
+ 231,
+ },
+ dictWord{138, 11, 509},
+ dictWord{7, 11, 601},
+ dictWord{9, 11, 277},
+ dictWord{9, 11, 674},
+ dictWord{10, 11, 178},
+ dictWord{10, 11, 257},
+ dictWord{
+ 10,
+ 11,
+ 418,
+ },
+ dictWord{11, 11, 531},
+ dictWord{11, 11, 544},
+ dictWord{11, 11, 585},
+ dictWord{12, 11, 113},
+ dictWord{12, 11, 475},
+ dictWord{13, 11, 99},
+ dictWord{142, 11, 428},
+ dictWord{134, 0, 1541},
+ dictWord{135, 11, 1779},
+ dictWord{5, 0, 343},
+ dictWord{134, 10, 398},
+ dictWord{135, 10, 50},
+ dictWord{
+ 135,
+ 11,
+ 1683,
+ },
+ dictWord{4, 0, 440},
+ dictWord{7, 0, 57},
+ dictWord{8, 0, 167},
+ dictWord{8, 0, 375},
+ dictWord{9, 0, 82},
+ dictWord{9, 0, 561},
+ dictWord{9, 0, 744},
+ dictWord{
+ 10,
+ 0,
+ 620,
+ },
+ dictWord{137, 11, 744},
+ dictWord{134, 0, 926},
+ dictWord{6, 10, 517},
+ dictWord{7, 10, 1159},
+ dictWord{10, 10, 621},
+ dictWord{139, 10, 192},
+ dictWord{137, 0, 827},
+ dictWord{8, 0, 194},
+ dictWord{136, 0, 756},
+ dictWord{10, 10, 223},
+ dictWord{139, 10, 645},
+ dictWord{7, 10, 64},
+ dictWord{
+ 136,
+ 10,
+ 245,
+ },
+ dictWord{4, 11, 399},
+ dictWord{5, 11, 119},
+ dictWord{5, 11, 494},
+ dictWord{7, 11, 751},
+ dictWord{137, 11, 556},
+ dictWord{132, 0, 808},
+ dictWord{
+ 135,
+ 0,
+ 22,
+ },
+ dictWord{7, 10, 1763},
+ dictWord{140, 10, 310},
+ dictWord{5, 0, 639},
+ dictWord{7, 0, 1249},
+ dictWord{11, 0, 896},
+ dictWord{134, 11, 584},
+ dictWord{
+ 134,
+ 0,
+ 1614,
+ },
+ dictWord{135, 0, 860},
+ dictWord{135, 11, 1121},
+ dictWord{5, 10, 129},
+ dictWord{6, 10, 61},
+ dictWord{135, 10, 947},
+ dictWord{4, 0, 102},
+ dictWord{
+ 7,
+ 0,
+ 815,
+ },
+ dictWord{7, 0, 1699},
+ dictWord{139, 0, 964},
+ dictWord{13, 10, 505},
+ dictWord{141, 10, 506},
+ dictWord{139, 10, 1000},
+ dictWord{
+ 132,
+ 11,
+ 679,
+ },
+ dictWord{132, 0, 899},
+ dictWord{132, 0, 569},
+ dictWord{5, 11, 694},
+ dictWord{137, 11, 714},
+ dictWord{136, 0, 795},
+ dictWord{6, 0, 2045},
+ dictWord{
+ 139,
+ 11,
+ 7,
+ },
+ dictWord{6, 0, 52},
+ dictWord{9, 0, 104},
+ dictWord{9, 0, 559},
+ dictWord{12, 0, 308},
+ dictWord{147, 0, 87},
+ dictWord{4, 0, 301},
+ dictWord{132, 0, 604},
+ dictWord{133, 10, 637},
+ dictWord{136, 0, 779},
+ dictWord{5, 11, 143},
+ dictWord{5, 11, 769},
+ dictWord{6, 11, 1760},
+ dictWord{7, 11, 682},
+ dictWord{7, 11, 1992},
+ dictWord{136, 11, 736},
+ dictWord{137, 10, 590},
+ dictWord{147, 0, 32},
+ dictWord{137, 11, 527},
+ dictWord{5, 10, 280},
+ dictWord{135, 10, 1226},
+ dictWord{134, 0, 494},
+ dictWord{6, 0, 677},
+ dictWord{6, 0, 682},
+ dictWord{134, 0, 1044},
+ dictWord{133, 10, 281},
+ dictWord{135, 10, 1064},
+ dictWord{7, 0, 508},
+ dictWord{133, 11, 860},
+ dictWord{6, 11, 422},
+ dictWord{7, 11, 0},
+ dictWord{7, 11, 1544},
+ dictWord{9, 11, 577},
+ dictWord{11, 11, 990},
+ dictWord{12, 11, 141},
+ dictWord{12, 11, 453},
+ dictWord{13, 11, 47},
+ dictWord{141, 11, 266},
+ dictWord{134, 0, 1014},
+ dictWord{5, 11, 515},
+ dictWord{137, 11, 131},
+ dictWord{
+ 134,
+ 0,
+ 957,
+ },
+ dictWord{132, 11, 646},
+ dictWord{6, 0, 310},
+ dictWord{7, 0, 1849},
+ dictWord{8, 0, 72},
+ dictWord{8, 0, 272},
+ dictWord{8, 0, 431},
+ dictWord{9, 0, 12},
+ dictWord{
+ 9,
+ 0,
+ 376,
+ },
+ dictWord{10, 0, 563},
+ dictWord{10, 0, 630},
+ dictWord{10, 0, 796},
+ dictWord{10, 0, 810},
+ dictWord{11, 0, 367},
+ dictWord{11, 0, 599},
+ dictWord{
+ 11,
+ 0,
+ 686,
+ },
+ dictWord{140, 0, 672},
+ dictWord{7, 0, 570},
+ dictWord{4, 11, 396},
+ dictWord{7, 10, 120},
+ dictWord{7, 11, 728},
+ dictWord{8, 10, 489},
+ dictWord{9, 11, 117},
+ dictWord{9, 10, 319},
+ dictWord{10, 10, 820},
+ dictWord{11, 10, 1004},
+ dictWord{12, 10, 379},
+ dictWord{12, 10, 679},
+ dictWord{13, 10, 117},
+ dictWord{
+ 13,
+ 11,
+ 202,
+ },
+ dictWord{13, 10, 412},
+ dictWord{14, 10, 25},
+ dictWord{15, 10, 52},
+ dictWord{15, 10, 161},
+ dictWord{16, 10, 47},
+ dictWord{20, 11, 51},
+ dictWord{
+ 149,
+ 10,
+ 2,
+ },
+ dictWord{6, 11, 121},
+ dictWord{6, 11, 124},
+ dictWord{6, 11, 357},
+ dictWord{7, 11, 1138},
+ dictWord{7, 11, 1295},
+ dictWord{8, 11, 162},
+ dictWord{
+ 139,
+ 11,
+ 655,
+ },
+ dictWord{8, 0, 449},
+ dictWord{4, 10, 937},
+ dictWord{5, 10, 801},
+ dictWord{136, 11, 449},
+ dictWord{139, 11, 958},
+ dictWord{6, 0, 181},
+ dictWord{
+ 7,
+ 0,
+ 537,
+ },
+ dictWord{8, 0, 64},
+ dictWord{9, 0, 127},
+ dictWord{10, 0, 496},
+ dictWord{12, 0, 510},
+ dictWord{141, 0, 384},
+ dictWord{138, 11, 253},
+ dictWord{4, 0, 244},
+ dictWord{135, 0, 233},
+ dictWord{133, 11, 237},
+ dictWord{132, 10, 365},
+ dictWord{6, 0, 1650},
+ dictWord{10, 0, 702},
+ dictWord{139, 0, 245},
+ dictWord{
+ 5,
+ 10,
+ 7,
+ },
+ dictWord{139, 10, 774},
+ dictWord{13, 0, 463},
+ dictWord{20, 0, 49},
+ dictWord{13, 11, 463},
+ dictWord{148, 11, 49},
+ dictWord{4, 10, 734},
+ dictWord{
+ 5,
+ 10,
+ 662,
+ },
+ dictWord{134, 10, 430},
+ dictWord{4, 10, 746},
+ dictWord{135, 10, 1090},
+ dictWord{5, 10, 360},
+ dictWord{136, 10, 237},
+ dictWord{137, 0, 338},
+ dictWord{143, 11, 10},
+ dictWord{7, 11, 571},
+ dictWord{138, 11, 366},
+ dictWord{134, 0, 1279},
+ dictWord{9, 11, 513},
+ dictWord{10, 11, 22},
+ dictWord{10, 11, 39},
+ dictWord{12, 11, 122},
+ dictWord{140, 11, 187},
+ dictWord{133, 0, 896},
+ dictWord{146, 0, 178},
+ dictWord{134, 0, 695},
+ dictWord{137, 0, 808},
+ dictWord{
+ 134,
+ 11,
+ 587,
+ },
+ dictWord{7, 11, 107},
+ dictWord{7, 11, 838},
+ dictWord{8, 11, 550},
+ dictWord{138, 11, 401},
+ dictWord{7, 0, 1117},
+ dictWord{136, 0, 539},
+ dictWord{
+ 4,
+ 10,
+ 277,
+ },
+ dictWord{5, 10, 608},
+ dictWord{6, 10, 493},
+ dictWord{7, 10, 457},
+ dictWord{140, 10, 384},
+ dictWord{133, 11, 768},
+ dictWord{12, 0, 257},
+ dictWord{
+ 7,
+ 10,
+ 27,
+ },
+ dictWord{135, 10, 316},
+ dictWord{140, 0, 1003},
+ dictWord{4, 0, 207},
+ dictWord{5, 0, 586},
+ dictWord{5, 0, 676},
+ dictWord{6, 0, 448},
+ dictWord{
+ 8,
+ 0,
+ 244,
+ },
+ dictWord{11, 0, 1},
+ dictWord{13, 0, 3},
+ dictWord{16, 0, 54},
+ dictWord{17, 0, 4},
+ dictWord{18, 0, 13},
+ dictWord{133, 10, 552},
+ dictWord{4, 10, 401},
+ dictWord{
+ 137,
+ 10,
+ 264,
+ },
+ dictWord{5, 0, 516},
+ dictWord{7, 0, 1883},
+ dictWord{135, 11, 1883},
+ dictWord{12, 0, 960},
+ dictWord{132, 11, 894},
+ dictWord{5, 0, 4},
+ dictWord{
+ 5,
+ 0,
+ 810,
+ },
+ dictWord{6, 0, 13},
+ dictWord{6, 0, 538},
+ dictWord{6, 0, 1690},
+ dictWord{6, 0, 1726},
+ dictWord{7, 0, 499},
+ dictWord{7, 0, 1819},
+ dictWord{8, 0, 148},
+ dictWord{
+ 8,
+ 0,
+ 696,
+ },
+ dictWord{8, 0, 791},
+ dictWord{12, 0, 125},
+ dictWord{143, 0, 9},
+ dictWord{135, 0, 1268},
+ dictWord{11, 0, 30},
+ dictWord{14, 0, 315},
+ dictWord{
+ 9,
+ 10,
+ 543,
+ },
+ dictWord{10, 10, 524},
+ dictWord{12, 10, 524},
+ dictWord{16, 10, 18},
+ dictWord{20, 10, 26},
+ dictWord{148, 10, 65},
+ dictWord{6, 0, 748},
+ dictWord{
+ 4,
+ 10,
+ 205,
+ },
+ dictWord{5, 10, 623},
+ dictWord{7, 10, 104},
+ dictWord{136, 10, 519},
+ dictWord{11, 0, 542},
+ dictWord{139, 0, 852},
+ dictWord{140, 0, 6},
+ dictWord{
+ 132,
+ 0,
+ 848,
+ },
+ dictWord{7, 0, 1385},
+ dictWord{11, 0, 582},
+ dictWord{11, 0, 650},
+ dictWord{11, 0, 901},
+ dictWord{11, 0, 949},
+ dictWord{12, 0, 232},
+ dictWord{12, 0, 236},
+ dictWord{13, 0, 413},
+ dictWord{13, 0, 501},
+ dictWord{18, 0, 116},
+ dictWord{7, 10, 579},
+ dictWord{9, 10, 41},
+ dictWord{9, 10, 244},
+ dictWord{9, 10, 669},
+ dictWord{10, 10, 5},
+ dictWord{11, 10, 861},
+ dictWord{11, 10, 951},
+ dictWord{139, 10, 980},
+ dictWord{4, 0, 945},
+ dictWord{6, 0, 1811},
+ dictWord{6, 0, 1845},
+ dictWord{
+ 6,
+ 0,
+ 1853,
+ },
+ dictWord{6, 0, 1858},
+ dictWord{8, 0, 862},
+ dictWord{12, 0, 782},
+ dictWord{12, 0, 788},
+ dictWord{18, 0, 160},
+ dictWord{148, 0, 117},
+ dictWord{
+ 132,
+ 10,
+ 717,
+ },
+ dictWord{4, 0, 925},
+ dictWord{5, 0, 803},
+ dictWord{8, 0, 698},
+ dictWord{138, 0, 828},
+ dictWord{134, 0, 1416},
+ dictWord{132, 0, 610},
+ dictWord{
+ 139,
+ 0,
+ 992,
+ },
+ dictWord{6, 0, 878},
+ dictWord{134, 0, 1477},
+ dictWord{135, 0, 1847},
+ dictWord{138, 11, 531},
+ dictWord{137, 11, 539},
+ dictWord{134, 11, 272},
+ dictWord{133, 0, 383},
+ dictWord{134, 0, 1404},
+ dictWord{132, 10, 489},
+ dictWord{4, 11, 9},
+ dictWord{5, 11, 128},
+ dictWord{7, 11, 368},
+ dictWord{
+ 11,
+ 11,
+ 480,
+ },
+ dictWord{148, 11, 3},
+ dictWord{136, 0, 986},
+ dictWord{9, 0, 660},
+ dictWord{138, 0, 347},
+ dictWord{135, 10, 892},
+ dictWord{136, 11, 682},
+ dictWord{
+ 7,
+ 0,
+ 572,
+ },
+ dictWord{9, 0, 592},
+ dictWord{11, 0, 680},
+ dictWord{12, 0, 356},
+ dictWord{140, 0, 550},
+ dictWord{7, 0, 1411},
+ dictWord{138, 11, 527},
+ dictWord{
+ 4,
+ 11,
+ 2,
+ },
+ dictWord{7, 11, 545},
+ dictWord{135, 11, 894},
+ dictWord{137, 10, 473},
+ dictWord{11, 0, 64},
+ dictWord{7, 11, 481},
+ dictWord{7, 10, 819},
+ dictWord{9, 10, 26},
+ dictWord{9, 10, 392},
+ dictWord{9, 11, 792},
+ dictWord{10, 10, 152},
+ dictWord{10, 10, 226},
+ dictWord{12, 10, 276},
+ dictWord{12, 10, 426},
+ dictWord{
+ 12,
+ 10,
+ 589,
+ },
+ dictWord{13, 10, 460},
+ dictWord{15, 10, 97},
+ dictWord{19, 10, 48},
+ dictWord{148, 10, 104},
+ dictWord{135, 10, 51},
+ dictWord{136, 11, 445},
+ dictWord{136, 11, 646},
+ dictWord{135, 0, 606},
+ dictWord{132, 10, 674},
+ dictWord{6, 0, 1829},
+ dictWord{134, 0, 1830},
+ dictWord{132, 10, 770},
+ dictWord{
+ 5,
+ 10,
+ 79,
+ },
+ dictWord{7, 10, 1027},
+ dictWord{7, 10, 1477},
+ dictWord{139, 10, 52},
+ dictWord{5, 11, 530},
+ dictWord{142, 11, 113},
+ dictWord{134, 10, 1666},
+ dictWord{
+ 7,
+ 0,
+ 748,
+ },
+ dictWord{139, 0, 700},
+ dictWord{134, 10, 195},
+ dictWord{133, 10, 789},
+ dictWord{9, 0, 87},
+ dictWord{10, 0, 365},
+ dictWord{4, 10, 251},
+ dictWord{
+ 4,
+ 10,
+ 688,
+ },
+ dictWord{7, 10, 513},
+ dictWord{135, 10, 1284},
+ dictWord{136, 11, 111},
+ dictWord{133, 0, 127},
+ dictWord{6, 0, 198},
+ dictWord{140, 0, 83},
+ dictWord{133, 11, 556},
+ dictWord{133, 10, 889},
+ dictWord{4, 10, 160},
+ dictWord{5, 10, 330},
+ dictWord{7, 10, 1434},
+ dictWord{136, 10, 174},
+ dictWord{5, 0, 276},
+ dictWord{6, 0, 55},
+ dictWord{7, 0, 1369},
+ dictWord{138, 0, 864},
+ dictWord{8, 11, 16},
+ dictWord{140, 11, 568},
+ dictWord{6, 0, 1752},
+ dictWord{136, 0, 726},
+ dictWord{135, 0, 1066},
+ dictWord{133, 0, 764},
+ dictWord{6, 11, 186},
+ dictWord{137, 11, 426},
+ dictWord{11, 0, 683},
+ dictWord{139, 11, 683},
+ dictWord{
+ 6,
+ 0,
+ 309,
+ },
+ dictWord{7, 0, 331},
+ dictWord{138, 0, 550},
+ dictWord{133, 10, 374},
+ dictWord{6, 0, 1212},
+ dictWord{6, 0, 1852},
+ dictWord{7, 0, 1062},
+ dictWord{
+ 8,
+ 0,
+ 874,
+ },
+ dictWord{8, 0, 882},
+ dictWord{138, 0, 936},
+ dictWord{132, 11, 585},
+ dictWord{134, 0, 1364},
+ dictWord{7, 0, 986},
+ dictWord{133, 10, 731},
+ dictWord{
+ 6,
+ 0,
+ 723,
+ },
+ dictWord{6, 0, 1408},
+ dictWord{138, 0, 381},
+ dictWord{135, 0, 1573},
+ dictWord{134, 0, 1025},
+ dictWord{4, 10, 626},
+ dictWord{5, 10, 642},
+ dictWord{
+ 6,
+ 10,
+ 425,
+ },
+ dictWord{10, 10, 202},
+ dictWord{139, 10, 141},
+ dictWord{4, 11, 93},
+ dictWord{5, 11, 252},
+ dictWord{6, 11, 229},
+ dictWord{7, 11, 291},
+ dictWord{
+ 9,
+ 11,
+ 550,
+ },
+ dictWord{139, 11, 644},
+ dictWord{137, 11, 749},
+ dictWord{137, 11, 162},
+ dictWord{132, 11, 381},
+ dictWord{135, 0, 1559},
+ dictWord{
+ 6,
+ 0,
+ 194,
+ },
+ dictWord{7, 0, 133},
+ dictWord{10, 0, 493},
+ dictWord{10, 0, 570},
+ dictWord{139, 0, 664},
+ dictWord{5, 0, 24},
+ dictWord{5, 0, 569},
+ dictWord{6, 0, 3},
+ dictWord{
+ 6,
+ 0,
+ 119,
+ },
+ dictWord{6, 0, 143},
+ dictWord{6, 0, 440},
+ dictWord{7, 0, 295},
+ dictWord{7, 0, 599},
+ dictWord{7, 0, 1686},
+ dictWord{7, 0, 1854},
+ dictWord{8, 0, 424},
+ dictWord{
+ 9,
+ 0,
+ 43,
+ },
+ dictWord{9, 0, 584},
+ dictWord{9, 0, 760},
+ dictWord{10, 0, 148},
+ dictWord{10, 0, 328},
+ dictWord{11, 0, 159},
+ dictWord{11, 0, 253},
+ dictWord{11, 0, 506},
+ dictWord{12, 0, 487},
+ dictWord{140, 0, 531},
+ dictWord{6, 0, 661},
+ dictWord{134, 0, 1517},
+ dictWord{136, 10, 835},
+ dictWord{151, 10, 17},
+ dictWord{5, 0, 14},
+ dictWord{5, 0, 892},
+ dictWord{6, 0, 283},
+ dictWord{7, 0, 234},
+ dictWord{136, 0, 537},
+ dictWord{139, 0, 541},
+ dictWord{4, 0, 126},
+ dictWord{8, 0, 635},
+ dictWord{
+ 147,
+ 0,
+ 34,
+ },
+ dictWord{4, 0, 316},
+ dictWord{4, 0, 495},
+ dictWord{135, 0, 1561},
+ dictWord{4, 11, 187},
+ dictWord{5, 11, 184},
+ dictWord{5, 11, 690},
+ dictWord{
+ 7,
+ 11,
+ 1869,
+ },
+ dictWord{138, 11, 756},
+ dictWord{139, 11, 783},
+ dictWord{4, 0, 998},
+ dictWord{137, 0, 861},
+ dictWord{136, 0, 1009},
+ dictWord{139, 11, 292},
+ dictWord{5, 11, 21},
+ dictWord{6, 11, 77},
+ dictWord{6, 11, 157},
+ dictWord{7, 11, 974},
+ dictWord{7, 11, 1301},
+ dictWord{7, 11, 1339},
+ dictWord{7, 11, 1490},
+ dictWord{
+ 7,
+ 11,
+ 1873,
+ },
+ dictWord{137, 11, 628},
+ dictWord{7, 11, 1283},
+ dictWord{9, 11, 227},
+ dictWord{9, 11, 499},
+ dictWord{10, 11, 341},
+ dictWord{11, 11, 325},
+ dictWord{11, 11, 408},
+ dictWord{14, 11, 180},
+ dictWord{15, 11, 144},
+ dictWord{18, 11, 47},
+ dictWord{147, 11, 49},
+ dictWord{4, 0, 64},
+ dictWord{5, 0, 352},
+ dictWord{5, 0, 720},
+ dictWord{6, 0, 368},
+ dictWord{139, 0, 359},
+ dictWord{5, 10, 384},
+ dictWord{8, 10, 455},
+ dictWord{140, 10, 48},
+ dictWord{5, 10, 264},
+ dictWord{
+ 134,
+ 10,
+ 184,
+ },
+ dictWord{7, 0, 1577},
+ dictWord{10, 0, 304},
+ dictWord{10, 0, 549},
+ dictWord{12, 0, 365},
+ dictWord{13, 0, 220},
+ dictWord{13, 0, 240},
+ dictWord{
+ 142,
+ 0,
+ 33,
+ },
+ dictWord{134, 0, 1107},
+ dictWord{134, 0, 929},
+ dictWord{135, 0, 1142},
+ dictWord{6, 0, 175},
+ dictWord{137, 0, 289},
+ dictWord{5, 0, 432},
+ dictWord{
+ 133,
+ 0,
+ 913,
+ },
+ dictWord{6, 0, 279},
+ dictWord{7, 0, 219},
+ dictWord{5, 10, 633},
+ dictWord{135, 10, 1323},
+ dictWord{7, 0, 785},
+ dictWord{7, 10, 359},
+ dictWord{
+ 8,
+ 10,
+ 243,
+ },
+ dictWord{140, 10, 175},
+ dictWord{139, 0, 595},
+ dictWord{132, 10, 105},
+ dictWord{8, 11, 398},
+ dictWord{9, 11, 681},
+ dictWord{139, 11, 632},
+ dictWord{140, 0, 80},
+ dictWord{5, 0, 931},
+ dictWord{134, 0, 1698},
+ dictWord{142, 11, 241},
+ dictWord{134, 11, 20},
+ dictWord{134, 0, 1323},
+ dictWord{11, 0, 526},
+ dictWord{11, 0, 939},
+ dictWord{141, 0, 290},
+ dictWord{5, 0, 774},
+ dictWord{6, 0, 780},
+ dictWord{6, 0, 1637},
+ dictWord{6, 0, 1686},
+ dictWord{6, 0, 1751},
+ dictWord{
+ 8,
+ 0,
+ 559,
+ },
+ dictWord{141, 0, 109},
+ dictWord{141, 0, 127},
+ dictWord{7, 0, 1167},
+ dictWord{11, 0, 934},
+ dictWord{13, 0, 391},
+ dictWord{17, 0, 76},
+ dictWord{
+ 135,
+ 11,
+ 709,
+ },
+ dictWord{135, 0, 963},
+ dictWord{6, 0, 260},
+ dictWord{135, 0, 1484},
+ dictWord{134, 0, 573},
+ dictWord{4, 10, 758},
+ dictWord{139, 11, 941},
+ dictWord{135, 10, 1649},
+ dictWord{145, 11, 36},
+ dictWord{4, 0, 292},
+ dictWord{137, 0, 580},
+ dictWord{4, 0, 736},
+ dictWord{5, 0, 871},
+ dictWord{6, 0, 1689},
+ dictWord{135, 0, 1944},
+ dictWord{7, 11, 945},
+ dictWord{11, 11, 713},
+ dictWord{139, 11, 744},
+ dictWord{134, 0, 1164},
+ dictWord{135, 11, 937},
+ dictWord{
+ 6,
+ 0,
+ 1922,
+ },
+ dictWord{9, 0, 982},
+ dictWord{15, 0, 173},
+ dictWord{15, 0, 178},
+ dictWord{15, 0, 200},
+ dictWord{18, 0, 189},
+ dictWord{18, 0, 207},
+ dictWord{21, 0, 47},
+ dictWord{135, 11, 1652},
+ dictWord{7, 0, 1695},
+ dictWord{139, 10, 128},
+ dictWord{6, 0, 63},
+ dictWord{135, 0, 920},
+ dictWord{133, 0, 793},
+ dictWord{
+ 143,
+ 11,
+ 134,
+ },
+ dictWord{133, 10, 918},
+ dictWord{5, 0, 67},
+ dictWord{6, 0, 62},
+ dictWord{6, 0, 374},
+ dictWord{135, 0, 1391},
+ dictWord{9, 0, 790},
+ dictWord{12, 0, 47},
+ dictWord{4, 11, 579},
+ dictWord{5, 11, 226},
+ dictWord{5, 11, 323},
+ dictWord{135, 11, 960},
+ dictWord{10, 11, 784},
+ dictWord{141, 11, 191},
+ dictWord{4, 0, 391},
+ dictWord{135, 0, 1169},
+ dictWord{137, 0, 443},
+ dictWord{13, 11, 232},
+ dictWord{146, 11, 35},
+ dictWord{132, 10, 340},
+ dictWord{132, 0, 271},
+ dictWord{
+ 137,
+ 11,
+ 313,
+ },
+ dictWord{5, 11, 973},
+ dictWord{137, 11, 659},
+ dictWord{134, 0, 1140},
+ dictWord{6, 11, 135},
+ dictWord{135, 11, 1176},
+ dictWord{4, 0, 253},
+ dictWord{5, 0, 544},
+ dictWord{7, 0, 300},
+ dictWord{137, 0, 340},
+ dictWord{7, 0, 897},
+ dictWord{5, 10, 985},
+ dictWord{7, 10, 509},
+ dictWord{145, 10, 96},
+ dictWord{
+ 138,
+ 11,
+ 735,
+ },
+ dictWord{135, 10, 1919},
+ dictWord{138, 0, 890},
+ dictWord{5, 0, 818},
+ dictWord{134, 0, 1122},
+ dictWord{5, 0, 53},
+ dictWord{5, 0, 541},
+ dictWord{
+ 6,
+ 0,
+ 94,
+ },
+ dictWord{6, 0, 499},
+ dictWord{7, 0, 230},
+ dictWord{139, 0, 321},
+ dictWord{4, 0, 920},
+ dictWord{5, 0, 25},
+ dictWord{5, 0, 790},
+ dictWord{6, 0, 457},
+ dictWord{
+ 7,
+ 0,
+ 853,
+ },
+ dictWord{8, 0, 788},
+ dictWord{142, 11, 31},
+ dictWord{132, 10, 247},
+ dictWord{135, 11, 314},
+ dictWord{132, 0, 468},
+ dictWord{7, 0, 243},
+ dictWord{
+ 6,
+ 10,
+ 337,
+ },
+ dictWord{7, 10, 494},
+ dictWord{8, 10, 27},
+ dictWord{8, 10, 599},
+ dictWord{138, 10, 153},
+ dictWord{4, 10, 184},
+ dictWord{5, 10, 390},
+ dictWord{
+ 7,
+ 10,
+ 618,
+ },
+ dictWord{7, 10, 1456},
+ dictWord{139, 10, 710},
+ dictWord{134, 0, 870},
+ dictWord{134, 0, 1238},
+ dictWord{134, 0, 1765},
+ dictWord{10, 0, 853},
+ dictWord{10, 0, 943},
+ dictWord{14, 0, 437},
+ dictWord{14, 0, 439},
+ dictWord{14, 0, 443},
+ dictWord{14, 0, 446},
+ dictWord{14, 0, 452},
+ dictWord{14, 0, 469},
+ dictWord{
+ 14,
+ 0,
+ 471,
+ },
+ dictWord{14, 0, 473},
+ dictWord{16, 0, 93},
+ dictWord{16, 0, 102},
+ dictWord{16, 0, 110},
+ dictWord{148, 0, 121},
+ dictWord{4, 0, 605},
+ dictWord{
+ 7,
+ 0,
+ 518,
+ },
+ dictWord{7, 0, 1282},
+ dictWord{7, 0, 1918},
+ dictWord{10, 0, 180},
+ dictWord{139, 0, 218},
+ dictWord{133, 0, 822},
+ dictWord{4, 0, 634},
+ dictWord{
+ 11,
+ 0,
+ 916,
+ },
+ dictWord{142, 0, 419},
+ dictWord{6, 11, 281},
+ dictWord{7, 11, 6},
+ dictWord{8, 11, 282},
+ dictWord{8, 11, 480},
+ dictWord{8, 11, 499},
+ dictWord{9, 11, 198},
+ dictWord{10, 11, 143},
+ dictWord{10, 11, 169},
+ dictWord{10, 11, 211},
+ dictWord{10, 11, 417},
+ dictWord{10, 11, 574},
+ dictWord{11, 11, 147},
+ dictWord{
+ 11,
+ 11,
+ 395,
+ },
+ dictWord{12, 11, 75},
+ dictWord{12, 11, 407},
+ dictWord{12, 11, 608},
+ dictWord{13, 11, 500},
+ dictWord{142, 11, 251},
+ dictWord{134, 0, 898},
+ dictWord{
+ 6,
+ 0,
+ 36,
+ },
+ dictWord{7, 0, 658},
+ dictWord{8, 0, 454},
+ dictWord{150, 11, 48},
+ dictWord{133, 11, 674},
+ dictWord{135, 11, 1776},
+ dictWord{4, 11, 419},
+ dictWord{
+ 10,
+ 10,
+ 227,
+ },
+ dictWord{11, 10, 497},
+ dictWord{11, 10, 709},
+ dictWord{140, 10, 415},
+ dictWord{6, 10, 360},
+ dictWord{7, 10, 1664},
+ dictWord{136, 10, 478},
+ dictWord{137, 0, 806},
+ dictWord{12, 11, 508},
+ dictWord{14, 11, 102},
+ dictWord{14, 11, 226},
+ dictWord{144, 11, 57},
+ dictWord{135, 11, 1123},
+ dictWord{
+ 4,
+ 11,
+ 138,
+ },
+ dictWord{7, 11, 1012},
+ dictWord{7, 11, 1280},
+ dictWord{137, 11, 76},
+ dictWord{5, 11, 29},
+ dictWord{140, 11, 638},
+ dictWord{136, 10, 699},
+ dictWord{134, 0, 1326},
+ dictWord{132, 0, 104},
+ dictWord{135, 11, 735},
+ dictWord{132, 10, 739},
+ dictWord{134, 0, 1331},
+ dictWord{7, 0, 260},
+ dictWord{
+ 135,
+ 11,
+ 260,
+ },
+ dictWord{135, 11, 1063},
+ dictWord{7, 0, 45},
+ dictWord{9, 0, 542},
+ dictWord{9, 0, 566},
+ dictWord{10, 0, 728},
+ dictWord{137, 10, 869},
+ dictWord{
+ 4,
+ 10,
+ 67,
+ },
+ dictWord{5, 10, 422},
+ dictWord{7, 10, 1037},
+ dictWord{7, 10, 1289},
+ dictWord{7, 10, 1555},
+ dictWord{9, 10, 741},
+ dictWord{145, 10, 108},
+ dictWord{
+ 139,
+ 0,
+ 263,
+ },
+ dictWord{134, 0, 1516},
+ dictWord{14, 0, 146},
+ dictWord{15, 0, 42},
+ dictWord{16, 0, 23},
+ dictWord{17, 0, 86},
+ dictWord{146, 0, 17},
+ dictWord{
+ 138,
+ 0,
+ 468,
+ },
+ dictWord{136, 0, 1005},
+ dictWord{4, 11, 17},
+ dictWord{5, 11, 23},
+ dictWord{7, 11, 995},
+ dictWord{11, 11, 383},
+ dictWord{11, 11, 437},
+ dictWord{
+ 12,
+ 11,
+ 460,
+ },
+ dictWord{140, 11, 532},
+ dictWord{7, 0, 87},
+ dictWord{142, 0, 288},
+ dictWord{138, 10, 96},
+ dictWord{135, 11, 626},
+ dictWord{144, 10, 26},
+ dictWord{
+ 7,
+ 0,
+ 988,
+ },
+ dictWord{7, 0, 1939},
+ dictWord{9, 0, 64},
+ dictWord{9, 0, 502},
+ dictWord{12, 0, 22},
+ dictWord{12, 0, 34},
+ dictWord{13, 0, 12},
+ dictWord{13, 0, 234},
+ dictWord{147, 0, 77},
+ dictWord{13, 0, 133},
+ dictWord{8, 10, 203},
+ dictWord{11, 10, 823},
+ dictWord{11, 10, 846},
+ dictWord{12, 10, 482},
+ dictWord{13, 10, 277},
+ dictWord{13, 10, 302},
+ dictWord{13, 10, 464},
+ dictWord{14, 10, 205},
+ dictWord{142, 10, 221},
+ dictWord{4, 10, 449},
+ dictWord{133, 10, 718},
+ dictWord{
+ 135,
+ 0,
+ 141,
+ },
+ dictWord{6, 0, 1842},
+ dictWord{136, 0, 872},
+ dictWord{8, 11, 70},
+ dictWord{12, 11, 171},
+ dictWord{141, 11, 272},
+ dictWord{4, 10, 355},
+ dictWord{
+ 6,
+ 10,
+ 311,
+ },
+ dictWord{9, 10, 256},
+ dictWord{138, 10, 404},
+ dictWord{132, 0, 619},
+ dictWord{137, 0, 261},
+ dictWord{10, 11, 233},
+ dictWord{10, 10, 758},
+ dictWord{139, 11, 76},
+ dictWord{5, 0, 246},
+ dictWord{8, 0, 189},
+ dictWord{9, 0, 355},
+ dictWord{9, 0, 512},
+ dictWord{10, 0, 124},
+ dictWord{10, 0, 453},
+ dictWord{
+ 11,
+ 0,
+ 143,
+ },
+ dictWord{11, 0, 416},
+ dictWord{11, 0, 859},
+ dictWord{141, 0, 341},
+ dictWord{134, 11, 442},
+ dictWord{133, 10, 827},
+ dictWord{5, 10, 64},
+ dictWord{
+ 140,
+ 10,
+ 581,
+ },
+ dictWord{4, 10, 442},
+ dictWord{7, 10, 1047},
+ dictWord{7, 10, 1352},
+ dictWord{135, 10, 1643},
+ dictWord{134, 11, 1709},
+ dictWord{5, 0, 678},
+ dictWord{6, 0, 305},
+ dictWord{7, 0, 775},
+ dictWord{7, 0, 1065},
+ dictWord{133, 10, 977},
+ dictWord{11, 11, 69},
+ dictWord{12, 11, 105},
+ dictWord{12, 11, 117},
+ dictWord{13, 11, 213},
+ dictWord{14, 11, 13},
+ dictWord{14, 11, 62},
+ dictWord{14, 11, 177},
+ dictWord{14, 11, 421},
+ dictWord{15, 11, 19},
+ dictWord{146, 11, 141},
+ dictWord{137, 11, 309},
+ dictWord{5, 0, 35},
+ dictWord{7, 0, 862},
+ dictWord{7, 0, 1886},
+ dictWord{138, 0, 179},
+ dictWord{136, 0, 285},
+ dictWord{132, 0, 517},
+ dictWord{7, 11, 976},
+ dictWord{9, 11, 146},
+ dictWord{10, 11, 206},
+ dictWord{10, 11, 596},
+ dictWord{13, 11, 218},
+ dictWord{142, 11, 153},
+ dictWord{
+ 132,
+ 10,
+ 254,
+ },
+ dictWord{6, 0, 214},
+ dictWord{12, 0, 540},
+ dictWord{4, 10, 275},
+ dictWord{7, 10, 1219},
+ dictWord{140, 10, 376},
+ dictWord{8, 0, 667},
+ dictWord{
+ 11,
+ 0,
+ 403,
+ },
+ dictWord{146, 0, 83},
+ dictWord{12, 0, 74},
+ dictWord{10, 11, 648},
+ dictWord{11, 11, 671},
+ dictWord{143, 11, 46},
+ dictWord{135, 0, 125},
+ dictWord{
+ 134,
+ 10,
+ 1753,
+ },
+ dictWord{133, 0, 761},
+ dictWord{6, 0, 912},
+ dictWord{4, 11, 518},
+ dictWord{6, 10, 369},
+ dictWord{6, 10, 502},
+ dictWord{7, 10, 1036},
+ dictWord{
+ 7,
+ 11,
+ 1136,
+ },
+ dictWord{8, 10, 348},
+ dictWord{9, 10, 452},
+ dictWord{10, 10, 26},
+ dictWord{11, 10, 224},
+ dictWord{11, 10, 387},
+ dictWord{11, 10, 772},
+ dictWord{12, 10, 95},
+ dictWord{12, 10, 629},
+ dictWord{13, 10, 195},
+ dictWord{13, 10, 207},
+ dictWord{13, 10, 241},
+ dictWord{14, 10, 260},
+ dictWord{14, 10, 270},
+ dictWord{143, 10, 140},
+ dictWord{10, 0, 131},
+ dictWord{140, 0, 72},
+ dictWord{132, 10, 269},
+ dictWord{5, 10, 480},
+ dictWord{7, 10, 532},
+ dictWord{
+ 7,
+ 10,
+ 1197,
+ },
+ dictWord{7, 10, 1358},
+ dictWord{8, 10, 291},
+ dictWord{11, 10, 349},
+ dictWord{142, 10, 396},
+ dictWord{8, 11, 689},
+ dictWord{137, 11, 863},
+ dictWord{
+ 8,
+ 0,
+ 333,
+ },
+ dictWord{138, 0, 182},
+ dictWord{4, 11, 18},
+ dictWord{7, 11, 145},
+ dictWord{7, 11, 444},
+ dictWord{7, 11, 1278},
+ dictWord{8, 11, 49},
+ dictWord{
+ 8,
+ 11,
+ 400,
+ },
+ dictWord{9, 11, 71},
+ dictWord{9, 11, 250},
+ dictWord{10, 11, 459},
+ dictWord{12, 11, 160},
+ dictWord{144, 11, 24},
+ dictWord{14, 11, 35},
+ dictWord{
+ 142,
+ 11,
+ 191,
+ },
+ dictWord{135, 11, 1864},
+ dictWord{135, 0, 1338},
+ dictWord{148, 10, 15},
+ dictWord{14, 0, 94},
+ dictWord{15, 0, 65},
+ dictWord{16, 0, 4},
+ dictWord{
+ 16,
+ 0,
+ 77,
+ },
+ dictWord{16, 0, 80},
+ dictWord{145, 0, 5},
+ dictWord{12, 11, 82},
+ dictWord{143, 11, 36},
+ dictWord{133, 11, 1010},
+ dictWord{133, 0, 449},
+ dictWord{
+ 133,
+ 0,
+ 646,
+ },
+ dictWord{7, 0, 86},
+ dictWord{8, 0, 103},
+ dictWord{135, 10, 657},
+ dictWord{7, 0, 2028},
+ dictWord{138, 0, 641},
+ dictWord{136, 10, 533},
+ dictWord{
+ 134,
+ 0,
+ 1,
+ },
+ dictWord{139, 11, 970},
+ dictWord{5, 11, 87},
+ dictWord{7, 11, 313},
+ dictWord{7, 11, 1103},
+ dictWord{10, 11, 112},
+ dictWord{10, 11, 582},
+ dictWord{
+ 11,
+ 11,
+ 389,
+ },
+ dictWord{11, 11, 813},
+ dictWord{12, 11, 385},
+ dictWord{13, 11, 286},
+ dictWord{14, 11, 124},
+ dictWord{146, 11, 108},
+ dictWord{6, 0, 869},
+ dictWord{
+ 132,
+ 11,
+ 267,
+ },
+ dictWord{6, 0, 277},
+ dictWord{7, 0, 1274},
+ dictWord{7, 0, 1386},
+ dictWord{146, 0, 87},
+ dictWord{6, 0, 187},
+ dictWord{7, 0, 39},
+ dictWord{7, 0, 1203},
+ dictWord{8, 0, 380},
+ dictWord{14, 0, 117},
+ dictWord{149, 0, 28},
+ dictWord{4, 10, 211},
+ dictWord{4, 10, 332},
+ dictWord{5, 10, 335},
+ dictWord{6, 10, 238},
+ dictWord{
+ 7,
+ 10,
+ 269,
+ },
+ dictWord{7, 10, 811},
+ dictWord{7, 10, 1797},
+ dictWord{8, 10, 836},
+ dictWord{9, 10, 507},
+ dictWord{141, 10, 242},
+ dictWord{4, 0, 785},
+ dictWord{
+ 5,
+ 0,
+ 368,
+ },
+ dictWord{6, 0, 297},
+ dictWord{7, 0, 793},
+ dictWord{139, 0, 938},
+ dictWord{7, 0, 464},
+ dictWord{8, 0, 558},
+ dictWord{11, 0, 105},
+ dictWord{12, 0, 231},
+ dictWord{14, 0, 386},
+ dictWord{15, 0, 102},
+ dictWord{148, 0, 75},
+ dictWord{133, 10, 1009},
+ dictWord{8, 0, 877},
+ dictWord{140, 0, 731},
+ dictWord{
+ 139,
+ 11,
+ 289,
+ },
+ dictWord{10, 11, 249},
+ dictWord{139, 11, 209},
+ dictWord{132, 11, 561},
+ dictWord{134, 0, 1608},
+ dictWord{132, 11, 760},
+ dictWord{134, 0, 1429},
+ dictWord{9, 11, 154},
+ dictWord{140, 11, 485},
+ dictWord{5, 10, 228},
+ dictWord{6, 10, 203},
+ dictWord{7, 10, 156},
+ dictWord{8, 10, 347},
+ dictWord{
+ 137,
+ 10,
+ 265,
+ },
+ dictWord{7, 0, 1010},
+ dictWord{11, 0, 733},
+ dictWord{11, 0, 759},
+ dictWord{13, 0, 34},
+ dictWord{14, 0, 427},
+ dictWord{146, 0, 45},
+ dictWord{7, 10, 1131},
+ dictWord{135, 10, 1468},
+ dictWord{136, 11, 255},
+ dictWord{7, 0, 1656},
+ dictWord{9, 0, 369},
+ dictWord{10, 0, 338},
+ dictWord{10, 0, 490},
+ dictWord{
+ 11,
+ 0,
+ 154,
+ },
+ dictWord{11, 0, 545},
+ dictWord{11, 0, 775},
+ dictWord{13, 0, 77},
+ dictWord{141, 0, 274},
+ dictWord{133, 11, 621},
+ dictWord{134, 0, 1038},
+ dictWord{
+ 4,
+ 11,
+ 368,
+ },
+ dictWord{135, 11, 641},
+ dictWord{6, 0, 2010},
+ dictWord{8, 0, 979},
+ dictWord{8, 0, 985},
+ dictWord{10, 0, 951},
+ dictWord{138, 0, 1011},
+ dictWord{
+ 134,
+ 0,
+ 1005,
+ },
+ dictWord{19, 0, 121},
+ dictWord{5, 10, 291},
+ dictWord{5, 10, 318},
+ dictWord{7, 10, 765},
+ dictWord{9, 10, 389},
+ dictWord{140, 10, 548},
+ dictWord{
+ 5,
+ 0,
+ 20,
+ },
+ dictWord{6, 0, 298},
+ dictWord{7, 0, 659},
+ dictWord{137, 0, 219},
+ dictWord{7, 0, 1440},
+ dictWord{11, 0, 854},
+ dictWord{11, 0, 872},
+ dictWord{11, 0, 921},
+ dictWord{12, 0, 551},
+ dictWord{13, 0, 472},
+ dictWord{142, 0, 367},
+ dictWord{5, 0, 490},
+ dictWord{6, 0, 615},
+ dictWord{6, 0, 620},
+ dictWord{135, 0, 683},
+ dictWord{
+ 6,
+ 0,
+ 1070,
+ },
+ dictWord{134, 0, 1597},
+ dictWord{139, 0, 522},
+ dictWord{132, 0, 439},
+ dictWord{136, 0, 669},
+ dictWord{6, 0, 766},
+ dictWord{6, 0, 1143},
+ dictWord{
+ 6,
+ 0,
+ 1245,
+ },
+ dictWord{10, 10, 525},
+ dictWord{139, 10, 82},
+ dictWord{9, 11, 92},
+ dictWord{147, 11, 91},
+ dictWord{6, 0, 668},
+ dictWord{134, 0, 1218},
+ dictWord{
+ 6,
+ 11,
+ 525,
+ },
+ dictWord{9, 11, 876},
+ dictWord{140, 11, 284},
+ dictWord{132, 0, 233},
+ dictWord{136, 0, 547},
+ dictWord{132, 10, 422},
+ dictWord{5, 10, 355},
+ dictWord{145, 10, 0},
+ dictWord{6, 11, 300},
+ dictWord{135, 11, 1515},
+ dictWord{4, 0, 482},
+ dictWord{137, 10, 905},
+ dictWord{4, 0, 886},
+ dictWord{7, 0, 346},
+ dictWord{133, 11, 594},
+ dictWord{133, 10, 865},
+ dictWord{5, 10, 914},
+ dictWord{134, 10, 1625},
+ dictWord{135, 0, 334},
+ dictWord{5, 0, 795},
+ dictWord{
+ 6,
+ 0,
+ 1741,
+ },
+ dictWord{133, 10, 234},
+ dictWord{135, 10, 1383},
+ dictWord{6, 11, 1641},
+ dictWord{136, 11, 820},
+ dictWord{135, 0, 371},
+ dictWord{7, 11, 1313},
+ dictWord{138, 11, 660},
+ dictWord{135, 10, 1312},
+ dictWord{135, 0, 622},
+ dictWord{7, 0, 625},
+ dictWord{135, 0, 1750},
+ dictWord{135, 0, 339},
+ dictWord{
+ 4,
+ 0,
+ 203,
+ },
+ dictWord{135, 0, 1936},
+ dictWord{15, 0, 29},
+ dictWord{16, 0, 38},
+ dictWord{15, 11, 29},
+ dictWord{144, 11, 38},
+ dictWord{5, 0, 338},
+ dictWord{
+ 135,
+ 0,
+ 1256,
+ },
+ dictWord{135, 10, 1493},
+ dictWord{10, 0, 130},
+ dictWord{6, 10, 421},
+ dictWord{7, 10, 61},
+ dictWord{7, 10, 1540},
+ dictWord{138, 10, 501},
+ dictWord{
+ 6,
+ 11,
+ 389,
+ },
+ dictWord{7, 11, 149},
+ dictWord{9, 11, 142},
+ dictWord{138, 11, 94},
+ dictWord{137, 10, 341},
+ dictWord{11, 0, 678},
+ dictWord{12, 0, 307},
+ dictWord{142, 10, 98},
+ dictWord{6, 11, 8},
+ dictWord{7, 11, 1881},
+ dictWord{136, 11, 91},
+ dictWord{135, 0, 2044},
+ dictWord{6, 0, 770},
+ dictWord{6, 0, 802},
+ dictWord{
+ 6,
+ 0,
+ 812,
+ },
+ dictWord{7, 0, 311},
+ dictWord{9, 0, 308},
+ dictWord{12, 0, 255},
+ dictWord{6, 10, 102},
+ dictWord{7, 10, 72},
+ dictWord{15, 10, 142},
+ dictWord{
+ 147,
+ 10,
+ 67,
+ },
+ dictWord{151, 10, 30},
+ dictWord{135, 10, 823},
+ dictWord{135, 0, 1266},
+ dictWord{135, 11, 1746},
+ dictWord{135, 10, 1870},
+ dictWord{4, 0, 400},
+ dictWord{5, 0, 267},
+ dictWord{135, 0, 232},
+ dictWord{7, 11, 24},
+ dictWord{11, 11, 542},
+ dictWord{139, 11, 852},
+ dictWord{135, 11, 1739},
+ dictWord{4, 11, 503},
+ dictWord{135, 11, 1661},
+ dictWord{5, 11, 130},
+ dictWord{7, 11, 1314},
+ dictWord{9, 11, 610},
+ dictWord{10, 11, 718},
+ dictWord{11, 11, 601},
+ dictWord{
+ 11,
+ 11,
+ 819,
+ },
+ dictWord{11, 11, 946},
+ dictWord{140, 11, 536},
+ dictWord{10, 11, 149},
+ dictWord{11, 11, 280},
+ dictWord{142, 11, 336},
+ dictWord{7, 0, 739},
+ dictWord{11, 0, 690},
+ dictWord{7, 11, 1946},
+ dictWord{8, 10, 48},
+ dictWord{8, 10, 88},
+ dictWord{8, 10, 582},
+ dictWord{8, 10, 681},
+ dictWord{9, 10, 373},
+ dictWord{
+ 9,
+ 10,
+ 864,
+ },
+ dictWord{11, 10, 157},
+ dictWord{11, 10, 843},
+ dictWord{148, 10, 27},
+ dictWord{134, 0, 990},
+ dictWord{4, 10, 88},
+ dictWord{5, 10, 137},
+ dictWord{
+ 5,
+ 10,
+ 174,
+ },
+ dictWord{5, 10, 777},
+ dictWord{6, 10, 1664},
+ dictWord{6, 10, 1725},
+ dictWord{7, 10, 77},
+ dictWord{7, 10, 426},
+ dictWord{7, 10, 1317},
+ dictWord{
+ 7,
+ 10,
+ 1355,
+ },
+ dictWord{8, 10, 126},
+ dictWord{8, 10, 563},
+ dictWord{9, 10, 523},
+ dictWord{9, 10, 750},
+ dictWord{10, 10, 310},
+ dictWord{10, 10, 836},
+ dictWord{
+ 11,
+ 10,
+ 42,
+ },
+ dictWord{11, 10, 318},
+ dictWord{11, 10, 731},
+ dictWord{12, 10, 68},
+ dictWord{12, 10, 92},
+ dictWord{12, 10, 507},
+ dictWord{12, 10, 692},
+ dictWord{
+ 13,
+ 10,
+ 81,
+ },
+ dictWord{13, 10, 238},
+ dictWord{13, 10, 374},
+ dictWord{14, 10, 436},
+ dictWord{18, 10, 138},
+ dictWord{19, 10, 78},
+ dictWord{19, 10, 111},
+ dictWord{20, 10, 55},
+ dictWord{20, 10, 77},
+ dictWord{148, 10, 92},
+ dictWord{141, 10, 418},
+ dictWord{7, 0, 1831},
+ dictWord{132, 10, 938},
+ dictWord{6, 0, 776},
+ dictWord{134, 0, 915},
+ dictWord{138, 10, 351},
+ dictWord{5, 11, 348},
+ dictWord{6, 11, 522},
+ dictWord{6, 10, 1668},
+ dictWord{7, 10, 1499},
+ dictWord{8, 10, 117},
+ dictWord{9, 10, 314},
+ dictWord{138, 10, 174},
+ dictWord{135, 10, 707},
+ dictWord{132, 0, 613},
+ dictWord{133, 10, 403},
+ dictWord{132, 11, 392},
+ dictWord{
+ 5,
+ 11,
+ 433,
+ },
+ dictWord{9, 11, 633},
+ dictWord{139, 11, 629},
+ dictWord{133, 0, 763},
+ dictWord{132, 0, 878},
+ dictWord{132, 0, 977},
+ dictWord{132, 0, 100},
+ dictWord{6, 0, 463},
+ dictWord{4, 10, 44},
+ dictWord{5, 10, 311},
+ dictWord{7, 10, 639},
+ dictWord{7, 10, 762},
+ dictWord{7, 10, 1827},
+ dictWord{9, 10, 8},
+ dictWord{
+ 9,
+ 10,
+ 462,
+ },
+ dictWord{148, 10, 83},
+ dictWord{134, 11, 234},
+ dictWord{4, 10, 346},
+ dictWord{7, 10, 115},
+ dictWord{9, 10, 180},
+ dictWord{9, 10, 456},
+ dictWord{
+ 138,
+ 10,
+ 363,
+ },
+ dictWord{5, 0, 362},
+ dictWord{5, 0, 443},
+ dictWord{6, 0, 318},
+ dictWord{7, 0, 1019},
+ dictWord{139, 0, 623},
+ dictWord{5, 0, 463},
+ dictWord{8, 0, 296},
+ dictWord{7, 11, 140},
+ dictWord{7, 11, 1950},
+ dictWord{8, 11, 680},
+ dictWord{11, 11, 817},
+ dictWord{147, 11, 88},
+ dictWord{7, 11, 1222},
+ dictWord{
+ 138,
+ 11,
+ 386,
+ },
+ dictWord{142, 0, 137},
+ dictWord{132, 0, 454},
+ dictWord{7, 0, 1914},
+ dictWord{6, 11, 5},
+ dictWord{7, 10, 1051},
+ dictWord{9, 10, 545},
+ dictWord{
+ 11,
+ 11,
+ 249,
+ },
+ dictWord{12, 11, 313},
+ dictWord{16, 11, 66},
+ dictWord{145, 11, 26},
+ dictWord{135, 0, 1527},
+ dictWord{145, 0, 58},
+ dictWord{148, 11, 59},
+ dictWord{
+ 5,
+ 0,
+ 48,
+ },
+ dictWord{5, 0, 404},
+ dictWord{6, 0, 557},
+ dictWord{7, 0, 458},
+ dictWord{8, 0, 597},
+ dictWord{10, 0, 455},
+ dictWord{10, 0, 606},
+ dictWord{11, 0, 49},
+ dictWord{
+ 11,
+ 0,
+ 548,
+ },
+ dictWord{12, 0, 476},
+ dictWord{13, 0, 18},
+ dictWord{141, 0, 450},
+ dictWord{5, 11, 963},
+ dictWord{134, 11, 1773},
+ dictWord{133, 0, 729},
+ dictWord{138, 11, 586},
+ dictWord{5, 0, 442},
+ dictWord{135, 0, 1984},
+ dictWord{134, 0, 449},
+ dictWord{144, 0, 40},
+ dictWord{4, 0, 853},
+ dictWord{7, 11, 180},
+ dictWord{8, 11, 509},
+ dictWord{136, 11, 792},
+ dictWord{6, 10, 185},
+ dictWord{7, 10, 1899},
+ dictWord{9, 10, 875},
+ dictWord{139, 10, 673},
+ dictWord{
+ 134,
+ 11,
+ 524,
+ },
+ dictWord{12, 0, 227},
+ dictWord{4, 10, 327},
+ dictWord{5, 10, 478},
+ dictWord{7, 10, 1332},
+ dictWord{136, 10, 753},
+ dictWord{6, 0, 1491},
+ dictWord{
+ 5,
+ 10,
+ 1020,
+ },
+ dictWord{133, 10, 1022},
+ dictWord{4, 10, 103},
+ dictWord{133, 10, 401},
+ dictWord{132, 11, 931},
+ dictWord{4, 10, 499},
+ dictWord{135, 10, 1421},
+ dictWord{5, 0, 55},
+ dictWord{7, 0, 376},
+ dictWord{140, 0, 161},
+ dictWord{133, 0, 450},
+ dictWord{6, 0, 1174},
+ dictWord{134, 0, 1562},
+ dictWord{10, 0, 62},
+ dictWord{13, 0, 400},
+ dictWord{135, 11, 1837},
+ dictWord{140, 0, 207},
+ dictWord{135, 0, 869},
+ dictWord{4, 11, 773},
+ dictWord{5, 11, 618},
+ dictWord{
+ 137,
+ 11,
+ 756,
+ },
+ dictWord{132, 10, 96},
+ dictWord{4, 0, 213},
+ dictWord{7, 0, 223},
+ dictWord{8, 0, 80},
+ dictWord{135, 10, 968},
+ dictWord{4, 11, 90},
+ dictWord{5, 11, 337},
+ dictWord{5, 11, 545},
+ dictWord{7, 11, 754},
+ dictWord{9, 11, 186},
+ dictWord{10, 11, 72},
+ dictWord{10, 11, 782},
+ dictWord{11, 11, 513},
+ dictWord{11, 11, 577},
+ dictWord{11, 11, 610},
+ dictWord{11, 11, 889},
+ dictWord{11, 11, 961},
+ dictWord{12, 11, 354},
+ dictWord{12, 11, 362},
+ dictWord{12, 11, 461},
+ dictWord{
+ 12,
+ 11,
+ 595,
+ },
+ dictWord{13, 11, 79},
+ dictWord{143, 11, 121},
+ dictWord{7, 0, 381},
+ dictWord{7, 0, 806},
+ dictWord{7, 0, 820},
+ dictWord{8, 0, 354},
+ dictWord{8, 0, 437},
+ dictWord{8, 0, 787},
+ dictWord{9, 0, 657},
+ dictWord{10, 0, 58},
+ dictWord{10, 0, 339},
+ dictWord{10, 0, 749},
+ dictWord{11, 0, 914},
+ dictWord{12, 0, 162},
+ dictWord{
+ 13,
+ 0,
+ 75,
+ },
+ dictWord{14, 0, 106},
+ dictWord{14, 0, 198},
+ dictWord{14, 0, 320},
+ dictWord{14, 0, 413},
+ dictWord{146, 0, 43},
+ dictWord{136, 0, 747},
+ dictWord{
+ 136,
+ 0,
+ 954,
+ },
+ dictWord{134, 0, 1073},
+ dictWord{135, 0, 556},
+ dictWord{7, 11, 151},
+ dictWord{9, 11, 329},
+ dictWord{139, 11, 254},
+ dictWord{5, 0, 692},
+ dictWord{
+ 134,
+ 0,
+ 1395,
+ },
+ dictWord{6, 10, 563},
+ dictWord{137, 10, 224},
+ dictWord{134, 0, 191},
+ dictWord{132, 0, 804},
+ dictWord{9, 11, 187},
+ dictWord{10, 11, 36},
+ dictWord{17, 11, 44},
+ dictWord{146, 11, 64},
+ dictWord{7, 11, 165},
+ dictWord{7, 11, 919},
+ dictWord{136, 11, 517},
+ dictWord{4, 11, 506},
+ dictWord{5, 11, 295},
+ dictWord{7, 11, 1680},
+ dictWord{15, 11, 14},
+ dictWord{144, 11, 5},
+ dictWord{4, 0, 706},
+ dictWord{6, 0, 162},
+ dictWord{7, 0, 1960},
+ dictWord{136, 0, 831},
+ dictWord{
+ 135,
+ 11,
+ 1376,
+ },
+ dictWord{7, 11, 987},
+ dictWord{9, 11, 688},
+ dictWord{10, 11, 522},
+ dictWord{11, 11, 788},
+ dictWord{140, 11, 566},
+ dictWord{150, 0, 35},
+ dictWord{138, 0, 426},
+ dictWord{135, 0, 1235},
+ dictWord{135, 11, 1741},
+ dictWord{7, 11, 389},
+ dictWord{7, 11, 700},
+ dictWord{7, 11, 940},
+ dictWord{
+ 8,
+ 11,
+ 514,
+ },
+ dictWord{9, 11, 116},
+ dictWord{9, 11, 535},
+ dictWord{10, 11, 118},
+ dictWord{11, 11, 107},
+ dictWord{11, 11, 148},
+ dictWord{11, 11, 922},
+ dictWord{
+ 12,
+ 11,
+ 254,
+ },
+ dictWord{12, 11, 421},
+ dictWord{142, 11, 238},
+ dictWord{134, 0, 1234},
+ dictWord{132, 11, 743},
+ dictWord{4, 10, 910},
+ dictWord{5, 10, 832},
+ dictWord{135, 11, 1335},
+ dictWord{141, 0, 96},
+ dictWord{135, 11, 185},
+ dictWord{146, 0, 149},
+ dictWord{4, 0, 204},
+ dictWord{137, 0, 902},
+ dictWord{
+ 4,
+ 11,
+ 784,
+ },
+ dictWord{133, 11, 745},
+ dictWord{136, 0, 833},
+ dictWord{136, 0, 949},
+ dictWord{7, 0, 366},
+ dictWord{9, 0, 287},
+ dictWord{12, 0, 199},
+ dictWord{
+ 12,
+ 0,
+ 556,
+ },
+ dictWord{12, 0, 577},
+ dictWord{5, 11, 81},
+ dictWord{7, 11, 146},
+ dictWord{7, 11, 1342},
+ dictWord{7, 11, 1446},
+ dictWord{8, 11, 53},
+ dictWord{8, 11, 561},
+ dictWord{8, 11, 694},
+ dictWord{8, 11, 754},
+ dictWord{9, 11, 97},
+ dictWord{9, 11, 115},
+ dictWord{9, 11, 894},
+ dictWord{10, 11, 462},
+ dictWord{10, 11, 813},
+ dictWord{11, 11, 230},
+ dictWord{11, 11, 657},
+ dictWord{11, 11, 699},
+ dictWord{11, 11, 748},
+ dictWord{12, 11, 119},
+ dictWord{12, 11, 200},
+ dictWord{
+ 12,
+ 11,
+ 283,
+ },
+ dictWord{14, 11, 273},
+ dictWord{145, 11, 15},
+ dictWord{5, 11, 408},
+ dictWord{137, 11, 747},
+ dictWord{9, 11, 498},
+ dictWord{140, 11, 181},
+ dictWord{
+ 6,
+ 0,
+ 2020,
+ },
+ dictWord{136, 0, 992},
+ dictWord{5, 0, 356},
+ dictWord{135, 0, 224},
+ dictWord{134, 0, 784},
+ dictWord{7, 0, 630},
+ dictWord{9, 0, 567},
+ dictWord{
+ 11,
+ 0,
+ 150,
+ },
+ dictWord{11, 0, 444},
+ dictWord{13, 0, 119},
+ dictWord{8, 10, 528},
+ dictWord{137, 10, 348},
+ dictWord{134, 0, 539},
+ dictWord{4, 10, 20},
+ dictWord{
+ 133,
+ 10,
+ 616,
+ },
+ dictWord{142, 0, 27},
+ dictWord{7, 11, 30},
+ dictWord{8, 11, 86},
+ dictWord{8, 11, 315},
+ dictWord{8, 11, 700},
+ dictWord{9, 11, 576},
+ dictWord{9, 11, 858},
+ dictWord{11, 11, 310},
+ dictWord{11, 11, 888},
+ dictWord{11, 11, 904},
+ dictWord{12, 11, 361},
+ dictWord{141, 11, 248},
+ dictWord{138, 11, 839},
+ dictWord{
+ 134,
+ 0,
+ 755,
+ },
+ dictWord{134, 0, 1063},
+ dictWord{7, 10, 1091},
+ dictWord{135, 10, 1765},
+ dictWord{134, 11, 428},
+ dictWord{7, 11, 524},
+ dictWord{8, 11, 169},
+ dictWord{8, 11, 234},
+ dictWord{9, 11, 480},
+ dictWord{138, 11, 646},
+ dictWord{139, 0, 814},
+ dictWord{7, 11, 1462},
+ dictWord{139, 11, 659},
+ dictWord{
+ 4,
+ 10,
+ 26,
+ },
+ dictWord{5, 10, 429},
+ dictWord{6, 10, 245},
+ dictWord{7, 10, 704},
+ dictWord{7, 10, 1379},
+ dictWord{135, 10, 1474},
+ dictWord{7, 11, 1205},
+ dictWord{
+ 138,
+ 11,
+ 637,
+ },
+ dictWord{139, 11, 803},
+ dictWord{132, 10, 621},
+ dictWord{136, 0, 987},
+ dictWord{4, 11, 266},
+ dictWord{8, 11, 4},
+ dictWord{9, 11, 39},
+ dictWord{
+ 10,
+ 11,
+ 166,
+ },
+ dictWord{11, 11, 918},
+ dictWord{12, 11, 635},
+ dictWord{20, 11, 10},
+ dictWord{22, 11, 27},
+ dictWord{150, 11, 43},
+ dictWord{4, 0, 235},
+ dictWord{
+ 135,
+ 0,
+ 255,
+ },
+ dictWord{4, 0, 194},
+ dictWord{5, 0, 584},
+ dictWord{6, 0, 384},
+ dictWord{7, 0, 583},
+ dictWord{10, 0, 761},
+ dictWord{11, 0, 760},
+ dictWord{139, 0, 851},
+ dictWord{133, 10, 542},
+ dictWord{134, 0, 1086},
+ dictWord{133, 10, 868},
+ dictWord{8, 0, 1016},
+ dictWord{136, 0, 1018},
+ dictWord{7, 0, 1396},
+ dictWord{
+ 7,
+ 11,
+ 1396,
+ },
+ dictWord{136, 10, 433},
+ dictWord{135, 10, 1495},
+ dictWord{138, 10, 215},
+ dictWord{141, 10, 124},
+ dictWord{7, 11, 157},
+ dictWord{
+ 8,
+ 11,
+ 279,
+ },
+ dictWord{9, 11, 759},
+ dictWord{16, 11, 31},
+ dictWord{16, 11, 39},
+ dictWord{16, 11, 75},
+ dictWord{18, 11, 24},
+ dictWord{20, 11, 42},
+ dictWord{152, 11, 1},
+ dictWord{5, 0, 562},
+ dictWord{134, 11, 604},
+ dictWord{134, 0, 913},
+ dictWord{5, 0, 191},
+ dictWord{137, 0, 271},
+ dictWord{4, 0, 470},
+ dictWord{6, 0, 153},
+ dictWord{7, 0, 1503},
+ dictWord{7, 0, 1923},
+ dictWord{10, 0, 701},
+ dictWord{11, 0, 132},
+ dictWord{11, 0, 227},
+ dictWord{11, 0, 320},
+ dictWord{11, 0, 436},
+ dictWord{
+ 11,
+ 0,
+ 525,
+ },
+ dictWord{11, 0, 855},
+ dictWord{11, 0, 873},
+ dictWord{12, 0, 41},
+ dictWord{12, 0, 286},
+ dictWord{13, 0, 103},
+ dictWord{13, 0, 284},
+ dictWord{
+ 14,
+ 0,
+ 255,
+ },
+ dictWord{14, 0, 262},
+ dictWord{15, 0, 117},
+ dictWord{143, 0, 127},
+ dictWord{7, 0, 475},
+ dictWord{12, 0, 45},
+ dictWord{147, 10, 112},
+ dictWord{
+ 132,
+ 11,
+ 567,
+ },
+ dictWord{137, 11, 859},
+ dictWord{6, 0, 713},
+ dictWord{6, 0, 969},
+ dictWord{6, 0, 1290},
+ dictWord{134, 0, 1551},
+ dictWord{133, 0, 327},
+ dictWord{
+ 6,
+ 0,
+ 552,
+ },
+ dictWord{6, 0, 1292},
+ dictWord{7, 0, 1754},
+ dictWord{137, 0, 604},
+ dictWord{4, 0, 223},
+ dictWord{6, 0, 359},
+ dictWord{11, 0, 3},
+ dictWord{13, 0, 108},
+ dictWord{14, 0, 89},
+ dictWord{16, 0, 22},
+ dictWord{5, 11, 762},
+ dictWord{7, 11, 1880},
+ dictWord{9, 11, 680},
+ dictWord{139, 11, 798},
+ dictWord{5, 0, 80},
+ dictWord{
+ 6,
+ 0,
+ 405,
+ },
+ dictWord{7, 0, 403},
+ dictWord{7, 0, 1502},
+ dictWord{8, 0, 456},
+ dictWord{9, 0, 487},
+ dictWord{9, 0, 853},
+ dictWord{9, 0, 889},
+ dictWord{10, 0, 309},
+ dictWord{
+ 11,
+ 0,
+ 721,
+ },
+ dictWord{11, 0, 994},
+ dictWord{12, 0, 430},
+ dictWord{141, 0, 165},
+ dictWord{133, 11, 298},
+ dictWord{132, 10, 647},
+ dictWord{134, 0, 2016},
+ dictWord{18, 10, 10},
+ dictWord{146, 11, 10},
+ dictWord{4, 0, 453},
+ dictWord{5, 0, 887},
+ dictWord{6, 0, 535},
+ dictWord{8, 0, 6},
+ dictWord{8, 0, 543},
+ dictWord{
+ 136,
+ 0,
+ 826,
+ },
+ dictWord{136, 0, 975},
+ dictWord{10, 0, 961},
+ dictWord{138, 0, 962},
+ dictWord{138, 10, 220},
+ dictWord{6, 0, 1891},
+ dictWord{6, 0, 1893},
+ dictWord{
+ 9,
+ 0,
+ 916,
+ },
+ dictWord{9, 0, 965},
+ dictWord{9, 0, 972},
+ dictWord{12, 0, 801},
+ dictWord{12, 0, 859},
+ dictWord{12, 0, 883},
+ dictWord{15, 0, 226},
+ dictWord{149, 0, 51},
+ dictWord{132, 10, 109},
+ dictWord{135, 11, 267},
+ dictWord{7, 11, 92},
+ dictWord{7, 11, 182},
+ dictWord{8, 11, 453},
+ dictWord{9, 11, 204},
+ dictWord{11, 11, 950},
+ dictWord{12, 11, 94},
+ dictWord{12, 11, 644},
+ dictWord{16, 11, 20},
+ dictWord{16, 11, 70},
+ dictWord{16, 11, 90},
+ dictWord{147, 11, 55},
+ dictWord{
+ 134,
+ 10,
+ 1746,
+ },
+ dictWord{6, 11, 71},
+ dictWord{7, 11, 845},
+ dictWord{7, 11, 1308},
+ dictWord{8, 11, 160},
+ dictWord{137, 11, 318},
+ dictWord{5, 0, 101},
+ dictWord{6, 0, 88},
+ dictWord{7, 0, 263},
+ dictWord{7, 0, 628},
+ dictWord{7, 0, 1677},
+ dictWord{8, 0, 349},
+ dictWord{9, 0, 100},
+ dictWord{10, 0, 677},
+ dictWord{14, 0, 169},
+ dictWord{
+ 14,
+ 0,
+ 302,
+ },
+ dictWord{14, 0, 313},
+ dictWord{15, 0, 48},
+ dictWord{15, 0, 84},
+ dictWord{7, 11, 237},
+ dictWord{8, 11, 664},
+ dictWord{9, 11, 42},
+ dictWord{9, 11, 266},
+ dictWord{9, 11, 380},
+ dictWord{9, 11, 645},
+ dictWord{10, 11, 177},
+ dictWord{138, 11, 276},
+ dictWord{138, 11, 69},
+ dictWord{4, 0, 310},
+ dictWord{7, 0, 708},
+ dictWord{7, 0, 996},
+ dictWord{9, 0, 795},
+ dictWord{10, 0, 390},
+ dictWord{10, 0, 733},
+ dictWord{11, 0, 451},
+ dictWord{12, 0, 249},
+ dictWord{14, 0, 115},
+ dictWord{
+ 14,
+ 0,
+ 286,
+ },
+ dictWord{143, 0, 100},
+ dictWord{5, 0, 587},
+ dictWord{4, 10, 40},
+ dictWord{10, 10, 67},
+ dictWord{11, 10, 117},
+ dictWord{11, 10, 768},
+ dictWord{
+ 139,
+ 10,
+ 935,
+ },
+ dictWord{6, 0, 1942},
+ dictWord{7, 0, 512},
+ dictWord{136, 0, 983},
+ dictWord{7, 10, 992},
+ dictWord{8, 10, 301},
+ dictWord{9, 10, 722},
+ dictWord{12, 10, 63},
+ dictWord{13, 10, 29},
+ dictWord{14, 10, 161},
+ dictWord{143, 10, 18},
+ dictWord{136, 11, 76},
+ dictWord{139, 10, 923},
+ dictWord{134, 0, 645},
+ dictWord{
+ 134,
+ 0,
+ 851,
+ },
+ dictWord{4, 0, 498},
+ dictWord{132, 11, 293},
+ dictWord{7, 0, 217},
+ dictWord{8, 0, 140},
+ dictWord{10, 0, 610},
+ dictWord{14, 11, 352},
+ dictWord{
+ 17,
+ 11,
+ 53,
+ },
+ dictWord{18, 11, 146},
+ dictWord{18, 11, 152},
+ dictWord{19, 11, 11},
+ dictWord{150, 11, 54},
+ dictWord{134, 0, 1448},
+ dictWord{138, 11, 841},
+ dictWord{133, 0, 905},
+ dictWord{4, 11, 605},
+ dictWord{7, 11, 518},
+ dictWord{7, 11, 1282},
+ dictWord{7, 11, 1918},
+ dictWord{10, 11, 180},
+ dictWord{139, 11, 218},
+ dictWord{139, 11, 917},
+ dictWord{135, 10, 825},
+ dictWord{140, 10, 328},
+ dictWord{4, 0, 456},
+ dictWord{7, 0, 105},
+ dictWord{7, 0, 358},
+ dictWord{7, 0, 1637},
+ dictWord{8, 0, 643},
+ dictWord{139, 0, 483},
+ dictWord{134, 0, 792},
+ dictWord{6, 11, 96},
+ dictWord{135, 11, 1426},
+ dictWord{137, 11, 691},
+ dictWord{
+ 4,
+ 11,
+ 651,
+ },
+ dictWord{133, 11, 289},
+ dictWord{7, 11, 688},
+ dictWord{8, 11, 35},
+ dictWord{9, 11, 511},
+ dictWord{10, 11, 767},
+ dictWord{147, 11, 118},
+ dictWord{
+ 150,
+ 0,
+ 56,
+ },
+ dictWord{5, 0, 243},
+ dictWord{5, 0, 535},
+ dictWord{6, 10, 204},
+ dictWord{10, 10, 320},
+ dictWord{10, 10, 583},
+ dictWord{13, 10, 502},
+ dictWord{
+ 14,
+ 10,
+ 72,
+ },
+ dictWord{14, 10, 274},
+ dictWord{14, 10, 312},
+ dictWord{14, 10, 344},
+ dictWord{15, 10, 159},
+ dictWord{16, 10, 62},
+ dictWord{16, 10, 69},
+ dictWord{
+ 17,
+ 10,
+ 30,
+ },
+ dictWord{18, 10, 42},
+ dictWord{18, 10, 53},
+ dictWord{18, 10, 84},
+ dictWord{18, 10, 140},
+ dictWord{19, 10, 68},
+ dictWord{19, 10, 85},
+ dictWord{20, 10, 5},
+ dictWord{20, 10, 45},
+ dictWord{20, 10, 101},
+ dictWord{22, 10, 7},
+ dictWord{150, 10, 20},
+ dictWord{4, 10, 558},
+ dictWord{6, 10, 390},
+ dictWord{7, 10, 162},
+ dictWord{7, 10, 689},
+ dictWord{9, 10, 360},
+ dictWord{138, 10, 653},
+ dictWord{146, 11, 23},
+ dictWord{135, 0, 1748},
+ dictWord{5, 10, 856},
+ dictWord{
+ 6,
+ 10,
+ 1672,
+ },
+ dictWord{6, 10, 1757},
+ dictWord{134, 10, 1781},
+ dictWord{5, 0, 539},
+ dictWord{5, 0, 754},
+ dictWord{6, 0, 876},
+ dictWord{132, 11, 704},
+ dictWord{
+ 135,
+ 11,
+ 1078,
+ },
+ dictWord{5, 10, 92},
+ dictWord{10, 10, 736},
+ dictWord{140, 10, 102},
+ dictWord{17, 0, 91},
+ dictWord{5, 10, 590},
+ dictWord{137, 10, 213},
+ dictWord{134, 0, 1565},
+ dictWord{6, 0, 91},
+ dictWord{135, 0, 435},
+ dictWord{4, 0, 939},
+ dictWord{140, 0, 792},
+ dictWord{134, 0, 1399},
+ dictWord{4, 0, 16},
+ dictWord{
+ 5,
+ 0,
+ 316,
+ },
+ dictWord{5, 0, 842},
+ dictWord{6, 0, 370},
+ dictWord{6, 0, 1778},
+ dictWord{8, 0, 166},
+ dictWord{11, 0, 812},
+ dictWord{12, 0, 206},
+ dictWord{12, 0, 351},
+ dictWord{14, 0, 418},
+ dictWord{16, 0, 15},
+ dictWord{16, 0, 34},
+ dictWord{18, 0, 3},
+ dictWord{19, 0, 3},
+ dictWord{19, 0, 7},
+ dictWord{20, 0, 4},
+ dictWord{21, 0, 21},
+ dictWord{
+ 4,
+ 11,
+ 720,
+ },
+ dictWord{133, 11, 306},
+ dictWord{144, 0, 95},
+ dictWord{133, 11, 431},
+ dictWord{132, 11, 234},
+ dictWord{135, 0, 551},
+ dictWord{4, 0, 999},
+ dictWord{6, 0, 1966},
+ dictWord{134, 0, 2042},
+ dictWord{7, 0, 619},
+ dictWord{10, 0, 547},
+ dictWord{11, 0, 122},
+ dictWord{12, 0, 601},
+ dictWord{15, 0, 7},
+ dictWord{148, 0, 20},
+ dictWord{5, 11, 464},
+ dictWord{6, 11, 236},
+ dictWord{7, 11, 276},
+ dictWord{7, 11, 696},
+ dictWord{7, 11, 914},
+ dictWord{7, 11, 1108},
+ dictWord{
+ 7,
+ 11,
+ 1448,
+ },
+ dictWord{9, 11, 15},
+ dictWord{9, 11, 564},
+ dictWord{10, 11, 14},
+ dictWord{12, 11, 565},
+ dictWord{13, 11, 449},
+ dictWord{14, 11, 53},
+ dictWord{
+ 15,
+ 11,
+ 13,
+ },
+ dictWord{16, 11, 64},
+ dictWord{145, 11, 41},
+ dictWord{6, 0, 884},
+ dictWord{6, 0, 1019},
+ dictWord{134, 0, 1150},
+ dictWord{6, 11, 1767},
+ dictWord{
+ 12,
+ 11,
+ 194,
+ },
+ dictWord{145, 11, 107},
+ dictWord{136, 10, 503},
+ dictWord{133, 11, 840},
+ dictWord{7, 0, 671},
+ dictWord{134, 10, 466},
+ dictWord{132, 0, 888},
+ dictWord{4, 0, 149},
+ dictWord{138, 0, 368},
+ dictWord{4, 0, 154},
+ dictWord{7, 0, 1134},
+ dictWord{136, 0, 105},
+ dictWord{135, 0, 983},
+ dictWord{9, 11, 642},
+ dictWord{11, 11, 236},
+ dictWord{142, 11, 193},
+ dictWord{4, 0, 31},
+ dictWord{6, 0, 429},
+ dictWord{7, 0, 962},
+ dictWord{9, 0, 458},
+ dictWord{139, 0, 691},
+ dictWord{
+ 6,
+ 0,
+ 643,
+ },
+ dictWord{134, 0, 1102},
+ dictWord{132, 0, 312},
+ dictWord{4, 11, 68},
+ dictWord{5, 11, 634},
+ dictWord{6, 11, 386},
+ dictWord{7, 11, 794},
+ dictWord{
+ 8,
+ 11,
+ 273,
+ },
+ dictWord{9, 11, 563},
+ dictWord{10, 11, 105},
+ dictWord{10, 11, 171},
+ dictWord{11, 11, 94},
+ dictWord{139, 11, 354},
+ dictWord{133, 0, 740},
+ dictWord{
+ 135,
+ 0,
+ 1642,
+ },
+ dictWord{4, 11, 95},
+ dictWord{7, 11, 416},
+ dictWord{8, 11, 211},
+ dictWord{139, 11, 830},
+ dictWord{132, 0, 236},
+ dictWord{138, 10, 241},
+ dictWord{7, 11, 731},
+ dictWord{13, 11, 20},
+ dictWord{143, 11, 11},
+ dictWord{5, 0, 836},
+ dictWord{5, 0, 857},
+ dictWord{6, 0, 1680},
+ dictWord{135, 0, 59},
+ dictWord{
+ 10,
+ 0,
+ 68,
+ },
+ dictWord{11, 0, 494},
+ dictWord{152, 11, 6},
+ dictWord{4, 0, 81},
+ dictWord{139, 0, 867},
+ dictWord{135, 0, 795},
+ dictWord{133, 11, 689},
+ dictWord{
+ 4,
+ 0,
+ 1001,
+ },
+ dictWord{5, 0, 282},
+ dictWord{6, 0, 1932},
+ dictWord{6, 0, 1977},
+ dictWord{6, 0, 1987},
+ dictWord{6, 0, 1992},
+ dictWord{8, 0, 650},
+ dictWord{8, 0, 919},
+ dictWord{8, 0, 920},
+ dictWord{8, 0, 923},
+ dictWord{8, 0, 926},
+ dictWord{8, 0, 927},
+ dictWord{8, 0, 931},
+ dictWord{8, 0, 939},
+ dictWord{8, 0, 947},
+ dictWord{8, 0, 956},
+ dictWord{8, 0, 997},
+ dictWord{9, 0, 907},
+ dictWord{10, 0, 950},
+ dictWord{10, 0, 953},
+ dictWord{10, 0, 954},
+ dictWord{10, 0, 956},
+ dictWord{10, 0, 958},
+ dictWord{
+ 10,
+ 0,
+ 959,
+ },
+ dictWord{10, 0, 964},
+ dictWord{10, 0, 970},
+ dictWord{10, 0, 972},
+ dictWord{10, 0, 973},
+ dictWord{10, 0, 975},
+ dictWord{10, 0, 976},
+ dictWord{
+ 10,
+ 0,
+ 980,
+ },
+ dictWord{10, 0, 981},
+ dictWord{10, 0, 984},
+ dictWord{10, 0, 988},
+ dictWord{10, 0, 990},
+ dictWord{10, 0, 995},
+ dictWord{10, 0, 999},
+ dictWord{
+ 10,
+ 0,
+ 1002,
+ },
+ dictWord{10, 0, 1003},
+ dictWord{10, 0, 1005},
+ dictWord{10, 0, 1006},
+ dictWord{10, 0, 1008},
+ dictWord{10, 0, 1009},
+ dictWord{10, 0, 1012},
+ dictWord{10, 0, 1014},
+ dictWord{10, 0, 1015},
+ dictWord{10, 0, 1019},
+ dictWord{10, 0, 1020},
+ dictWord{10, 0, 1022},
+ dictWord{12, 0, 959},
+ dictWord{12, 0, 961},
+ dictWord{12, 0, 962},
+ dictWord{12, 0, 963},
+ dictWord{12, 0, 964},
+ dictWord{12, 0, 965},
+ dictWord{12, 0, 967},
+ dictWord{12, 0, 968},
+ dictWord{12, 0, 969},
+ dictWord{12, 0, 970},
+ dictWord{12, 0, 971},
+ dictWord{12, 0, 972},
+ dictWord{12, 0, 973},
+ dictWord{12, 0, 974},
+ dictWord{12, 0, 975},
+ dictWord{12, 0, 976},
+ dictWord{
+ 12,
+ 0,
+ 977,
+ },
+ dictWord{12, 0, 979},
+ dictWord{12, 0, 981},
+ dictWord{12, 0, 982},
+ dictWord{12, 0, 983},
+ dictWord{12, 0, 984},
+ dictWord{12, 0, 985},
+ dictWord{
+ 12,
+ 0,
+ 986,
+ },
+ dictWord{12, 0, 987},
+ dictWord{12, 0, 989},
+ dictWord{12, 0, 990},
+ dictWord{12, 0, 992},
+ dictWord{12, 0, 993},
+ dictWord{12, 0, 995},
+ dictWord{12, 0, 998},
+ dictWord{12, 0, 999},
+ dictWord{12, 0, 1000},
+ dictWord{12, 0, 1001},
+ dictWord{12, 0, 1002},
+ dictWord{12, 0, 1004},
+ dictWord{12, 0, 1005},
+ dictWord{
+ 12,
+ 0,
+ 1006,
+ },
+ dictWord{12, 0, 1007},
+ dictWord{12, 0, 1008},
+ dictWord{12, 0, 1009},
+ dictWord{12, 0, 1010},
+ dictWord{12, 0, 1011},
+ dictWord{12, 0, 1012},
+ dictWord{12, 0, 1014},
+ dictWord{12, 0, 1015},
+ dictWord{12, 0, 1016},
+ dictWord{12, 0, 1017},
+ dictWord{12, 0, 1018},
+ dictWord{12, 0, 1019},
+ dictWord{
+ 12,
+ 0,
+ 1022,
+ },
+ dictWord{12, 0, 1023},
+ dictWord{14, 0, 475},
+ dictWord{14, 0, 477},
+ dictWord{14, 0, 478},
+ dictWord{14, 0, 479},
+ dictWord{14, 0, 480},
+ dictWord{
+ 14,
+ 0,
+ 482,
+ },
+ dictWord{14, 0, 483},
+ dictWord{14, 0, 484},
+ dictWord{14, 0, 485},
+ dictWord{14, 0, 486},
+ dictWord{14, 0, 487},
+ dictWord{14, 0, 488},
+ dictWord{14, 0, 489},
+ dictWord{14, 0, 490},
+ dictWord{14, 0, 491},
+ dictWord{14, 0, 492},
+ dictWord{14, 0, 493},
+ dictWord{14, 0, 494},
+ dictWord{14, 0, 495},
+ dictWord{14, 0, 496},
+ dictWord{14, 0, 497},
+ dictWord{14, 0, 498},
+ dictWord{14, 0, 499},
+ dictWord{14, 0, 500},
+ dictWord{14, 0, 501},
+ dictWord{14, 0, 502},
+ dictWord{14, 0, 503},
+ dictWord{
+ 14,
+ 0,
+ 504,
+ },
+ dictWord{14, 0, 506},
+ dictWord{14, 0, 507},
+ dictWord{14, 0, 508},
+ dictWord{14, 0, 509},
+ dictWord{14, 0, 510},
+ dictWord{14, 0, 511},
+ dictWord{
+ 16,
+ 0,
+ 113,
+ },
+ dictWord{16, 0, 114},
+ dictWord{16, 0, 115},
+ dictWord{16, 0, 117},
+ dictWord{16, 0, 118},
+ dictWord{16, 0, 119},
+ dictWord{16, 0, 121},
+ dictWord{16, 0, 122},
+ dictWord{16, 0, 123},
+ dictWord{16, 0, 124},
+ dictWord{16, 0, 125},
+ dictWord{16, 0, 126},
+ dictWord{16, 0, 127},
+ dictWord{18, 0, 242},
+ dictWord{18, 0, 243},
+ dictWord{18, 0, 244},
+ dictWord{18, 0, 245},
+ dictWord{18, 0, 248},
+ dictWord{18, 0, 249},
+ dictWord{18, 0, 250},
+ dictWord{18, 0, 251},
+ dictWord{18, 0, 252},
+ dictWord{
+ 18,
+ 0,
+ 253,
+ },
+ dictWord{18, 0, 254},
+ dictWord{18, 0, 255},
+ dictWord{20, 0, 125},
+ dictWord{20, 0, 126},
+ dictWord{148, 0, 127},
+ dictWord{7, 11, 1717},
+ dictWord{
+ 7,
+ 11,
+ 1769,
+ },
+ dictWord{138, 11, 546},
+ dictWord{7, 11, 1127},
+ dictWord{7, 11, 1572},
+ dictWord{10, 11, 297},
+ dictWord{10, 11, 422},
+ dictWord{11, 11, 764},
+ dictWord{11, 11, 810},
+ dictWord{12, 11, 264},
+ dictWord{13, 11, 102},
+ dictWord{13, 11, 300},
+ dictWord{13, 11, 484},
+ dictWord{14, 11, 147},
+ dictWord{
+ 14,
+ 11,
+ 229,
+ },
+ dictWord{17, 11, 71},
+ dictWord{18, 11, 118},
+ dictWord{147, 11, 120},
+ dictWord{6, 0, 1148},
+ dictWord{134, 0, 1586},
+ dictWord{132, 0, 775},
+ dictWord{135, 10, 954},
+ dictWord{133, 11, 864},
+ dictWord{133, 11, 928},
+ dictWord{138, 11, 189},
+ dictWord{135, 10, 1958},
+ dictWord{6, 10, 549},
+ dictWord{
+ 8,
+ 10,
+ 34,
+ },
+ dictWord{8, 10, 283},
+ dictWord{9, 10, 165},
+ dictWord{138, 10, 475},
+ dictWord{5, 10, 652},
+ dictWord{5, 10, 701},
+ dictWord{135, 10, 449},
+ dictWord{135, 11, 695},
+ dictWord{4, 10, 655},
+ dictWord{7, 10, 850},
+ dictWord{17, 10, 75},
+ dictWord{146, 10, 137},
+ dictWord{140, 11, 682},
+ dictWord{
+ 133,
+ 11,
+ 523,
+ },
+ dictWord{8, 0, 970},
+ dictWord{136, 10, 670},
+ dictWord{136, 11, 555},
+ dictWord{7, 11, 76},
+ dictWord{8, 11, 44},
+ dictWord{9, 11, 884},
+ dictWord{
+ 10,
+ 11,
+ 580,
+ },
+ dictWord{11, 11, 399},
+ dictWord{11, 11, 894},
+ dictWord{15, 11, 122},
+ dictWord{18, 11, 144},
+ dictWord{147, 11, 61},
+ dictWord{6, 10, 159},
+ dictWord{
+ 6,
+ 10,
+ 364,
+ },
+ dictWord{7, 10, 516},
+ dictWord{7, 10, 1439},
+ dictWord{137, 10, 518},
+ dictWord{4, 0, 71},
+ dictWord{5, 0, 376},
+ dictWord{7, 0, 119},
+ dictWord{
+ 138,
+ 0,
+ 665,
+ },
+ dictWord{141, 10, 151},
+ dictWord{11, 0, 827},
+ dictWord{14, 0, 34},
+ dictWord{143, 0, 148},
+ dictWord{133, 11, 518},
+ dictWord{4, 0, 479},
+ dictWord{
+ 135,
+ 11,
+ 1787,
+ },
+ dictWord{135, 11, 1852},
+ dictWord{135, 10, 993},
+ dictWord{7, 0, 607},
+ dictWord{136, 0, 99},
+ dictWord{134, 0, 1960},
+ dictWord{132, 0, 793},
+ dictWord{4, 0, 41},
+ dictWord{5, 0, 74},
+ dictWord{7, 0, 1627},
+ dictWord{11, 0, 871},
+ dictWord{140, 0, 619},
+ dictWord{7, 0, 94},
+ dictWord{11, 0, 329},
+ dictWord{
+ 11,
+ 0,
+ 965,
+ },
+ dictWord{12, 0, 241},
+ dictWord{14, 0, 354},
+ dictWord{15, 0, 22},
+ dictWord{148, 0, 63},
+ dictWord{7, 10, 501},
+ dictWord{9, 10, 111},
+ dictWord{10, 10, 141},
+ dictWord{11, 10, 332},
+ dictWord{13, 10, 43},
+ dictWord{13, 10, 429},
+ dictWord{14, 10, 130},
+ dictWord{14, 10, 415},
+ dictWord{145, 10, 102},
+ dictWord{
+ 9,
+ 0,
+ 209,
+ },
+ dictWord{137, 0, 300},
+ dictWord{134, 0, 1497},
+ dictWord{138, 11, 255},
+ dictWord{4, 11, 934},
+ dictWord{5, 11, 138},
+ dictWord{136, 11, 610},
+ dictWord{133, 0, 98},
+ dictWord{6, 0, 1316},
+ dictWord{10, 11, 804},
+ dictWord{138, 11, 832},
+ dictWord{8, 11, 96},
+ dictWord{9, 11, 36},
+ dictWord{10, 11, 607},
+ dictWord{11, 11, 423},
+ dictWord{11, 11, 442},
+ dictWord{12, 11, 309},
+ dictWord{14, 11, 199},
+ dictWord{15, 11, 90},
+ dictWord{145, 11, 110},
+ dictWord{
+ 132,
+ 0,
+ 463,
+ },
+ dictWord{5, 10, 149},
+ dictWord{136, 10, 233},
+ dictWord{133, 10, 935},
+ dictWord{4, 11, 652},
+ dictWord{8, 11, 320},
+ dictWord{9, 11, 13},
+ dictWord{
+ 9,
+ 11,
+ 398,
+ },
+ dictWord{9, 11, 727},
+ dictWord{10, 11, 75},
+ dictWord{10, 11, 184},
+ dictWord{10, 11, 230},
+ dictWord{10, 11, 564},
+ dictWord{10, 11, 569},
+ dictWord{
+ 11,
+ 11,
+ 973,
+ },
+ dictWord{12, 11, 70},
+ dictWord{12, 11, 189},
+ dictWord{13, 11, 57},
+ dictWord{13, 11, 257},
+ dictWord{22, 11, 6},
+ dictWord{150, 11, 16},
+ dictWord{
+ 142,
+ 0,
+ 291,
+ },
+ dictWord{12, 10, 582},
+ dictWord{146, 10, 131},
+ dictWord{136, 10, 801},
+ dictWord{133, 0, 984},
+ dictWord{145, 11, 116},
+ dictWord{4, 11, 692},
+ dictWord{133, 11, 321},
+ dictWord{4, 0, 182},
+ dictWord{6, 0, 205},
+ dictWord{135, 0, 220},
+ dictWord{4, 0, 42},
+ dictWord{9, 0, 205},
+ dictWord{9, 0, 786},
+ dictWord{
+ 138,
+ 0,
+ 659,
+ },
+ dictWord{6, 0, 801},
+ dictWord{11, 11, 130},
+ dictWord{140, 11, 609},
+ dictWord{132, 0, 635},
+ dictWord{5, 11, 345},
+ dictWord{135, 11, 1016},
+ dictWord{139, 0, 533},
+ dictWord{132, 0, 371},
+ dictWord{4, 0, 272},
+ dictWord{135, 0, 836},
+ dictWord{6, 0, 1282},
+ dictWord{135, 11, 1100},
+ dictWord{5, 0, 825},
+ dictWord{134, 0, 1640},
+ dictWord{135, 11, 1325},
+ dictWord{133, 11, 673},
+ dictWord{4, 11, 287},
+ dictWord{133, 11, 1018},
+ dictWord{135, 0, 357},
+ dictWord{
+ 6,
+ 0,
+ 467,
+ },
+ dictWord{137, 0, 879},
+ dictWord{7, 0, 317},
+ dictWord{135, 0, 569},
+ dictWord{6, 0, 924},
+ dictWord{134, 0, 1588},
+ dictWord{5, 11, 34},
+ dictWord{
+ 5,
+ 10,
+ 406,
+ },
+ dictWord{10, 11, 724},
+ dictWord{12, 11, 444},
+ dictWord{13, 11, 354},
+ dictWord{18, 11, 32},
+ dictWord{23, 11, 24},
+ dictWord{23, 11, 31},
+ dictWord{
+ 152,
+ 11,
+ 5,
+ },
+ dictWord{6, 0, 1795},
+ dictWord{6, 0, 1835},
+ dictWord{6, 0, 1836},
+ dictWord{6, 0, 1856},
+ dictWord{8, 0, 844},
+ dictWord{8, 0, 849},
+ dictWord{8, 0, 854},
+ dictWord{8, 0, 870},
+ dictWord{8, 0, 887},
+ dictWord{10, 0, 852},
+ dictWord{138, 0, 942},
+ dictWord{6, 10, 69},
+ dictWord{135, 10, 117},
+ dictWord{137, 0, 307},
+ dictWord{
+ 4,
+ 0,
+ 944,
+ },
+ dictWord{6, 0, 1799},
+ dictWord{6, 0, 1825},
+ dictWord{10, 0, 848},
+ dictWord{10, 0, 875},
+ dictWord{10, 0, 895},
+ dictWord{10, 0, 899},
+ dictWord{
+ 10,
+ 0,
+ 902,
+ },
+ dictWord{140, 0, 773},
+ dictWord{11, 0, 43},
+ dictWord{13, 0, 72},
+ dictWord{141, 0, 142},
+ dictWord{135, 10, 1830},
+ dictWord{134, 11, 382},
+ dictWord{
+ 4,
+ 10,
+ 432,
+ },
+ dictWord{135, 10, 824},
+ dictWord{132, 11, 329},
+ dictWord{7, 0, 1820},
+ dictWord{139, 11, 124},
+ dictWord{133, 10, 826},
+ dictWord{
+ 133,
+ 0,
+ 525,
+ },
+ dictWord{132, 11, 906},
+ dictWord{7, 11, 1940},
+ dictWord{136, 11, 366},
+ dictWord{138, 11, 10},
+ dictWord{4, 11, 123},
+ dictWord{4, 11, 649},
+ dictWord{
+ 5,
+ 11,
+ 605,
+ },
+ dictWord{7, 11, 1509},
+ dictWord{136, 11, 36},
+ dictWord{6, 0, 110},
+ dictWord{135, 0, 1681},
+ dictWord{133, 0, 493},
+ dictWord{133, 11, 767},
+ dictWord{4, 0, 174},
+ dictWord{135, 0, 911},
+ dictWord{138, 11, 786},
+ dictWord{8, 0, 417},
+ dictWord{137, 0, 782},
+ dictWord{133, 10, 1000},
+ dictWord{7, 0, 733},
+ dictWord{137, 0, 583},
+ dictWord{4, 10, 297},
+ dictWord{6, 10, 529},
+ dictWord{7, 10, 152},
+ dictWord{7, 10, 713},
+ dictWord{7, 10, 1845},
+ dictWord{8, 10, 710},
+ dictWord{8, 10, 717},
+ dictWord{12, 10, 639},
+ dictWord{140, 10, 685},
+ dictWord{4, 0, 32},
+ dictWord{5, 0, 215},
+ dictWord{6, 0, 269},
+ dictWord{7, 0, 1782},
+ dictWord{
+ 7,
+ 0,
+ 1892,
+ },
+ dictWord{10, 0, 16},
+ dictWord{11, 0, 822},
+ dictWord{11, 0, 954},
+ dictWord{141, 0, 481},
+ dictWord{4, 11, 273},
+ dictWord{5, 11, 658},
+ dictWord{
+ 133,
+ 11,
+ 995,
+ },
+ dictWord{136, 0, 477},
+ dictWord{134, 11, 72},
+ dictWord{135, 11, 1345},
+ dictWord{5, 0, 308},
+ dictWord{7, 0, 1088},
+ dictWord{4, 10, 520},
+ dictWord{
+ 135,
+ 10,
+ 575,
+ },
+ dictWord{133, 11, 589},
+ dictWord{5, 0, 126},
+ dictWord{8, 0, 297},
+ dictWord{9, 0, 366},
+ dictWord{140, 0, 374},
+ dictWord{7, 0, 1551},
+ dictWord{
+ 139,
+ 0,
+ 361,
+ },
+ dictWord{5, 11, 117},
+ dictWord{6, 11, 514},
+ dictWord{6, 11, 541},
+ dictWord{7, 11, 1164},
+ dictWord{7, 11, 1436},
+ dictWord{8, 11, 220},
+ dictWord{
+ 8,
+ 11,
+ 648,
+ },
+ dictWord{10, 11, 688},
+ dictWord{139, 11, 560},
+ dictWord{133, 11, 686},
+ dictWord{4, 0, 946},
+ dictWord{6, 0, 1807},
+ dictWord{8, 0, 871},
+ dictWord{
+ 10,
+ 0,
+ 854,
+ },
+ dictWord{10, 0, 870},
+ dictWord{10, 0, 888},
+ dictWord{10, 0, 897},
+ dictWord{10, 0, 920},
+ dictWord{12, 0, 722},
+ dictWord{12, 0, 761},
+ dictWord{
+ 12,
+ 0,
+ 763,
+ },
+ dictWord{12, 0, 764},
+ dictWord{14, 0, 454},
+ dictWord{14, 0, 465},
+ dictWord{16, 0, 107},
+ dictWord{18, 0, 167},
+ dictWord{18, 0, 168},
+ dictWord{
+ 146,
+ 0,
+ 172,
+ },
+ dictWord{132, 0, 175},
+ dictWord{135, 0, 1307},
+ dictWord{132, 0, 685},
+ dictWord{135, 11, 1834},
+ dictWord{133, 0, 797},
+ dictWord{6, 0, 745},
+ dictWord{
+ 6,
+ 0,
+ 858,
+ },
+ dictWord{134, 0, 963},
+ dictWord{133, 0, 565},
+ dictWord{5, 10, 397},
+ dictWord{6, 10, 154},
+ dictWord{7, 11, 196},
+ dictWord{7, 10, 676},
+ dictWord{
+ 8,
+ 10,
+ 443,
+ },
+ dictWord{8, 10, 609},
+ dictWord{9, 10, 24},
+ dictWord{9, 10, 325},
+ dictWord{10, 10, 35},
+ dictWord{10, 11, 765},
+ dictWord{11, 11, 347},
+ dictWord{
+ 11,
+ 10,
+ 535,
+ },
+ dictWord{11, 11, 552},
+ dictWord{11, 11, 576},
+ dictWord{11, 10, 672},
+ dictWord{11, 11, 790},
+ dictWord{11, 10, 1018},
+ dictWord{12, 11, 263},
+ dictWord{12, 10, 637},
+ dictWord{13, 11, 246},
+ dictWord{13, 11, 270},
+ dictWord{13, 11, 395},
+ dictWord{14, 11, 74},
+ dictWord{14, 11, 176},
+ dictWord{
+ 14,
+ 11,
+ 190,
+ },
+ dictWord{14, 11, 398},
+ dictWord{14, 11, 412},
+ dictWord{15, 11, 32},
+ dictWord{15, 11, 63},
+ dictWord{16, 10, 30},
+ dictWord{16, 11, 88},
+ dictWord{
+ 147,
+ 11,
+ 105,
+ },
+ dictWord{13, 11, 84},
+ dictWord{141, 11, 122},
+ dictWord{4, 0, 252},
+ dictWord{7, 0, 1068},
+ dictWord{10, 0, 434},
+ dictWord{11, 0, 228},
+ dictWord{
+ 11,
+ 0,
+ 426,
+ },
+ dictWord{13, 0, 231},
+ dictWord{18, 0, 106},
+ dictWord{148, 0, 87},
+ dictWord{137, 0, 826},
+ dictWord{4, 11, 589},
+ dictWord{139, 11, 282},
+ dictWord{
+ 5,
+ 11,
+ 381,
+ },
+ dictWord{135, 11, 1792},
+ dictWord{132, 0, 791},
+ dictWord{5, 0, 231},
+ dictWord{10, 0, 509},
+ dictWord{133, 10, 981},
+ dictWord{7, 0, 601},
+ dictWord{
+ 9,
+ 0,
+ 277,
+ },
+ dictWord{9, 0, 674},
+ dictWord{10, 0, 178},
+ dictWord{10, 0, 418},
+ dictWord{10, 0, 571},
+ dictWord{11, 0, 531},
+ dictWord{12, 0, 113},
+ dictWord{12, 0, 475},
+ dictWord{13, 0, 99},
+ dictWord{142, 0, 428},
+ dictWord{4, 10, 56},
+ dictWord{7, 11, 616},
+ dictWord{7, 10, 1791},
+ dictWord{8, 10, 607},
+ dictWord{8, 10, 651},
+ dictWord{10, 11, 413},
+ dictWord{11, 10, 465},
+ dictWord{11, 10, 835},
+ dictWord{12, 10, 337},
+ dictWord{141, 10, 480},
+ dictWord{7, 0, 1591},
+ dictWord{144, 0, 43},
+ dictWord{9, 10, 158},
+ dictWord{138, 10, 411},
+ dictWord{135, 0, 1683},
+ dictWord{8, 0, 289},
+ dictWord{11, 0, 45},
+ dictWord{12, 0, 278},
+ dictWord{140, 0, 537},
+ dictWord{6, 11, 120},
+ dictWord{7, 11, 1188},
+ dictWord{7, 11, 1710},
+ dictWord{8, 11, 286},
+ dictWord{9, 11, 667},
+ dictWord{11, 11, 592},
+ dictWord{
+ 139,
+ 11,
+ 730,
+ },
+ dictWord{136, 10, 617},
+ dictWord{135, 0, 1120},
+ dictWord{135, 11, 1146},
+ dictWord{139, 10, 563},
+ dictWord{4, 11, 352},
+ dictWord{4, 10, 369},
+ dictWord{135, 11, 687},
+ dictWord{143, 11, 38},
+ dictWord{4, 0, 399},
+ dictWord{5, 0, 119},
+ dictWord{5, 0, 494},
+ dictWord{7, 0, 751},
+ dictWord{9, 0, 556},
+ dictWord{
+ 14,
+ 11,
+ 179,
+ },
+ dictWord{15, 11, 151},
+ dictWord{150, 11, 11},
+ dictWord{4, 11, 192},
+ dictWord{5, 11, 49},
+ dictWord{6, 11, 200},
+ dictWord{6, 11, 293},
+ dictWord{
+ 6,
+ 11,
+ 1696,
+ },
+ dictWord{135, 11, 488},
+ dictWord{4, 0, 398},
+ dictWord{133, 0, 660},
+ dictWord{7, 0, 1030},
+ dictWord{134, 10, 622},
+ dictWord{135, 11, 595},
+ dictWord{141, 0, 168},
+ dictWord{132, 11, 147},
+ dictWord{7, 0, 973},
+ dictWord{10, 10, 624},
+ dictWord{142, 10, 279},
+ dictWord{132, 10, 363},
+ dictWord{
+ 132,
+ 0,
+ 642,
+ },
+ dictWord{133, 11, 934},
+ dictWord{134, 0, 1615},
+ dictWord{7, 11, 505},
+ dictWord{135, 11, 523},
+ dictWord{7, 0, 594},
+ dictWord{7, 0, 851},
+ dictWord{
+ 7,
+ 0,
+ 1858,
+ },
+ dictWord{9, 0, 411},
+ dictWord{9, 0, 574},
+ dictWord{9, 0, 666},
+ dictWord{9, 0, 737},
+ dictWord{10, 0, 346},
+ dictWord{10, 0, 712},
+ dictWord{11, 0, 246},
+ dictWord{11, 0, 432},
+ dictWord{11, 0, 517},
+ dictWord{11, 0, 647},
+ dictWord{11, 0, 679},
+ dictWord{11, 0, 727},
+ dictWord{12, 0, 304},
+ dictWord{12, 0, 305},
+ dictWord{
+ 12,
+ 0,
+ 323,
+ },
+ dictWord{12, 0, 483},
+ dictWord{12, 0, 572},
+ dictWord{12, 0, 593},
+ dictWord{12, 0, 602},
+ dictWord{13, 0, 95},
+ dictWord{13, 0, 101},
+ dictWord{
+ 13,
+ 0,
+ 171,
+ },
+ dictWord{13, 0, 315},
+ dictWord{13, 0, 378},
+ dictWord{13, 0, 425},
+ dictWord{13, 0, 475},
+ dictWord{14, 0, 63},
+ dictWord{14, 0, 380},
+ dictWord{14, 0, 384},
+ dictWord{15, 0, 133},
+ dictWord{18, 0, 112},
+ dictWord{148, 0, 72},
+ dictWord{135, 0, 1093},
+ dictWord{132, 0, 679},
+ dictWord{8, 0, 913},
+ dictWord{10, 0, 903},
+ dictWord{10, 0, 915},
+ dictWord{12, 0, 648},
+ dictWord{12, 0, 649},
+ dictWord{14, 0, 455},
+ dictWord{16, 0, 112},
+ dictWord{138, 11, 438},
+ dictWord{137, 0, 203},
+ dictWord{134, 10, 292},
+ dictWord{134, 0, 1492},
+ dictWord{7, 0, 1374},
+ dictWord{8, 0, 540},
+ dictWord{5, 10, 177},
+ dictWord{6, 10, 616},
+ dictWord{7, 10, 827},
+ dictWord{9, 10, 525},
+ dictWord{138, 10, 656},
+ dictWord{135, 0, 1486},
+ dictWord{9, 0, 714},
+ dictWord{138, 10, 31},
+ dictWord{136, 0, 825},
+ dictWord{
+ 134,
+ 0,
+ 1511,
+ },
+ dictWord{132, 11, 637},
+ dictWord{134, 0, 952},
+ dictWord{4, 10, 161},
+ dictWord{133, 10, 631},
+ dictWord{5, 0, 143},
+ dictWord{5, 0, 769},
+ dictWord{
+ 6,
+ 0,
+ 1760,
+ },
+ dictWord{7, 0, 682},
+ dictWord{7, 0, 1992},
+ dictWord{136, 0, 736},
+ dictWord{132, 0, 700},
+ dictWord{134, 0, 1540},
+ dictWord{132, 11, 777},
+ dictWord{
+ 9,
+ 11,
+ 867,
+ },
+ dictWord{138, 11, 837},
+ dictWord{7, 0, 1557},
+ dictWord{135, 10, 1684},
+ dictWord{133, 0, 860},
+ dictWord{6, 0, 422},
+ dictWord{7, 0, 0},
+ dictWord{
+ 7,
+ 0,
+ 1544,
+ },
+ dictWord{9, 0, 605},
+ dictWord{11, 0, 990},
+ dictWord{12, 0, 235},
+ dictWord{12, 0, 453},
+ dictWord{13, 0, 47},
+ dictWord{13, 0, 266},
+ dictWord{9, 10, 469},
+ dictWord{9, 10, 709},
+ dictWord{12, 10, 512},
+ dictWord{14, 10, 65},
+ dictWord{145, 10, 12},
+ dictWord{11, 0, 807},
+ dictWord{10, 10, 229},
+ dictWord{11, 10, 73},
+ dictWord{139, 10, 376},
+ dictWord{6, 11, 170},
+ dictWord{7, 11, 1080},
+ dictWord{8, 11, 395},
+ dictWord{8, 11, 487},
+ dictWord{11, 11, 125},
+ dictWord{
+ 141,
+ 11,
+ 147,
+ },
+ dictWord{5, 0, 515},
+ dictWord{137, 0, 131},
+ dictWord{7, 0, 1605},
+ dictWord{11, 0, 962},
+ dictWord{146, 0, 139},
+ dictWord{132, 0, 646},
+ dictWord{
+ 4,
+ 0,
+ 396,
+ },
+ dictWord{7, 0, 728},
+ dictWord{9, 0, 117},
+ dictWord{13, 0, 202},
+ dictWord{148, 0, 51},
+ dictWord{6, 0, 121},
+ dictWord{6, 0, 124},
+ dictWord{6, 0, 357},
+ dictWord{
+ 7,
+ 0,
+ 1138,
+ },
+ dictWord{7, 0, 1295},
+ dictWord{8, 0, 162},
+ dictWord{8, 0, 508},
+ dictWord{11, 0, 655},
+ dictWord{4, 11, 535},
+ dictWord{6, 10, 558},
+ dictWord{
+ 7,
+ 10,
+ 651,
+ },
+ dictWord{8, 11, 618},
+ dictWord{9, 10, 0},
+ dictWord{10, 10, 34},
+ dictWord{139, 10, 1008},
+ dictWord{135, 11, 1245},
+ dictWord{138, 0, 357},
+ dictWord{
+ 150,
+ 11,
+ 23,
+ },
+ dictWord{133, 0, 237},
+ dictWord{135, 0, 1784},
+ dictWord{7, 10, 1832},
+ dictWord{138, 10, 374},
+ dictWord{132, 0, 713},
+ dictWord{132, 11, 46},
+ dictWord{6, 0, 1536},
+ dictWord{10, 0, 348},
+ dictWord{5, 11, 811},
+ dictWord{6, 11, 1679},
+ dictWord{6, 11, 1714},
+ dictWord{135, 11, 2032},
+ dictWord{
+ 11,
+ 11,
+ 182,
+ },
+ dictWord{142, 11, 195},
+ dictWord{6, 0, 523},
+ dictWord{7, 0, 738},
+ dictWord{7, 10, 771},
+ dictWord{7, 10, 1731},
+ dictWord{9, 10, 405},
+ dictWord{
+ 138,
+ 10,
+ 421,
+ },
+ dictWord{7, 11, 1458},
+ dictWord{9, 11, 407},
+ dictWord{139, 11, 15},
+ dictWord{6, 11, 34},
+ dictWord{7, 11, 69},
+ dictWord{7, 11, 640},
+ dictWord{
+ 7,
+ 11,
+ 1089,
+ },
+ dictWord{8, 11, 708},
+ dictWord{8, 11, 721},
+ dictWord{9, 11, 363},
+ dictWord{9, 11, 643},
+ dictWord{10, 11, 628},
+ dictWord{148, 11, 98},
+ dictWord{
+ 133,
+ 0,
+ 434,
+ },
+ dictWord{135, 0, 1877},
+ dictWord{7, 0, 571},
+ dictWord{138, 0, 366},
+ dictWord{5, 10, 881},
+ dictWord{133, 10, 885},
+ dictWord{9, 0, 513},
+ dictWord{
+ 10,
+ 0,
+ 25,
+ },
+ dictWord{10, 0, 39},
+ dictWord{12, 0, 122},
+ dictWord{140, 0, 187},
+ dictWord{132, 0, 580},
+ dictWord{5, 10, 142},
+ dictWord{134, 10, 546},
+ dictWord{
+ 132,
+ 11,
+ 462,
+ },
+ dictWord{137, 0, 873},
+ dictWord{5, 10, 466},
+ dictWord{11, 10, 571},
+ dictWord{12, 10, 198},
+ dictWord{13, 10, 283},
+ dictWord{14, 10, 186},
+ dictWord{15, 10, 21},
+ dictWord{143, 10, 103},
+ dictWord{7, 0, 171},
+ dictWord{4, 10, 185},
+ dictWord{5, 10, 257},
+ dictWord{5, 10, 839},
+ dictWord{5, 10, 936},
+ dictWord{
+ 9,
+ 10,
+ 399,
+ },
+ dictWord{10, 10, 258},
+ dictWord{10, 10, 395},
+ dictWord{10, 10, 734},
+ dictWord{11, 10, 1014},
+ dictWord{12, 10, 23},
+ dictWord{13, 10, 350},
+ dictWord{14, 10, 150},
+ dictWord{147, 10, 6},
+ dictWord{134, 0, 625},
+ dictWord{7, 0, 107},
+ dictWord{7, 0, 838},
+ dictWord{8, 0, 550},
+ dictWord{138, 0, 401},
+ dictWord{
+ 5,
+ 11,
+ 73,
+ },
+ dictWord{6, 11, 23},
+ dictWord{134, 11, 338},
+ dictWord{4, 0, 943},
+ dictWord{6, 0, 1850},
+ dictWord{12, 0, 713},
+ dictWord{142, 0, 434},
+ dictWord{
+ 11,
+ 0,
+ 588,
+ },
+ dictWord{11, 0, 864},
+ dictWord{11, 0, 936},
+ dictWord{11, 0, 968},
+ dictWord{12, 0, 73},
+ dictWord{12, 0, 343},
+ dictWord{12, 0, 394},
+ dictWord{13, 0, 275},
+ dictWord{14, 0, 257},
+ dictWord{15, 0, 160},
+ dictWord{7, 10, 404},
+ dictWord{7, 10, 1377},
+ dictWord{7, 10, 1430},
+ dictWord{7, 10, 2017},
+ dictWord{8, 10, 149},
+ dictWord{8, 10, 239},
+ dictWord{8, 10, 512},
+ dictWord{8, 10, 793},
+ dictWord{8, 10, 818},
+ dictWord{9, 10, 474},
+ dictWord{9, 10, 595},
+ dictWord{10, 10, 122},
+ dictWord{10, 10, 565},
+ dictWord{10, 10, 649},
+ dictWord{10, 10, 783},
+ dictWord{11, 10, 239},
+ dictWord{11, 10, 295},
+ dictWord{11, 10, 447},
+ dictWord{
+ 11,
+ 10,
+ 528,
+ },
+ dictWord{11, 10, 639},
+ dictWord{11, 10, 800},
+ dictWord{12, 10, 25},
+ dictWord{12, 10, 157},
+ dictWord{12, 10, 316},
+ dictWord{12, 10, 390},
+ dictWord{
+ 12,
+ 10,
+ 391,
+ },
+ dictWord{12, 10, 395},
+ dictWord{12, 10, 478},
+ dictWord{12, 10, 503},
+ dictWord{12, 10, 592},
+ dictWord{12, 10, 680},
+ dictWord{13, 10, 50},
+ dictWord{13, 10, 53},
+ dictWord{13, 10, 132},
+ dictWord{13, 10, 198},
+ dictWord{13, 10, 322},
+ dictWord{13, 10, 415},
+ dictWord{13, 10, 511},
+ dictWord{14, 10, 71},
+ dictWord{14, 10, 395},
+ dictWord{15, 10, 71},
+ dictWord{15, 10, 136},
+ dictWord{17, 10, 123},
+ dictWord{18, 10, 93},
+ dictWord{147, 10, 58},
+ dictWord{
+ 133,
+ 0,
+ 768,
+ },
+ dictWord{11, 0, 103},
+ dictWord{142, 0, 0},
+ dictWord{136, 10, 712},
+ dictWord{132, 0, 799},
+ dictWord{132, 0, 894},
+ dictWord{7, 11, 725},
+ dictWord{
+ 8,
+ 11,
+ 498,
+ },
+ dictWord{139, 11, 268},
+ dictWord{135, 11, 1798},
+ dictWord{135, 11, 773},
+ dictWord{141, 11, 360},
+ dictWord{4, 10, 377},
+ dictWord{152, 10, 13},
+ dictWord{135, 0, 1673},
+ dictWord{132, 11, 583},
+ dictWord{134, 0, 1052},
+ dictWord{133, 11, 220},
+ dictWord{140, 11, 69},
+ dictWord{132, 11, 544},
+ dictWord{
+ 4,
+ 10,
+ 180,
+ },
+ dictWord{135, 10, 1906},
+ dictWord{134, 0, 272},
+ dictWord{4, 0, 441},
+ dictWord{134, 0, 1421},
+ dictWord{4, 0, 9},
+ dictWord{5, 0, 128},
+ dictWord{
+ 7,
+ 0,
+ 368,
+ },
+ dictWord{11, 0, 480},
+ dictWord{148, 0, 3},
+ dictWord{5, 11, 176},
+ dictWord{6, 11, 437},
+ dictWord{6, 11, 564},
+ dictWord{11, 11, 181},
+ dictWord{
+ 141,
+ 11,
+ 183,
+ },
+ dictWord{132, 10, 491},
+ dictWord{7, 0, 1182},
+ dictWord{141, 11, 67},
+ dictWord{6, 0, 1346},
+ dictWord{4, 10, 171},
+ dictWord{138, 10, 234},
+ dictWord{
+ 4,
+ 10,
+ 586,
+ },
+ dictWord{7, 10, 1186},
+ dictWord{138, 10, 631},
+ dictWord{136, 0, 682},
+ dictWord{134, 0, 1004},
+ dictWord{15, 0, 24},
+ dictWord{143, 11, 24},
+ dictWord{134, 0, 968},
+ dictWord{4, 0, 2},
+ dictWord{6, 0, 742},
+ dictWord{6, 0, 793},
+ dictWord{7, 0, 545},
+ dictWord{7, 0, 894},
+ dictWord{9, 10, 931},
+ dictWord{
+ 10,
+ 10,
+ 334,
+ },
+ dictWord{148, 10, 71},
+ dictWord{136, 11, 600},
+ dictWord{133, 10, 765},
+ dictWord{9, 0, 769},
+ dictWord{140, 0, 185},
+ dictWord{4, 11, 790},
+ dictWord{
+ 5,
+ 11,
+ 273,
+ },
+ dictWord{134, 11, 394},
+ dictWord{7, 0, 474},
+ dictWord{137, 0, 578},
+ dictWord{4, 11, 135},
+ dictWord{6, 11, 127},
+ dictWord{7, 11, 1185},
+ dictWord{
+ 7,
+ 11,
+ 1511,
+ },
+ dictWord{8, 11, 613},
+ dictWord{11, 11, 5},
+ dictWord{12, 11, 133},
+ dictWord{12, 11, 495},
+ dictWord{12, 11, 586},
+ dictWord{14, 11, 385},
+ dictWord{15, 11, 118},
+ dictWord{17, 11, 20},
+ dictWord{146, 11, 98},
+ dictWord{133, 10, 424},
+ dictWord{5, 0, 530},
+ dictWord{142, 0, 113},
+ dictWord{6, 11, 230},
+ dictWord{7, 11, 961},
+ dictWord{7, 11, 1085},
+ dictWord{136, 11, 462},
+ dictWord{7, 11, 1954},
+ dictWord{137, 11, 636},
+ dictWord{136, 10, 714},
+ dictWord{
+ 149,
+ 11,
+ 6,
+ },
+ dictWord{135, 10, 685},
+ dictWord{9, 10, 420},
+ dictWord{10, 10, 269},
+ dictWord{10, 10, 285},
+ dictWord{10, 10, 576},
+ dictWord{11, 10, 397},
+ dictWord{13, 10, 175},
+ dictWord{145, 10, 90},
+ dictWord{132, 10, 429},
+ dictWord{5, 0, 556},
+ dictWord{5, 11, 162},
+ dictWord{136, 11, 68},
+ dictWord{132, 11, 654},
+ dictWord{4, 11, 156},
+ dictWord{7, 11, 998},
+ dictWord{7, 11, 1045},
+ dictWord{7, 11, 1860},
+ dictWord{9, 11, 48},
+ dictWord{9, 11, 692},
+ dictWord{11, 11, 419},
+ dictWord{139, 11, 602},
+ dictWord{6, 0, 1317},
+ dictWord{8, 0, 16},
+ dictWord{9, 0, 825},
+ dictWord{12, 0, 568},
+ dictWord{7, 11, 1276},
+ dictWord{8, 11, 474},
+ dictWord{137, 11, 652},
+ dictWord{18, 0, 97},
+ dictWord{7, 10, 18},
+ dictWord{7, 10, 699},
+ dictWord{7, 10, 1966},
+ dictWord{8, 10, 752},
+ dictWord{9, 10, 273},
+ dictWord{
+ 9,
+ 10,
+ 412,
+ },
+ dictWord{9, 10, 703},
+ dictWord{10, 10, 71},
+ dictWord{10, 10, 427},
+ dictWord{138, 10, 508},
+ dictWord{10, 0, 703},
+ dictWord{7, 11, 1454},
+ dictWord{138, 11, 703},
+ dictWord{4, 10, 53},
+ dictWord{5, 10, 186},
+ dictWord{135, 10, 752},
+ dictWord{134, 0, 892},
+ dictWord{134, 0, 1571},
+ dictWord{8, 10, 575},
+ dictWord{10, 10, 289},
+ dictWord{139, 10, 319},
+ dictWord{6, 0, 186},
+ dictWord{137, 0, 426},
+ dictWord{134, 0, 1101},
+ dictWord{132, 10, 675},
+ dictWord{
+ 132,
+ 0,
+ 585,
+ },
+ dictWord{6, 0, 1870},
+ dictWord{137, 0, 937},
+ dictWord{152, 11, 10},
+ dictWord{9, 11, 197},
+ dictWord{10, 11, 300},
+ dictWord{12, 11, 473},
+ dictWord{
+ 13,
+ 11,
+ 90,
+ },
+ dictWord{141, 11, 405},
+ dictWord{4, 0, 93},
+ dictWord{5, 0, 252},
+ dictWord{6, 0, 229},
+ dictWord{7, 0, 291},
+ dictWord{9, 0, 550},
+ dictWord{139, 0, 644},
+ dictWord{137, 0, 749},
+ dictWord{9, 0, 162},
+ dictWord{6, 10, 209},
+ dictWord{8, 10, 468},
+ dictWord{9, 10, 210},
+ dictWord{11, 10, 36},
+ dictWord{12, 10, 28},
+ dictWord{12, 10, 630},
+ dictWord{13, 10, 21},
+ dictWord{13, 10, 349},
+ dictWord{14, 10, 7},
+ dictWord{145, 10, 13},
+ dictWord{132, 0, 381},
+ dictWord{132, 11, 606},
+ dictWord{4, 10, 342},
+ dictWord{135, 10, 1179},
+ dictWord{7, 11, 1587},
+ dictWord{7, 11, 1707},
+ dictWord{10, 11, 528},
+ dictWord{139, 11, 504},
+ dictWord{
+ 12,
+ 11,
+ 39,
+ },
+ dictWord{13, 11, 265},
+ dictWord{141, 11, 439},
+ dictWord{4, 10, 928},
+ dictWord{133, 10, 910},
+ dictWord{7, 10, 1838},
+ dictWord{7, 11, 1978},
+ dictWord{136, 11, 676},
+ dictWord{6, 0, 762},
+ dictWord{6, 0, 796},
+ dictWord{134, 0, 956},
+ dictWord{4, 10, 318},
+ dictWord{4, 10, 496},
+ dictWord{7, 10, 856},
+ dictWord{139, 10, 654},
+ dictWord{137, 11, 242},
+ dictWord{4, 11, 361},
+ dictWord{133, 11, 315},
+ dictWord{132, 11, 461},
+ dictWord{132, 11, 472},
+ dictWord{
+ 132,
+ 0,
+ 857,
+ },
+ dictWord{5, 0, 21},
+ dictWord{6, 0, 77},
+ dictWord{6, 0, 157},
+ dictWord{7, 0, 974},
+ dictWord{7, 0, 1301},
+ dictWord{7, 0, 1339},
+ dictWord{7, 0, 1490},
+ dictWord{
+ 7,
+ 0,
+ 1873,
+ },
+ dictWord{9, 0, 628},
+ dictWord{7, 10, 915},
+ dictWord{8, 10, 247},
+ dictWord{147, 10, 0},
+ dictWord{4, 10, 202},
+ dictWord{5, 10, 382},
+ dictWord{
+ 6,
+ 10,
+ 454,
+ },
+ dictWord{7, 10, 936},
+ dictWord{7, 10, 1803},
+ dictWord{8, 10, 758},
+ dictWord{9, 10, 375},
+ dictWord{9, 10, 895},
+ dictWord{10, 10, 743},
+ dictWord{
+ 10,
+ 10,
+ 792,
+ },
+ dictWord{11, 10, 978},
+ dictWord{11, 10, 1012},
+ dictWord{142, 10, 109},
+ dictWord{7, 11, 617},
+ dictWord{10, 11, 498},
+ dictWord{11, 11, 501},
+ dictWord{12, 11, 16},
+ dictWord{140, 11, 150},
+ dictWord{7, 10, 1150},
+ dictWord{7, 10, 1425},
+ dictWord{7, 10, 1453},
+ dictWord{10, 11, 747},
+ dictWord{
+ 140,
+ 10,
+ 513,
+ },
+ dictWord{133, 11, 155},
+ dictWord{11, 0, 919},
+ dictWord{141, 0, 409},
+ dictWord{138, 10, 791},
+ dictWord{10, 0, 633},
+ dictWord{139, 11, 729},
+ dictWord{
+ 7,
+ 11,
+ 163,
+ },
+ dictWord{8, 11, 319},
+ dictWord{9, 11, 402},
+ dictWord{10, 11, 24},
+ dictWord{10, 11, 681},
+ dictWord{11, 11, 200},
+ dictWord{11, 11, 567},
+ dictWord{12, 11, 253},
+ dictWord{12, 11, 410},
+ dictWord{142, 11, 219},
+ dictWord{5, 11, 475},
+ dictWord{7, 11, 1780},
+ dictWord{9, 11, 230},
+ dictWord{11, 11, 297},
+ dictWord{11, 11, 558},
+ dictWord{14, 11, 322},
+ dictWord{147, 11, 76},
+ dictWord{7, 0, 332},
+ dictWord{6, 10, 445},
+ dictWord{137, 10, 909},
+ dictWord{
+ 135,
+ 11,
+ 1956,
+ },
+ dictWord{136, 11, 274},
+ dictWord{134, 10, 578},
+ dictWord{135, 0, 1489},
+ dictWord{135, 11, 1848},
+ dictWord{5, 11, 944},
+ dictWord{
+ 134,
+ 11,
+ 1769,
+ },
+ dictWord{132, 11, 144},
+ dictWord{136, 10, 766},
+ dictWord{4, 0, 832},
+ dictWord{135, 10, 541},
+ dictWord{8, 0, 398},
+ dictWord{9, 0, 681},
+ dictWord{
+ 139,
+ 0,
+ 632,
+ },
+ dictWord{136, 0, 645},
+ dictWord{9, 0, 791},
+ dictWord{10, 0, 93},
+ dictWord{16, 0, 13},
+ dictWord{17, 0, 23},
+ dictWord{18, 0, 135},
+ dictWord{19, 0, 12},
+ dictWord{20, 0, 1},
+ dictWord{20, 0, 12},
+ dictWord{148, 0, 14},
+ dictWord{6, 11, 247},
+ dictWord{137, 11, 555},
+ dictWord{134, 0, 20},
+ dictWord{132, 0, 800},
+ dictWord{135, 0, 1841},
+ dictWord{139, 10, 983},
+ dictWord{137, 10, 768},
+ dictWord{132, 10, 584},
+ dictWord{141, 11, 51},
+ dictWord{6, 0, 1993},
+ dictWord{
+ 4,
+ 11,
+ 620,
+ },
+ dictWord{138, 11, 280},
+ dictWord{136, 0, 769},
+ dictWord{11, 0, 290},
+ dictWord{11, 0, 665},
+ dictWord{7, 11, 1810},
+ dictWord{11, 11, 866},
+ dictWord{
+ 12,
+ 11,
+ 103,
+ },
+ dictWord{13, 11, 495},
+ dictWord{17, 11, 67},
+ dictWord{147, 11, 74},
+ dictWord{134, 0, 1426},
+ dictWord{139, 0, 60},
+ dictWord{4, 10, 326},
+ dictWord{135, 10, 1770},
+ dictWord{7, 0, 1874},
+ dictWord{9, 0, 641},
+ dictWord{132, 10, 226},
+ dictWord{6, 0, 644},
+ dictWord{5, 10, 426},
+ dictWord{8, 10, 30},
+ dictWord{
+ 9,
+ 10,
+ 2,
+ },
+ dictWord{11, 10, 549},
+ dictWord{147, 10, 122},
+ dictWord{5, 11, 428},
+ dictWord{138, 11, 442},
+ dictWord{135, 11, 1871},
+ dictWord{
+ 135,
+ 0,
+ 1757,
+ },
+ dictWord{147, 10, 117},
+ dictWord{135, 0, 937},
+ dictWord{135, 0, 1652},
+ dictWord{6, 0, 654},
+ dictWord{134, 0, 1476},
+ dictWord{133, 11, 99},
+ dictWord{135, 0, 527},
+ dictWord{132, 10, 345},
+ dictWord{4, 10, 385},
+ dictWord{4, 11, 397},
+ dictWord{7, 10, 265},
+ dictWord{135, 10, 587},
+ dictWord{4, 0, 579},
+ dictWord{5, 0, 226},
+ dictWord{5, 0, 323},
+ dictWord{135, 0, 960},
+ dictWord{134, 0, 1486},
+ dictWord{8, 11, 502},
+ dictWord{144, 11, 9},
+ dictWord{4, 10, 347},
+ dictWord{
+ 5,
+ 10,
+ 423,
+ },
+ dictWord{5, 10, 996},
+ dictWord{135, 10, 1329},
+ dictWord{7, 11, 727},
+ dictWord{146, 11, 73},
+ dictWord{4, 11, 485},
+ dictWord{7, 11, 353},
+ dictWord{7, 10, 1259},
+ dictWord{7, 11, 1523},
+ dictWord{9, 10, 125},
+ dictWord{139, 10, 65},
+ dictWord{6, 0, 325},
+ dictWord{5, 10, 136},
+ dictWord{6, 11, 366},
+ dictWord{
+ 7,
+ 11,
+ 1384,
+ },
+ dictWord{7, 11, 1601},
+ dictWord{136, 10, 644},
+ dictWord{138, 11, 160},
+ dictWord{6, 0, 1345},
+ dictWord{137, 11, 282},
+ dictWord{18, 0, 91},
+ dictWord{147, 0, 70},
+ dictWord{136, 0, 404},
+ dictWord{4, 11, 157},
+ dictWord{133, 11, 471},
+ dictWord{133, 0, 973},
+ dictWord{6, 0, 135},
+ dictWord{
+ 135,
+ 0,
+ 1176,
+ },
+ dictWord{8, 11, 116},
+ dictWord{11, 11, 551},
+ dictWord{142, 11, 159},
+ dictWord{4, 0, 549},
+ dictWord{4, 10, 433},
+ dictWord{133, 10, 719},
+ dictWord{
+ 136,
+ 0,
+ 976,
+ },
+ dictWord{5, 11, 160},
+ dictWord{7, 11, 363},
+ dictWord{7, 11, 589},
+ dictWord{10, 11, 170},
+ dictWord{141, 11, 55},
+ dictWord{144, 0, 21},
+ dictWord{
+ 144,
+ 0,
+ 51,
+ },
+ dictWord{135, 0, 314},
+ dictWord{135, 10, 1363},
+ dictWord{4, 11, 108},
+ dictWord{7, 11, 405},
+ dictWord{10, 11, 491},
+ dictWord{139, 11, 498},
+ dictWord{146, 0, 4},
+ dictWord{4, 10, 555},
+ dictWord{8, 10, 536},
+ dictWord{10, 10, 288},
+ dictWord{139, 10, 1005},
+ dictWord{135, 11, 1005},
+ dictWord{6, 0, 281},
+ dictWord{7, 0, 6},
+ dictWord{8, 0, 282},
+ dictWord{8, 0, 480},
+ dictWord{8, 0, 499},
+ dictWord{9, 0, 198},
+ dictWord{10, 0, 143},
+ dictWord{10, 0, 169},
+ dictWord{
+ 10,
+ 0,
+ 211,
+ },
+ dictWord{10, 0, 417},
+ dictWord{10, 0, 574},
+ dictWord{11, 0, 147},
+ dictWord{11, 0, 395},
+ dictWord{12, 0, 75},
+ dictWord{12, 0, 407},
+ dictWord{12, 0, 608},
+ dictWord{13, 0, 500},
+ dictWord{142, 0, 251},
+ dictWord{6, 0, 1093},
+ dictWord{6, 0, 1405},
+ dictWord{9, 10, 370},
+ dictWord{138, 10, 90},
+ dictWord{4, 11, 926},
+ dictWord{133, 11, 983},
+ dictWord{135, 0, 1776},
+ dictWord{134, 0, 1528},
+ dictWord{132, 0, 419},
+ dictWord{132, 11, 538},
+ dictWord{6, 11, 294},
+ dictWord{
+ 7,
+ 11,
+ 1267,
+ },
+ dictWord{136, 11, 624},
+ dictWord{135, 11, 1772},
+ dictWord{138, 11, 301},
+ dictWord{4, 10, 257},
+ dictWord{135, 10, 2031},
+ dictWord{4, 0, 138},
+ dictWord{7, 0, 1012},
+ dictWord{7, 0, 1280},
+ dictWord{9, 0, 76},
+ dictWord{135, 10, 1768},
+ dictWord{132, 11, 757},
+ dictWord{5, 0, 29},
+ dictWord{140, 0, 638},
+ dictWord{7, 11, 655},
+ dictWord{135, 11, 1844},
+ dictWord{7, 0, 1418},
+ dictWord{6, 11, 257},
+ dictWord{135, 11, 1522},
+ dictWord{8, 11, 469},
+ dictWord{
+ 138,
+ 11,
+ 47,
+ },
+ dictWord{142, 11, 278},
+ dictWord{6, 10, 83},
+ dictWord{6, 10, 1733},
+ dictWord{135, 10, 1389},
+ dictWord{11, 11, 204},
+ dictWord{11, 11, 243},
+ dictWord{140, 11, 293},
+ dictWord{135, 11, 1875},
+ dictWord{6, 0, 1710},
+ dictWord{135, 0, 2038},
+ dictWord{137, 11, 299},
+ dictWord{4, 0, 17},
+ dictWord{5, 0, 23},
+ dictWord{7, 0, 995},
+ dictWord{11, 0, 383},
+ dictWord{11, 0, 437},
+ dictWord{12, 0, 460},
+ dictWord{140, 0, 532},
+ dictWord{133, 0, 862},
+ dictWord{137, 10, 696},
+ dictWord{6, 0, 592},
+ dictWord{138, 0, 946},
+ dictWord{138, 11, 599},
+ dictWord{7, 10, 1718},
+ dictWord{9, 10, 95},
+ dictWord{9, 10, 274},
+ dictWord{10, 10, 279},
+ dictWord{10, 10, 317},
+ dictWord{10, 10, 420},
+ dictWord{11, 10, 303},
+ dictWord{11, 10, 808},
+ dictWord{12, 10, 134},
+ dictWord{12, 10, 367},
+ dictWord{
+ 13,
+ 10,
+ 149,
+ },
+ dictWord{13, 10, 347},
+ dictWord{14, 10, 349},
+ dictWord{14, 10, 406},
+ dictWord{18, 10, 22},
+ dictWord{18, 10, 89},
+ dictWord{18, 10, 122},
+ dictWord{
+ 147,
+ 10,
+ 47,
+ },
+ dictWord{8, 0, 70},
+ dictWord{12, 0, 171},
+ dictWord{141, 0, 272},
+ dictWord{133, 10, 26},
+ dictWord{132, 10, 550},
+ dictWord{137, 0, 812},
+ dictWord{
+ 10,
+ 0,
+ 233,
+ },
+ dictWord{139, 0, 76},
+ dictWord{134, 0, 988},
+ dictWord{134, 0, 442},
+ dictWord{136, 10, 822},
+ dictWord{7, 0, 896},
+ dictWord{4, 10, 902},
+ dictWord{
+ 5,
+ 10,
+ 809,
+ },
+ dictWord{134, 10, 122},
+ dictWord{5, 11, 150},
+ dictWord{7, 11, 106},
+ dictWord{8, 11, 603},
+ dictWord{9, 11, 593},
+ dictWord{9, 11, 634},
+ dictWord{
+ 10,
+ 11,
+ 44,
+ },
+ dictWord{10, 11, 173},
+ dictWord{11, 11, 462},
+ dictWord{11, 11, 515},
+ dictWord{13, 11, 216},
+ dictWord{13, 11, 288},
+ dictWord{142, 11, 400},
+ dictWord{136, 0, 483},
+ dictWord{135, 10, 262},
+ dictWord{6, 0, 1709},
+ dictWord{133, 10, 620},
+ dictWord{4, 10, 34},
+ dictWord{5, 10, 574},
+ dictWord{7, 10, 279},
+ dictWord{7, 10, 1624},
+ dictWord{136, 10, 601},
+ dictWord{137, 10, 170},
+ dictWord{147, 0, 119},
+ dictWord{12, 11, 108},
+ dictWord{141, 11, 291},
+ dictWord{
+ 11,
+ 0,
+ 69,
+ },
+ dictWord{12, 0, 105},
+ dictWord{12, 0, 117},
+ dictWord{13, 0, 213},
+ dictWord{14, 0, 13},
+ dictWord{14, 0, 62},
+ dictWord{14, 0, 177},
+ dictWord{14, 0, 421},
+ dictWord{15, 0, 19},
+ dictWord{146, 0, 141},
+ dictWord{137, 0, 309},
+ dictWord{11, 11, 278},
+ dictWord{142, 11, 73},
+ dictWord{7, 0, 608},
+ dictWord{7, 0, 976},
+ dictWord{9, 0, 146},
+ dictWord{10, 0, 206},
+ dictWord{10, 0, 596},
+ dictWord{13, 0, 218},
+ dictWord{142, 0, 153},
+ dictWord{133, 10, 332},
+ dictWord{6, 10, 261},
+ dictWord{
+ 8,
+ 10,
+ 182,
+ },
+ dictWord{139, 10, 943},
+ dictWord{4, 11, 493},
+ dictWord{144, 11, 55},
+ dictWord{134, 10, 1721},
+ dictWord{132, 0, 768},
+ dictWord{4, 10, 933},
+ dictWord{133, 10, 880},
+ dictWord{7, 11, 555},
+ dictWord{7, 11, 1316},
+ dictWord{7, 11, 1412},
+ dictWord{7, 11, 1839},
+ dictWord{9, 11, 192},
+ dictWord{
+ 9,
+ 11,
+ 589,
+ },
+ dictWord{11, 11, 241},
+ dictWord{11, 11, 676},
+ dictWord{11, 11, 811},
+ dictWord{11, 11, 891},
+ dictWord{12, 11, 140},
+ dictWord{12, 11, 346},
+ dictWord{
+ 12,
+ 11,
+ 479,
+ },
+ dictWord{13, 11, 30},
+ dictWord{13, 11, 49},
+ dictWord{13, 11, 381},
+ dictWord{14, 11, 188},
+ dictWord{15, 11, 150},
+ dictWord{16, 11, 76},
+ dictWord{18, 11, 30},
+ dictWord{148, 11, 52},
+ dictWord{4, 0, 518},
+ dictWord{135, 0, 1136},
+ dictWord{6, 11, 568},
+ dictWord{7, 11, 112},
+ dictWord{7, 11, 1804},
+ dictWord{8, 11, 362},
+ dictWord{8, 11, 410},
+ dictWord{8, 11, 830},
+ dictWord{9, 11, 514},
+ dictWord{11, 11, 649},
+ dictWord{142, 11, 157},
+ dictWord{135, 11, 673},
+ dictWord{8, 0, 689},
+ dictWord{137, 0, 863},
+ dictWord{4, 0, 18},
+ dictWord{7, 0, 145},
+ dictWord{7, 0, 444},
+ dictWord{7, 0, 1278},
+ dictWord{8, 0, 49},
+ dictWord{8, 0, 400},
+ dictWord{9, 0, 71},
+ dictWord{9, 0, 250},
+ dictWord{10, 0, 459},
+ dictWord{12, 0, 160},
+ dictWord{16, 0, 24},
+ dictWord{132, 11, 625},
+ dictWord{140, 0, 1020},
+ dictWord{4, 0, 997},
+ dictWord{6, 0, 1946},
+ dictWord{6, 0, 1984},
+ dictWord{134, 0, 1998},
+ dictWord{6, 11, 16},
+ dictWord{6, 11, 158},
+ dictWord{7, 11, 43},
+ dictWord{
+ 7,
+ 11,
+ 129,
+ },
+ dictWord{7, 11, 181},
+ dictWord{8, 11, 276},
+ dictWord{8, 11, 377},
+ dictWord{10, 11, 523},
+ dictWord{11, 11, 816},
+ dictWord{12, 11, 455},
+ dictWord{
+ 13,
+ 11,
+ 303,
+ },
+ dictWord{142, 11, 135},
+ dictWord{133, 10, 812},
+ dictWord{134, 0, 658},
+ dictWord{4, 11, 1},
+ dictWord{7, 11, 1143},
+ dictWord{7, 11, 1463},
+ dictWord{8, 11, 61},
+ dictWord{9, 11, 207},
+ dictWord{9, 11, 390},
+ dictWord{9, 11, 467},
+ dictWord{139, 11, 836},
+ dictWord{150, 11, 26},
+ dictWord{140, 0, 106},
+ dictWord{6, 0, 1827},
+ dictWord{10, 0, 931},
+ dictWord{18, 0, 166},
+ dictWord{20, 0, 114},
+ dictWord{4, 10, 137},
+ dictWord{7, 10, 1178},
+ dictWord{7, 11, 1319},
+ dictWord{135, 10, 1520},
+ dictWord{133, 0, 1010},
+ dictWord{4, 11, 723},
+ dictWord{5, 11, 895},
+ dictWord{7, 11, 1031},
+ dictWord{8, 11, 199},
+ dictWord{8, 11, 340},
+ dictWord{9, 11, 153},
+ dictWord{9, 11, 215},
+ dictWord{10, 11, 21},
+ dictWord{10, 11, 59},
+ dictWord{10, 11, 80},
+ dictWord{10, 11, 224},
+ dictWord{11, 11, 229},
+ dictWord{11, 11, 652},
+ dictWord{12, 11, 192},
+ dictWord{13, 11, 146},
+ dictWord{142, 11, 91},
+ dictWord{132, 11, 295},
+ dictWord{6, 11, 619},
+ dictWord{
+ 7,
+ 11,
+ 898,
+ },
+ dictWord{7, 11, 1092},
+ dictWord{8, 11, 485},
+ dictWord{18, 11, 28},
+ dictWord{147, 11, 116},
+ dictWord{137, 11, 51},
+ dictWord{6, 10, 1661},
+ dictWord{
+ 7,
+ 10,
+ 1975,
+ },
+ dictWord{7, 10, 2009},
+ dictWord{135, 10, 2011},
+ dictWord{5, 11, 309},
+ dictWord{140, 11, 211},
+ dictWord{5, 0, 87},
+ dictWord{7, 0, 313},
+ dictWord{
+ 7,
+ 0,
+ 1103,
+ },
+ dictWord{10, 0, 208},
+ dictWord{10, 0, 582},
+ dictWord{11, 0, 389},
+ dictWord{11, 0, 813},
+ dictWord{12, 0, 385},
+ dictWord{13, 0, 286},
+ dictWord{
+ 14,
+ 0,
+ 124,
+ },
+ dictWord{146, 0, 108},
+ dictWord{5, 11, 125},
+ dictWord{8, 11, 77},
+ dictWord{138, 11, 15},
+ dictWord{132, 0, 267},
+ dictWord{133, 0, 703},
+ dictWord{
+ 137,
+ 11,
+ 155,
+ },
+ dictWord{133, 11, 439},
+ dictWord{11, 11, 164},
+ dictWord{140, 11, 76},
+ dictWord{9, 0, 496},
+ dictWord{5, 10, 89},
+ dictWord{7, 10, 1915},
+ dictWord{
+ 9,
+ 10,
+ 185,
+ },
+ dictWord{9, 10, 235},
+ dictWord{10, 10, 64},
+ dictWord{10, 10, 270},
+ dictWord{10, 10, 403},
+ dictWord{10, 10, 469},
+ dictWord{10, 10, 529},
+ dictWord{10, 10, 590},
+ dictWord{11, 10, 140},
+ dictWord{11, 10, 860},
+ dictWord{13, 10, 1},
+ dictWord{13, 10, 422},
+ dictWord{14, 10, 341},
+ dictWord{14, 10, 364},
+ dictWord{17, 10, 93},
+ dictWord{18, 10, 113},
+ dictWord{19, 10, 97},
+ dictWord{147, 10, 113},
+ dictWord{133, 10, 695},
+ dictWord{135, 0, 1121},
+ dictWord{
+ 5,
+ 10,
+ 6,
+ },
+ dictWord{6, 10, 183},
+ dictWord{7, 10, 680},
+ dictWord{7, 10, 978},
+ dictWord{7, 10, 1013},
+ dictWord{7, 10, 1055},
+ dictWord{12, 10, 230},
+ dictWord{
+ 13,
+ 10,
+ 172,
+ },
+ dictWord{146, 10, 29},
+ dictWord{4, 11, 8},
+ dictWord{7, 11, 1152},
+ dictWord{7, 11, 1153},
+ dictWord{7, 11, 1715},
+ dictWord{9, 11, 374},
+ dictWord{
+ 10,
+ 11,
+ 478,
+ },
+ dictWord{139, 11, 648},
+ dictWord{135, 11, 1099},
+ dictWord{6, 10, 29},
+ dictWord{139, 10, 63},
+ dictWord{4, 0, 561},
+ dictWord{10, 0, 249},
+ dictWord{
+ 139,
+ 0,
+ 209,
+ },
+ dictWord{132, 0, 760},
+ dictWord{7, 11, 799},
+ dictWord{138, 11, 511},
+ dictWord{136, 11, 87},
+ dictWord{9, 0, 154},
+ dictWord{140, 0, 485},
+ dictWord{136, 0, 255},
+ dictWord{132, 0, 323},
+ dictWord{140, 0, 419},
+ dictWord{132, 10, 311},
+ dictWord{134, 10, 1740},
+ dictWord{4, 0, 368},
+ dictWord{
+ 135,
+ 0,
+ 641,
+ },
+ dictWord{7, 10, 170},
+ dictWord{8, 10, 90},
+ dictWord{8, 10, 177},
+ dictWord{8, 10, 415},
+ dictWord{11, 10, 714},
+ dictWord{142, 10, 281},
+ dictWord{
+ 4,
+ 11,
+ 69,
+ },
+ dictWord{5, 11, 122},
+ dictWord{9, 11, 656},
+ dictWord{138, 11, 464},
+ dictWord{5, 11, 849},
+ dictWord{134, 11, 1633},
+ dictWord{8, 0, 522},
+ dictWord{
+ 142,
+ 0,
+ 328,
+ },
+ dictWord{11, 10, 91},
+ dictWord{13, 10, 129},
+ dictWord{15, 10, 101},
+ dictWord{145, 10, 125},
+ dictWord{7, 0, 562},
+ dictWord{8, 0, 551},
+ dictWord{
+ 4,
+ 10,
+ 494,
+ },
+ dictWord{6, 10, 74},
+ dictWord{7, 10, 44},
+ dictWord{11, 11, 499},
+ dictWord{12, 10, 17},
+ dictWord{15, 10, 5},
+ dictWord{148, 10, 11},
+ dictWord{4, 10, 276},
+ dictWord{133, 10, 296},
+ dictWord{9, 0, 92},
+ dictWord{147, 0, 91},
+ dictWord{4, 10, 7},
+ dictWord{5, 10, 90},
+ dictWord{5, 10, 158},
+ dictWord{6, 10, 542},
+ dictWord{
+ 7,
+ 10,
+ 221,
+ },
+ dictWord{7, 10, 1574},
+ dictWord{9, 10, 490},
+ dictWord{10, 10, 540},
+ dictWord{11, 10, 443},
+ dictWord{139, 10, 757},
+ dictWord{6, 0, 525},
+ dictWord{
+ 6,
+ 0,
+ 1976,
+ },
+ dictWord{8, 0, 806},
+ dictWord{9, 0, 876},
+ dictWord{140, 0, 284},
+ dictWord{5, 11, 859},
+ dictWord{7, 10, 588},
+ dictWord{7, 11, 1160},
+ dictWord{
+ 8,
+ 11,
+ 107,
+ },
+ dictWord{9, 10, 175},
+ dictWord{9, 11, 291},
+ dictWord{9, 11, 439},
+ dictWord{10, 10, 530},
+ dictWord{10, 11, 663},
+ dictWord{11, 11, 609},
+ dictWord{
+ 140,
+ 11,
+ 197,
+ },
+ dictWord{7, 11, 168},
+ dictWord{13, 11, 196},
+ dictWord{141, 11, 237},
+ dictWord{139, 0, 958},
+ dictWord{133, 0, 594},
+ dictWord{135, 10, 580},
+ dictWord{7, 10, 88},
+ dictWord{136, 10, 627},
+ dictWord{6, 0, 479},
+ dictWord{6, 0, 562},
+ dictWord{7, 0, 1060},
+ dictWord{13, 0, 6},
+ dictWord{5, 10, 872},
+ dictWord{
+ 6,
+ 10,
+ 57,
+ },
+ dictWord{7, 10, 471},
+ dictWord{9, 10, 447},
+ dictWord{137, 10, 454},
+ dictWord{136, 11, 413},
+ dictWord{145, 11, 19},
+ dictWord{4, 11, 117},
+ dictWord{
+ 6,
+ 11,
+ 372,
+ },
+ dictWord{7, 11, 1905},
+ dictWord{142, 11, 323},
+ dictWord{4, 11, 722},
+ dictWord{139, 11, 471},
+ dictWord{17, 0, 61},
+ dictWord{5, 10, 31},
+ dictWord{134, 10, 614},
+ dictWord{8, 10, 330},
+ dictWord{140, 10, 477},
+ dictWord{7, 10, 1200},
+ dictWord{138, 10, 460},
+ dictWord{6, 10, 424},
+ dictWord{
+ 135,
+ 10,
+ 1866,
+ },
+ dictWord{6, 0, 1641},
+ dictWord{136, 0, 820},
+ dictWord{6, 0, 1556},
+ dictWord{134, 0, 1618},
+ dictWord{9, 11, 5},
+ dictWord{12, 11, 216},
+ dictWord{
+ 12,
+ 11,
+ 294,
+ },
+ dictWord{12, 11, 298},
+ dictWord{12, 11, 400},
+ dictWord{12, 11, 518},
+ dictWord{13, 11, 229},
+ dictWord{143, 11, 139},
+ dictWord{15, 11, 155},
+ dictWord{144, 11, 79},
+ dictWord{4, 0, 302},
+ dictWord{135, 0, 1766},
+ dictWord{5, 10, 13},
+ dictWord{134, 10, 142},
+ dictWord{6, 0, 148},
+ dictWord{7, 0, 1313},
+ dictWord{
+ 7,
+ 10,
+ 116,
+ },
+ dictWord{8, 10, 322},
+ dictWord{8, 10, 755},
+ dictWord{9, 10, 548},
+ dictWord{10, 10, 714},
+ dictWord{11, 10, 884},
+ dictWord{141, 10, 324},
+ dictWord{137, 0, 676},
+ dictWord{9, 11, 88},
+ dictWord{139, 11, 270},
+ dictWord{5, 11, 12},
+ dictWord{7, 11, 375},
+ dictWord{137, 11, 438},
+ dictWord{134, 0, 1674},
+ dictWord{7, 10, 1472},
+ dictWord{135, 10, 1554},
+ dictWord{11, 0, 178},
+ dictWord{7, 10, 1071},
+ dictWord{7, 10, 1541},
+ dictWord{7, 10, 1767},
+ dictWord{
+ 7,
+ 10,
+ 1806,
+ },
+ dictWord{11, 10, 162},
+ dictWord{11, 10, 242},
+ dictWord{12, 10, 605},
+ dictWord{15, 10, 26},
+ dictWord{144, 10, 44},
+ dictWord{6, 0, 389},
+ dictWord{
+ 7,
+ 0,
+ 149,
+ },
+ dictWord{9, 0, 142},
+ dictWord{138, 0, 94},
+ dictWord{140, 11, 71},
+ dictWord{145, 10, 115},
+ dictWord{6, 0, 8},
+ dictWord{7, 0, 1881},
+ dictWord{8, 0, 91},
+ dictWord{11, 11, 966},
+ dictWord{12, 11, 287},
+ dictWord{13, 11, 342},
+ dictWord{13, 11, 402},
+ dictWord{15, 11, 110},
+ dictWord{143, 11, 163},
+ dictWord{
+ 4,
+ 11,
+ 258,
+ },
+ dictWord{136, 11, 639},
+ dictWord{6, 11, 22},
+ dictWord{7, 11, 903},
+ dictWord{138, 11, 577},
+ dictWord{133, 11, 681},
+ dictWord{135, 10, 1111},
+ dictWord{135, 11, 1286},
+ dictWord{9, 0, 112},
+ dictWord{8, 10, 1},
+ dictWord{138, 10, 326},
+ dictWord{5, 10, 488},
+ dictWord{6, 10, 527},
+ dictWord{7, 10, 489},
+ dictWord{
+ 7,
+ 10,
+ 1636,
+ },
+ dictWord{8, 10, 121},
+ dictWord{8, 10, 144},
+ dictWord{8, 10, 359},
+ dictWord{9, 10, 193},
+ dictWord{9, 10, 241},
+ dictWord{9, 10, 336},
+ dictWord{
+ 9,
+ 10,
+ 882,
+ },
+ dictWord{11, 10, 266},
+ dictWord{11, 10, 372},
+ dictWord{11, 10, 944},
+ dictWord{12, 10, 401},
+ dictWord{140, 10, 641},
+ dictWord{4, 11, 664},
+ dictWord{133, 11, 804},
+ dictWord{6, 0, 747},
+ dictWord{134, 0, 1015},
+ dictWord{135, 0, 1746},
+ dictWord{9, 10, 31},
+ dictWord{10, 10, 244},
+ dictWord{
+ 10,
+ 10,
+ 699,
+ },
+ dictWord{12, 10, 149},
+ dictWord{141, 10, 497},
+ dictWord{133, 10, 377},
+ dictWord{135, 0, 24},
+ dictWord{6, 0, 1352},
+ dictWord{5, 11, 32},
+ dictWord{
+ 145,
+ 10,
+ 101,
+ },
+ dictWord{7, 0, 1530},
+ dictWord{10, 0, 158},
+ dictWord{13, 0, 13},
+ dictWord{13, 0, 137},
+ dictWord{13, 0, 258},
+ dictWord{14, 0, 111},
+ dictWord{
+ 14,
+ 0,
+ 225,
+ },
+ dictWord{14, 0, 253},
+ dictWord{14, 0, 304},
+ dictWord{14, 0, 339},
+ dictWord{14, 0, 417},
+ dictWord{146, 0, 33},
+ dictWord{4, 0, 503},
+ dictWord{
+ 135,
+ 0,
+ 1661,
+ },
+ dictWord{5, 0, 130},
+ dictWord{6, 0, 845},
+ dictWord{7, 0, 1314},
+ dictWord{9, 0, 610},
+ dictWord{10, 0, 718},
+ dictWord{11, 0, 601},
+ dictWord{11, 0, 819},
+ dictWord{11, 0, 946},
+ dictWord{140, 0, 536},
+ dictWord{10, 0, 149},
+ dictWord{11, 0, 280},
+ dictWord{142, 0, 336},
+ dictWord{134, 0, 1401},
+ dictWord{
+ 135,
+ 0,
+ 1946,
+ },
+ dictWord{8, 0, 663},
+ dictWord{144, 0, 8},
+ dictWord{134, 0, 1607},
+ dictWord{135, 10, 2023},
+ dictWord{4, 11, 289},
+ dictWord{7, 11, 629},
+ dictWord{
+ 7,
+ 11,
+ 1698,
+ },
+ dictWord{7, 11, 1711},
+ dictWord{140, 11, 215},
+ dictWord{6, 11, 450},
+ dictWord{136, 11, 109},
+ dictWord{10, 0, 882},
+ dictWord{10, 0, 883},
+ dictWord{10, 0, 914},
+ dictWord{138, 0, 928},
+ dictWord{133, 10, 843},
+ dictWord{136, 11, 705},
+ dictWord{132, 10, 554},
+ dictWord{133, 10, 536},
+ dictWord{
+ 5,
+ 0,
+ 417,
+ },
+ dictWord{9, 10, 79},
+ dictWord{11, 10, 625},
+ dictWord{145, 10, 7},
+ dictWord{7, 11, 1238},
+ dictWord{142, 11, 37},
+ dictWord{4, 0, 392},
+ dictWord{
+ 135,
+ 0,
+ 1597,
+ },
+ dictWord{5, 0, 433},
+ dictWord{9, 0, 633},
+ dictWord{11, 0, 629},
+ dictWord{132, 10, 424},
+ dictWord{7, 10, 336},
+ dictWord{136, 10, 785},
+ dictWord{
+ 134,
+ 11,
+ 355,
+ },
+ dictWord{6, 0, 234},
+ dictWord{7, 0, 769},
+ dictWord{9, 0, 18},
+ dictWord{138, 0, 358},
+ dictWord{4, 10, 896},
+ dictWord{134, 10, 1777},
+ dictWord{
+ 138,
+ 11,
+ 323,
+ },
+ dictWord{7, 0, 140},
+ dictWord{7, 0, 1950},
+ dictWord{8, 0, 680},
+ dictWord{11, 0, 817},
+ dictWord{147, 0, 88},
+ dictWord{7, 0, 1222},
+ dictWord{
+ 138,
+ 0,
+ 386,
+ },
+ dictWord{139, 11, 908},
+ dictWord{11, 0, 249},
+ dictWord{12, 0, 313},
+ dictWord{16, 0, 66},
+ dictWord{145, 0, 26},
+ dictWord{134, 0, 5},
+ dictWord{7, 10, 750},
+ dictWord{9, 10, 223},
+ dictWord{11, 10, 27},
+ dictWord{11, 10, 466},
+ dictWord{12, 10, 624},
+ dictWord{14, 10, 265},
+ dictWord{146, 10, 61},
+ dictWord{
+ 134,
+ 11,
+ 26,
+ },
+ dictWord{134, 0, 1216},
+ dictWord{5, 0, 963},
+ dictWord{134, 0, 1773},
+ dictWord{4, 11, 414},
+ dictWord{5, 11, 467},
+ dictWord{9, 11, 654},
+ dictWord{
+ 10,
+ 11,
+ 451,
+ },
+ dictWord{12, 11, 59},
+ dictWord{141, 11, 375},
+ dictWord{135, 11, 17},
+ dictWord{4, 10, 603},
+ dictWord{133, 10, 661},
+ dictWord{4, 10, 11},
+ dictWord{
+ 6,
+ 10,
+ 128,
+ },
+ dictWord{7, 10, 231},
+ dictWord{7, 10, 1533},
+ dictWord{138, 10, 725},
+ dictWord{135, 11, 955},
+ dictWord{7, 0, 180},
+ dictWord{8, 0, 509},
+ dictWord{
+ 136,
+ 0,
+ 792,
+ },
+ dictWord{132, 10, 476},
+ dictWord{132, 0, 1002},
+ dictWord{133, 11, 538},
+ dictWord{135, 10, 1807},
+ dictWord{132, 0, 931},
+ dictWord{7, 0, 943},
+ dictWord{11, 0, 614},
+ dictWord{140, 0, 747},
+ dictWord{135, 0, 1837},
+ dictWord{9, 10, 20},
+ dictWord{10, 10, 324},
+ dictWord{10, 10, 807},
+ dictWord{
+ 139,
+ 10,
+ 488,
+ },
+ dictWord{134, 0, 641},
+ dictWord{6, 11, 280},
+ dictWord{10, 11, 502},
+ dictWord{11, 11, 344},
+ dictWord{140, 11, 38},
+ dictWord{5, 11, 45},
+ dictWord{
+ 7,
+ 11,
+ 1161,
+ },
+ dictWord{11, 11, 448},
+ dictWord{11, 11, 880},
+ dictWord{13, 11, 139},
+ dictWord{13, 11, 407},
+ dictWord{15, 11, 16},
+ dictWord{17, 11, 95},
+ dictWord{
+ 18,
+ 11,
+ 66,
+ },
+ dictWord{18, 11, 88},
+ dictWord{18, 11, 123},
+ dictWord{149, 11, 7},
+ dictWord{9, 0, 280},
+ dictWord{138, 0, 134},
+ dictWord{22, 0, 22},
+ dictWord{23, 0, 5},
+ dictWord{151, 0, 29},
+ dictWord{136, 11, 777},
+ dictWord{4, 0, 90},
+ dictWord{5, 0, 545},
+ dictWord{7, 0, 754},
+ dictWord{9, 0, 186},
+ dictWord{10, 0, 72},
+ dictWord{
+ 10,
+ 0,
+ 782,
+ },
+ dictWord{11, 0, 577},
+ dictWord{11, 0, 610},
+ dictWord{11, 0, 960},
+ dictWord{12, 0, 354},
+ dictWord{12, 0, 362},
+ dictWord{12, 0, 595},
+ dictWord{
+ 4,
+ 11,
+ 410,
+ },
+ dictWord{135, 11, 521},
+ dictWord{135, 11, 1778},
+ dictWord{5, 10, 112},
+ dictWord{6, 10, 103},
+ dictWord{134, 10, 150},
+ dictWord{138, 10, 356},
+ dictWord{132, 0, 742},
+ dictWord{7, 0, 151},
+ dictWord{9, 0, 329},
+ dictWord{139, 0, 254},
+ dictWord{8, 0, 853},
+ dictWord{8, 0, 881},
+ dictWord{8, 0, 911},
+ dictWord{
+ 8,
+ 0,
+ 912,
+ },
+ dictWord{10, 0, 872},
+ dictWord{12, 0, 741},
+ dictWord{12, 0, 742},
+ dictWord{152, 0, 18},
+ dictWord{4, 11, 573},
+ dictWord{136, 11, 655},
+ dictWord{
+ 6,
+ 0,
+ 921,
+ },
+ dictWord{134, 0, 934},
+ dictWord{9, 0, 187},
+ dictWord{10, 0, 36},
+ dictWord{11, 0, 1016},
+ dictWord{17, 0, 44},
+ dictWord{146, 0, 64},
+ dictWord{7, 0, 833},
+ dictWord{136, 0, 517},
+ dictWord{4, 0, 506},
+ dictWord{5, 0, 295},
+ dictWord{135, 0, 1680},
+ dictWord{4, 10, 708},
+ dictWord{8, 10, 15},
+ dictWord{9, 10, 50},
+ dictWord{
+ 9,
+ 10,
+ 386,
+ },
+ dictWord{11, 10, 18},
+ dictWord{11, 10, 529},
+ dictWord{140, 10, 228},
+ dictWord{7, 0, 251},
+ dictWord{7, 0, 1701},
+ dictWord{8, 0, 436},
+ dictWord{
+ 4,
+ 10,
+ 563,
+ },
+ dictWord{7, 10, 592},
+ dictWord{7, 10, 637},
+ dictWord{7, 10, 770},
+ dictWord{8, 10, 463},
+ dictWord{9, 10, 60},
+ dictWord{9, 10, 335},
+ dictWord{9, 10, 904},
+ dictWord{10, 10, 73},
+ dictWord{11, 10, 434},
+ dictWord{12, 10, 585},
+ dictWord{13, 10, 331},
+ dictWord{18, 10, 110},
+ dictWord{148, 10, 60},
+ dictWord{
+ 132,
+ 10,
+ 502,
+ },
+ dictWord{136, 0, 584},
+ dictWord{6, 10, 347},
+ dictWord{138, 10, 161},
+ dictWord{7, 0, 987},
+ dictWord{9, 0, 688},
+ dictWord{10, 0, 522},
+ dictWord{
+ 11,
+ 0,
+ 788,
+ },
+ dictWord{12, 0, 137},
+ dictWord{12, 0, 566},
+ dictWord{14, 0, 9},
+ dictWord{14, 0, 24},
+ dictWord{14, 0, 64},
+ dictWord{7, 11, 899},
+ dictWord{142, 11, 325},
+ dictWord{4, 0, 214},
+ dictWord{5, 0, 500},
+ dictWord{5, 10, 102},
+ dictWord{6, 10, 284},
+ dictWord{7, 10, 1079},
+ dictWord{7, 10, 1423},
+ dictWord{7, 10, 1702},
+ dictWord{
+ 8,
+ 10,
+ 470,
+ },
+ dictWord{9, 10, 554},
+ dictWord{9, 10, 723},
+ dictWord{139, 10, 333},
+ dictWord{7, 10, 246},
+ dictWord{135, 10, 840},
+ dictWord{6, 10, 10},
+ dictWord{
+ 8,
+ 10,
+ 571,
+ },
+ dictWord{9, 10, 739},
+ dictWord{143, 10, 91},
+ dictWord{133, 10, 626},
+ dictWord{146, 0, 195},
+ dictWord{134, 0, 1775},
+ dictWord{7, 0, 389},
+ dictWord{7, 0, 700},
+ dictWord{7, 0, 940},
+ dictWord{8, 0, 514},
+ dictWord{9, 0, 116},
+ dictWord{9, 0, 535},
+ dictWord{10, 0, 118},
+ dictWord{11, 0, 107},
+ dictWord{
+ 11,
+ 0,
+ 148,
+ },
+ dictWord{11, 0, 922},
+ dictWord{12, 0, 254},
+ dictWord{12, 0, 421},
+ dictWord{142, 0, 238},
+ dictWord{5, 10, 18},
+ dictWord{6, 10, 526},
+ dictWord{13, 10, 24},
+ dictWord{13, 10, 110},
+ dictWord{19, 10, 5},
+ dictWord{147, 10, 44},
+ dictWord{132, 0, 743},
+ dictWord{11, 0, 292},
+ dictWord{4, 10, 309},
+ dictWord{5, 10, 462},
+ dictWord{7, 10, 970},
+ dictWord{135, 10, 1097},
+ dictWord{22, 10, 30},
+ dictWord{150, 10, 33},
+ dictWord{139, 11, 338},
+ dictWord{135, 11, 1598},
+ dictWord{
+ 7,
+ 0,
+ 1283,
+ },
+ dictWord{9, 0, 227},
+ dictWord{11, 0, 325},
+ dictWord{11, 0, 408},
+ dictWord{14, 0, 180},
+ dictWord{146, 0, 47},
+ dictWord{4, 0, 953},
+ dictWord{6, 0, 1805},
+ dictWord{6, 0, 1814},
+ dictWord{6, 0, 1862},
+ dictWord{140, 0, 774},
+ dictWord{6, 11, 611},
+ dictWord{135, 11, 1733},
+ dictWord{135, 11, 1464},
+ dictWord{
+ 5,
+ 0,
+ 81,
+ },
+ dictWord{7, 0, 146},
+ dictWord{7, 0, 1342},
+ dictWord{8, 0, 53},
+ dictWord{8, 0, 561},
+ dictWord{8, 0, 694},
+ dictWord{8, 0, 754},
+ dictWord{9, 0, 115},
+ dictWord{
+ 9,
+ 0,
+ 179,
+ },
+ dictWord{9, 0, 894},
+ dictWord{10, 0, 462},
+ dictWord{10, 0, 813},
+ dictWord{11, 0, 230},
+ dictWord{11, 0, 657},
+ dictWord{11, 0, 699},
+ dictWord{11, 0, 748},
+ dictWord{12, 0, 119},
+ dictWord{12, 0, 200},
+ dictWord{12, 0, 283},
+ dictWord{142, 0, 273},
+ dictWord{5, 0, 408},
+ dictWord{6, 0, 789},
+ dictWord{6, 0, 877},
+ dictWord{
+ 6,
+ 0,
+ 1253,
+ },
+ dictWord{6, 0, 1413},
+ dictWord{137, 0, 747},
+ dictWord{134, 10, 1704},
+ dictWord{135, 11, 663},
+ dictWord{6, 0, 1910},
+ dictWord{6, 0, 1915},
+ dictWord{6, 0, 1923},
+ dictWord{9, 0, 913},
+ dictWord{9, 0, 928},
+ dictWord{9, 0, 950},
+ dictWord{9, 0, 954},
+ dictWord{9, 0, 978},
+ dictWord{9, 0, 993},
+ dictWord{12, 0, 812},
+ dictWord{12, 0, 819},
+ dictWord{12, 0, 831},
+ dictWord{12, 0, 833},
+ dictWord{12, 0, 838},
+ dictWord{12, 0, 909},
+ dictWord{12, 0, 928},
+ dictWord{12, 0, 931},
+ dictWord{12, 0, 950},
+ dictWord{15, 0, 186},
+ dictWord{15, 0, 187},
+ dictWord{15, 0, 195},
+ dictWord{15, 0, 196},
+ dictWord{15, 0, 209},
+ dictWord{15, 0, 215},
+ dictWord{
+ 15,
+ 0,
+ 236,
+ },
+ dictWord{15, 0, 241},
+ dictWord{15, 0, 249},
+ dictWord{15, 0, 253},
+ dictWord{18, 0, 180},
+ dictWord{18, 0, 221},
+ dictWord{18, 0, 224},
+ dictWord{
+ 18,
+ 0,
+ 227,
+ },
+ dictWord{18, 0, 229},
+ dictWord{149, 0, 60},
+ dictWord{7, 0, 1826},
+ dictWord{135, 0, 1938},
+ dictWord{11, 0, 490},
+ dictWord{18, 0, 143},
+ dictWord{
+ 5,
+ 10,
+ 86,
+ },
+ dictWord{7, 10, 743},
+ dictWord{9, 10, 85},
+ dictWord{10, 10, 281},
+ dictWord{10, 10, 432},
+ dictWord{12, 10, 251},
+ dictWord{13, 10, 118},
+ dictWord{
+ 142,
+ 10,
+ 378,
+ },
+ dictWord{5, 10, 524},
+ dictWord{133, 10, 744},
+ dictWord{141, 11, 442},
+ dictWord{10, 10, 107},
+ dictWord{140, 10, 436},
+ dictWord{135, 11, 503},
+ dictWord{134, 0, 1162},
+ dictWord{132, 10, 927},
+ dictWord{7, 0, 30},
+ dictWord{8, 0, 86},
+ dictWord{8, 0, 315},
+ dictWord{8, 0, 700},
+ dictWord{9, 0, 576},
+ dictWord{
+ 9,
+ 0,
+ 858,
+ },
+ dictWord{10, 0, 414},
+ dictWord{11, 0, 310},
+ dictWord{11, 0, 888},
+ dictWord{11, 0, 904},
+ dictWord{12, 0, 361},
+ dictWord{13, 0, 248},
+ dictWord{13, 0, 371},
+ dictWord{14, 0, 142},
+ dictWord{12, 10, 670},
+ dictWord{146, 10, 94},
+ dictWord{134, 0, 721},
+ dictWord{4, 11, 113},
+ dictWord{5, 11, 163},
+ dictWord{5, 11, 735},
+ dictWord{7, 11, 1009},
+ dictWord{7, 10, 1149},
+ dictWord{9, 11, 9},
+ dictWord{9, 10, 156},
+ dictWord{9, 11, 771},
+ dictWord{12, 11, 90},
+ dictWord{13, 11, 138},
+ dictWord{13, 11, 410},
+ dictWord{143, 11, 128},
+ dictWord{138, 0, 839},
+ dictWord{133, 10, 778},
+ dictWord{137, 0, 617},
+ dictWord{133, 10, 502},
+ dictWord{
+ 8,
+ 10,
+ 196,
+ },
+ dictWord{10, 10, 283},
+ dictWord{139, 10, 406},
+ dictWord{6, 0, 428},
+ dictWord{7, 0, 524},
+ dictWord{8, 0, 169},
+ dictWord{8, 0, 234},
+ dictWord{9, 0, 480},
+ dictWord{138, 0, 646},
+ dictWord{133, 10, 855},
+ dictWord{134, 0, 1648},
+ dictWord{7, 0, 1205},
+ dictWord{138, 0, 637},
+ dictWord{7, 0, 1596},
+ dictWord{
+ 4,
+ 11,
+ 935,
+ },
+ dictWord{133, 11, 823},
+ dictWord{5, 11, 269},
+ dictWord{7, 11, 434},
+ dictWord{7, 11, 891},
+ dictWord{8, 11, 339},
+ dictWord{9, 11, 702},
+ dictWord{
+ 11,
+ 11,
+ 594,
+ },
+ dictWord{11, 11, 718},
+ dictWord{145, 11, 100},
+ dictWord{7, 11, 878},
+ dictWord{9, 11, 485},
+ dictWord{141, 11, 264},
+ dictWord{4, 0, 266},
+ dictWord{
+ 8,
+ 0,
+ 4,
+ },
+ dictWord{9, 0, 39},
+ dictWord{10, 0, 166},
+ dictWord{11, 0, 918},
+ dictWord{12, 0, 635},
+ dictWord{20, 0, 10},
+ dictWord{22, 0, 27},
+ dictWord{22, 0, 43},
+ dictWord{
+ 22,
+ 0,
+ 52,
+ },
+ dictWord{134, 11, 1713},
+ dictWord{7, 10, 1400},
+ dictWord{9, 10, 446},
+ dictWord{138, 10, 45},
+ dictWord{135, 11, 900},
+ dictWord{132, 0, 862},
+ dictWord{134, 0, 1554},
+ dictWord{135, 11, 1033},
+ dictWord{19, 0, 16},
+ dictWord{147, 11, 16},
+ dictWord{135, 11, 1208},
+ dictWord{7, 0, 157},
+ dictWord{
+ 136,
+ 0,
+ 279,
+ },
+ dictWord{6, 0, 604},
+ dictWord{136, 0, 391},
+ dictWord{13, 10, 455},
+ dictWord{15, 10, 99},
+ dictWord{15, 10, 129},
+ dictWord{144, 10, 68},
+ dictWord{
+ 135,
+ 10,
+ 172,
+ },
+ dictWord{7, 0, 945},
+ dictWord{11, 0, 713},
+ dictWord{139, 0, 744},
+ dictWord{4, 0, 973},
+ dictWord{10, 0, 877},
+ dictWord{10, 0, 937},
+ dictWord{
+ 10,
+ 0,
+ 938,
+ },
+ dictWord{140, 0, 711},
+ dictWord{139, 0, 1022},
+ dictWord{132, 10, 568},
+ dictWord{142, 11, 143},
+ dictWord{4, 0, 567},
+ dictWord{9, 0, 859},
+ dictWord{
+ 132,
+ 10,
+ 732,
+ },
+ dictWord{7, 0, 1846},
+ dictWord{136, 0, 628},
+ dictWord{136, 10, 733},
+ dictWord{133, 0, 762},
+ dictWord{4, 10, 428},
+ dictWord{135, 10, 1789},
+ dictWord{10, 0, 784},
+ dictWord{13, 0, 191},
+ dictWord{7, 10, 2015},
+ dictWord{140, 10, 665},
+ dictWord{133, 0, 298},
+ dictWord{7, 0, 633},
+ dictWord{7, 0, 905},
+ dictWord{7, 0, 909},
+ dictWord{7, 0, 1538},
+ dictWord{9, 0, 767},
+ dictWord{140, 0, 636},
+ dictWord{138, 10, 806},
+ dictWord{132, 0, 795},
+ dictWord{139, 0, 301},
+ dictWord{135, 0, 1970},
+ dictWord{5, 11, 625},
+ dictWord{135, 11, 1617},
+ dictWord{135, 11, 275},
+ dictWord{7, 11, 37},
+ dictWord{8, 11, 425},
+ dictWord{
+ 8,
+ 11,
+ 693,
+ },
+ dictWord{9, 11, 720},
+ dictWord{10, 11, 380},
+ dictWord{10, 11, 638},
+ dictWord{11, 11, 273},
+ dictWord{11, 11, 307},
+ dictWord{11, 11, 473},
+ dictWord{
+ 12,
+ 11,
+ 61,
+ },
+ dictWord{143, 11, 43},
+ dictWord{135, 11, 198},
+ dictWord{134, 0, 1236},
+ dictWord{7, 0, 369},
+ dictWord{12, 0, 644},
+ dictWord{12, 0, 645},
+ dictWord{144, 0, 90},
+ dictWord{19, 0, 15},
+ dictWord{149, 0, 27},
+ dictWord{6, 0, 71},
+ dictWord{7, 0, 845},
+ dictWord{8, 0, 160},
+ dictWord{9, 0, 318},
+ dictWord{6, 10, 1623},
+ dictWord{134, 10, 1681},
+ dictWord{134, 0, 1447},
+ dictWord{134, 0, 1255},
+ dictWord{138, 0, 735},
+ dictWord{8, 0, 76},
+ dictWord{132, 11, 168},
+ dictWord{
+ 6,
+ 10,
+ 1748,
+ },
+ dictWord{8, 10, 715},
+ dictWord{9, 10, 802},
+ dictWord{10, 10, 46},
+ dictWord{10, 10, 819},
+ dictWord{13, 10, 308},
+ dictWord{14, 10, 351},
+ dictWord{14, 10, 363},
+ dictWord{146, 10, 67},
+ dictWord{135, 11, 91},
+ dictWord{6, 0, 474},
+ dictWord{4, 10, 63},
+ dictWord{133, 10, 347},
+ dictWord{133, 10, 749},
+ dictWord{138, 0, 841},
+ dictWord{133, 10, 366},
+ dictWord{6, 0, 836},
+ dictWord{132, 11, 225},
+ dictWord{135, 0, 1622},
+ dictWord{135, 10, 89},
+ dictWord{
+ 140,
+ 0,
+ 735,
+ },
+ dictWord{134, 0, 1601},
+ dictWord{138, 11, 145},
+ dictWord{6, 0, 1390},
+ dictWord{137, 0, 804},
+ dictWord{142, 0, 394},
+ dictWord{6, 11, 15},
+ dictWord{
+ 7,
+ 11,
+ 70,
+ },
+ dictWord{10, 11, 240},
+ dictWord{147, 11, 93},
+ dictWord{6, 0, 96},
+ dictWord{135, 0, 1426},
+ dictWord{4, 0, 651},
+ dictWord{133, 0, 289},
+ dictWord{
+ 7,
+ 11,
+ 956,
+ },
+ dictWord{7, 10, 977},
+ dictWord{7, 11, 1157},
+ dictWord{7, 11, 1506},
+ dictWord{7, 11, 1606},
+ dictWord{7, 11, 1615},
+ dictWord{7, 11, 1619},
+ dictWord{
+ 7,
+ 11,
+ 1736,
+ },
+ dictWord{7, 11, 1775},
+ dictWord{8, 11, 590},
+ dictWord{9, 11, 324},
+ dictWord{9, 11, 736},
+ dictWord{9, 11, 774},
+ dictWord{9, 11, 776},
+ dictWord{
+ 9,
+ 11,
+ 784,
+ },
+ dictWord{10, 11, 567},
+ dictWord{10, 11, 708},
+ dictWord{11, 11, 518},
+ dictWord{11, 11, 613},
+ dictWord{11, 11, 695},
+ dictWord{11, 11, 716},
+ dictWord{11, 11, 739},
+ dictWord{11, 11, 770},
+ dictWord{11, 11, 771},
+ dictWord{11, 11, 848},
+ dictWord{11, 11, 857},
+ dictWord{11, 11, 931},
+ dictWord{
+ 11,
+ 11,
+ 947,
+ },
+ dictWord{12, 11, 326},
+ dictWord{12, 11, 387},
+ dictWord{12, 11, 484},
+ dictWord{12, 11, 528},
+ dictWord{12, 11, 552},
+ dictWord{12, 11, 613},
+ dictWord{
+ 13,
+ 11,
+ 189,
+ },
+ dictWord{13, 11, 256},
+ dictWord{13, 11, 340},
+ dictWord{13, 11, 432},
+ dictWord{13, 11, 436},
+ dictWord{13, 11, 440},
+ dictWord{13, 11, 454},
+ dictWord{14, 11, 174},
+ dictWord{14, 11, 220},
+ dictWord{14, 11, 284},
+ dictWord{14, 11, 390},
+ dictWord{145, 11, 121},
+ dictWord{7, 0, 688},
+ dictWord{8, 0, 35},
+ dictWord{9, 0, 511},
+ dictWord{10, 0, 767},
+ dictWord{147, 0, 118},
+ dictWord{134, 0, 667},
+ dictWord{4, 0, 513},
+ dictWord{5, 10, 824},
+ dictWord{133, 10, 941},
+ dictWord{7, 10, 440},
+ dictWord{8, 10, 230},
+ dictWord{139, 10, 106},
+ dictWord{134, 0, 2034},
+ dictWord{135, 11, 1399},
+ dictWord{143, 11, 66},
+ dictWord{
+ 135,
+ 11,
+ 1529,
+ },
+ dictWord{4, 11, 145},
+ dictWord{6, 11, 176},
+ dictWord{7, 11, 395},
+ dictWord{9, 11, 562},
+ dictWord{144, 11, 28},
+ dictWord{132, 11, 501},
+ dictWord{132, 0, 704},
+ dictWord{134, 0, 1524},
+ dictWord{7, 0, 1078},
+ dictWord{134, 11, 464},
+ dictWord{6, 11, 509},
+ dictWord{10, 11, 82},
+ dictWord{20, 11, 91},
+ dictWord{151, 11, 13},
+ dictWord{4, 0, 720},
+ dictWord{133, 0, 306},
+ dictWord{133, 0, 431},
+ dictWord{7, 0, 1196},
+ dictWord{4, 10, 914},
+ dictWord{5, 10, 800},
+ dictWord{133, 10, 852},
+ dictWord{135, 11, 1189},
+ dictWord{10, 0, 54},
+ dictWord{141, 10, 115},
+ dictWord{7, 10, 564},
+ dictWord{142, 10, 168},
+ dictWord{
+ 5,
+ 0,
+ 464,
+ },
+ dictWord{6, 0, 236},
+ dictWord{7, 0, 696},
+ dictWord{7, 0, 914},
+ dictWord{7, 0, 1108},
+ dictWord{7, 0, 1448},
+ dictWord{9, 0, 15},
+ dictWord{9, 0, 564},
+ dictWord{
+ 10,
+ 0,
+ 14,
+ },
+ dictWord{12, 0, 565},
+ dictWord{13, 0, 449},
+ dictWord{14, 0, 53},
+ dictWord{15, 0, 13},
+ dictWord{16, 0, 64},
+ dictWord{17, 0, 41},
+ dictWord{4, 10, 918},
+ dictWord{133, 10, 876},
+ dictWord{6, 0, 1418},
+ dictWord{134, 10, 1764},
+ dictWord{4, 10, 92},
+ dictWord{133, 10, 274},
+ dictWord{134, 0, 907},
+ dictWord{
+ 4,
+ 11,
+ 114,
+ },
+ dictWord{8, 10, 501},
+ dictWord{9, 11, 492},
+ dictWord{13, 11, 462},
+ dictWord{142, 11, 215},
+ dictWord{4, 11, 77},
+ dictWord{5, 11, 361},
+ dictWord{
+ 6,
+ 11,
+ 139,
+ },
+ dictWord{6, 11, 401},
+ dictWord{6, 11, 404},
+ dictWord{7, 11, 413},
+ dictWord{7, 11, 715},
+ dictWord{7, 11, 1716},
+ dictWord{11, 11, 279},
+ dictWord{
+ 12,
+ 11,
+ 179,
+ },
+ dictWord{12, 11, 258},
+ dictWord{13, 11, 244},
+ dictWord{142, 11, 358},
+ dictWord{6, 0, 1767},
+ dictWord{12, 0, 194},
+ dictWord{145, 0, 107},
+ dictWord{
+ 134,
+ 11,
+ 1717,
+ },
+ dictWord{5, 10, 743},
+ dictWord{142, 11, 329},
+ dictWord{4, 10, 49},
+ dictWord{7, 10, 280},
+ dictWord{135, 10, 1633},
+ dictWord{5, 0, 840},
+ dictWord{7, 11, 1061},
+ dictWord{8, 11, 82},
+ dictWord{11, 11, 250},
+ dictWord{12, 11, 420},
+ dictWord{141, 11, 184},
+ dictWord{135, 11, 724},
+ dictWord{
+ 134,
+ 0,
+ 900,
+ },
+ dictWord{136, 10, 47},
+ dictWord{134, 0, 1436},
+ dictWord{144, 11, 0},
+ dictWord{6, 0, 675},
+ dictWord{7, 0, 1008},
+ dictWord{7, 0, 1560},
+ dictWord{
+ 9,
+ 0,
+ 642,
+ },
+ dictWord{11, 0, 236},
+ dictWord{14, 0, 193},
+ dictWord{5, 10, 272},
+ dictWord{5, 10, 908},
+ dictWord{5, 10, 942},
+ dictWord{8, 10, 197},
+ dictWord{9, 10, 47},
+ dictWord{11, 10, 538},
+ dictWord{139, 10, 742},
+ dictWord{4, 0, 68},
+ dictWord{5, 0, 628},
+ dictWord{5, 0, 634},
+ dictWord{6, 0, 386},
+ dictWord{7, 0, 794},
+ dictWord{
+ 8,
+ 0,
+ 273,
+ },
+ dictWord{9, 0, 563},
+ dictWord{10, 0, 105},
+ dictWord{10, 0, 171},
+ dictWord{11, 0, 94},
+ dictWord{139, 0, 354},
+ dictWord{135, 10, 1911},
+ dictWord{
+ 137,
+ 10,
+ 891,
+ },
+ dictWord{4, 0, 95},
+ dictWord{6, 0, 1297},
+ dictWord{6, 0, 1604},
+ dictWord{7, 0, 416},
+ dictWord{139, 0, 830},
+ dictWord{6, 11, 513},
+ dictWord{
+ 135,
+ 11,
+ 1052,
+ },
+ dictWord{7, 0, 731},
+ dictWord{13, 0, 20},
+ dictWord{143, 0, 11},
+ dictWord{137, 11, 899},
+ dictWord{10, 0, 850},
+ dictWord{140, 0, 697},
+ dictWord{
+ 4,
+ 0,
+ 662,
+ },
+ dictWord{7, 11, 1417},
+ dictWord{12, 11, 382},
+ dictWord{17, 11, 48},
+ dictWord{152, 11, 12},
+ dictWord{133, 0, 736},
+ dictWord{132, 0, 861},
+ dictWord{
+ 4,
+ 10,
+ 407,
+ },
+ dictWord{132, 10, 560},
+ dictWord{141, 10, 490},
+ dictWord{6, 11, 545},
+ dictWord{7, 11, 565},
+ dictWord{7, 11, 1669},
+ dictWord{10, 11, 114},
+ dictWord{11, 11, 642},
+ dictWord{140, 11, 618},
+ dictWord{6, 0, 871},
+ dictWord{134, 0, 1000},
+ dictWord{5, 0, 864},
+ dictWord{10, 0, 648},
+ dictWord{11, 0, 671},
+ dictWord{15, 0, 46},
+ dictWord{133, 11, 5},
+ dictWord{133, 0, 928},
+ dictWord{11, 0, 90},
+ dictWord{13, 0, 7},
+ dictWord{4, 10, 475},
+ dictWord{11, 10, 35},
+ dictWord{
+ 13,
+ 10,
+ 71,
+ },
+ dictWord{13, 10, 177},
+ dictWord{142, 10, 422},
+ dictWord{136, 0, 332},
+ dictWord{135, 11, 192},
+ dictWord{134, 0, 1055},
+ dictWord{136, 11, 763},
+ dictWord{11, 0, 986},
+ dictWord{140, 0, 682},
+ dictWord{7, 0, 76},
+ dictWord{8, 0, 44},
+ dictWord{9, 0, 884},
+ dictWord{10, 0, 580},
+ dictWord{11, 0, 399},
+ dictWord{
+ 11,
+ 0,
+ 894,
+ },
+ dictWord{143, 0, 122},
+ dictWord{135, 11, 1237},
+ dictWord{135, 10, 636},
+ dictWord{11, 0, 300},
+ dictWord{6, 10, 222},
+ dictWord{7, 10, 1620},
+ dictWord{
+ 8,
+ 10,
+ 409,
+ },
+ dictWord{137, 10, 693},
+ dictWord{4, 11, 87},
+ dictWord{5, 11, 250},
+ dictWord{10, 11, 601},
+ dictWord{13, 11, 298},
+ dictWord{13, 11, 353},
+ dictWord{141, 11, 376},
+ dictWord{5, 0, 518},
+ dictWord{10, 0, 340},
+ dictWord{11, 0, 175},
+ dictWord{149, 0, 16},
+ dictWord{140, 0, 771},
+ dictWord{6, 0, 1108},
+ dictWord{137, 0, 831},
+ dictWord{132, 0, 836},
+ dictWord{135, 0, 1852},
+ dictWord{4, 0, 957},
+ dictWord{6, 0, 1804},
+ dictWord{8, 0, 842},
+ dictWord{8, 0, 843},
+ dictWord{
+ 8,
+ 0,
+ 851,
+ },
+ dictWord{8, 0, 855},
+ dictWord{140, 0, 767},
+ dictWord{135, 11, 814},
+ dictWord{4, 11, 57},
+ dictWord{7, 11, 1195},
+ dictWord{7, 11, 1438},
+ dictWord{
+ 7,
+ 11,
+ 1548,
+ },
+ dictWord{7, 11, 1835},
+ dictWord{7, 11, 1904},
+ dictWord{9, 11, 757},
+ dictWord{10, 11, 604},
+ dictWord{139, 11, 519},
+ dictWord{133, 10, 882},
+ dictWord{138, 0, 246},
+ dictWord{4, 0, 934},
+ dictWord{5, 0, 202},
+ dictWord{8, 0, 610},
+ dictWord{7, 11, 1897},
+ dictWord{12, 11, 290},
+ dictWord{13, 11, 80},
+ dictWord{13, 11, 437},
+ dictWord{145, 11, 74},
+ dictWord{8, 0, 96},
+ dictWord{9, 0, 36},
+ dictWord{10, 0, 607},
+ dictWord{10, 0, 804},
+ dictWord{10, 0, 832},
+ dictWord{
+ 11,
+ 0,
+ 423,
+ },
+ dictWord{11, 0, 442},
+ dictWord{12, 0, 309},
+ dictWord{14, 0, 199},
+ dictWord{15, 0, 90},
+ dictWord{145, 0, 110},
+ dictWord{132, 10, 426},
+ dictWord{
+ 7,
+ 0,
+ 654,
+ },
+ dictWord{8, 0, 240},
+ dictWord{6, 10, 58},
+ dictWord{7, 10, 745},
+ dictWord{7, 10, 1969},
+ dictWord{8, 10, 675},
+ dictWord{9, 10, 479},
+ dictWord{9, 10, 731},
+ dictWord{10, 10, 330},
+ dictWord{10, 10, 593},
+ dictWord{10, 10, 817},
+ dictWord{11, 10, 32},
+ dictWord{11, 10, 133},
+ dictWord{11, 10, 221},
+ dictWord{
+ 145,
+ 10,
+ 68,
+ },
+ dictWord{9, 0, 13},
+ dictWord{9, 0, 398},
+ dictWord{9, 0, 727},
+ dictWord{10, 0, 75},
+ dictWord{10, 0, 184},
+ dictWord{10, 0, 230},
+ dictWord{10, 0, 564},
+ dictWord{
+ 10,
+ 0,
+ 569,
+ },
+ dictWord{11, 0, 973},
+ dictWord{12, 0, 70},
+ dictWord{12, 0, 189},
+ dictWord{13, 0, 57},
+ dictWord{141, 0, 257},
+ dictWord{4, 11, 209},
+ dictWord{
+ 135,
+ 11,
+ 902,
+ },
+ dictWord{7, 0, 391},
+ dictWord{137, 10, 538},
+ dictWord{134, 0, 403},
+ dictWord{6, 11, 303},
+ dictWord{7, 11, 335},
+ dictWord{7, 11, 1437},
+ dictWord{
+ 7,
+ 11,
+ 1668,
+ },
+ dictWord{8, 11, 553},
+ dictWord{8, 11, 652},
+ dictWord{8, 11, 656},
+ dictWord{9, 11, 558},
+ dictWord{11, 11, 743},
+ dictWord{149, 11, 18},
+ dictWord{
+ 132,
+ 11,
+ 559,
+ },
+ dictWord{11, 0, 75},
+ dictWord{142, 0, 267},
+ dictWord{6, 0, 815},
+ dictWord{141, 11, 2},
+ dictWord{141, 0, 366},
+ dictWord{137, 0, 631},
+ dictWord{
+ 133,
+ 11,
+ 1017,
+ },
+ dictWord{5, 0, 345},
+ dictWord{135, 0, 1016},
+ dictWord{133, 11, 709},
+ dictWord{134, 11, 1745},
+ dictWord{133, 10, 566},
+ dictWord{7, 0, 952},
+ dictWord{6, 10, 48},
+ dictWord{9, 10, 139},
+ dictWord{10, 10, 399},
+ dictWord{11, 10, 469},
+ dictWord{12, 10, 634},
+ dictWord{141, 10, 223},
+ dictWord{
+ 133,
+ 0,
+ 673,
+ },
+ dictWord{9, 0, 850},
+ dictWord{7, 11, 8},
+ dictWord{136, 11, 206},
+ dictWord{6, 0, 662},
+ dictWord{149, 0, 35},
+ dictWord{4, 0, 287},
+ dictWord{133, 0, 1018},
+ dictWord{6, 10, 114},
+ dictWord{7, 10, 1224},
+ dictWord{7, 10, 1556},
+ dictWord{136, 10, 3},
+ dictWord{8, 10, 576},
+ dictWord{137, 10, 267},
+ dictWord{4, 0, 884},
+ dictWord{5, 0, 34},
+ dictWord{10, 0, 724},
+ dictWord{12, 0, 444},
+ dictWord{13, 0, 354},
+ dictWord{18, 0, 32},
+ dictWord{23, 0, 24},
+ dictWord{23, 0, 31},
+ dictWord{
+ 152,
+ 0,
+ 5,
+ },
+ dictWord{133, 10, 933},
+ dictWord{132, 11, 776},
+ dictWord{138, 0, 151},
+ dictWord{136, 0, 427},
+ dictWord{134, 0, 382},
+ dictWord{132, 0, 329},
+ dictWord{
+ 9,
+ 0,
+ 846,
+ },
+ dictWord{10, 0, 827},
+ dictWord{138, 11, 33},
+ dictWord{9, 0, 279},
+ dictWord{10, 0, 407},
+ dictWord{14, 0, 84},
+ dictWord{22, 0, 18},
+ dictWord{
+ 135,
+ 11,
+ 1297,
+ },
+ dictWord{136, 11, 406},
+ dictWord{132, 0, 906},
+ dictWord{136, 0, 366},
+ dictWord{134, 0, 843},
+ dictWord{134, 0, 1443},
+ dictWord{135, 0, 1372},
+ dictWord{138, 0, 992},
+ dictWord{4, 0, 123},
+ dictWord{5, 0, 605},
+ dictWord{7, 0, 1509},
+ dictWord{136, 0, 36},
+ dictWord{132, 0, 649},
+ dictWord{8, 11, 175},
+ dictWord{10, 11, 168},
+ dictWord{138, 11, 573},
+ dictWord{133, 0, 767},
+ dictWord{134, 0, 1018},
+ dictWord{135, 11, 1305},
+ dictWord{12, 10, 30},
+ dictWord{
+ 13,
+ 10,
+ 148,
+ },
+ dictWord{14, 10, 87},
+ dictWord{14, 10, 182},
+ dictWord{16, 10, 42},
+ dictWord{148, 10, 70},
+ dictWord{134, 11, 607},
+ dictWord{4, 0, 273},
+ dictWord{
+ 5,
+ 0,
+ 658,
+ },
+ dictWord{133, 0, 995},
+ dictWord{6, 0, 72},
+ dictWord{139, 11, 174},
+ dictWord{10, 0, 483},
+ dictWord{12, 0, 368},
+ dictWord{7, 10, 56},
+ dictWord{
+ 7,
+ 10,
+ 1989,
+ },
+ dictWord{8, 10, 337},
+ dictWord{8, 10, 738},
+ dictWord{9, 10, 600},
+ dictWord{13, 10, 447},
+ dictWord{142, 10, 92},
+ dictWord{5, 11, 784},
+ dictWord{
+ 138,
+ 10,
+ 666,
+ },
+ dictWord{135, 0, 1345},
+ dictWord{139, 11, 882},
+ dictWord{134, 0, 1293},
+ dictWord{133, 0, 589},
+ dictWord{134, 0, 1988},
+ dictWord{5, 0, 117},
+ dictWord{6, 0, 514},
+ dictWord{6, 0, 541},
+ dictWord{7, 0, 1164},
+ dictWord{7, 0, 1436},
+ dictWord{8, 0, 220},
+ dictWord{8, 0, 648},
+ dictWord{10, 0, 688},
+ dictWord{
+ 139,
+ 0,
+ 560,
+ },
+ dictWord{136, 0, 379},
+ dictWord{5, 0, 686},
+ dictWord{7, 10, 866},
+ dictWord{135, 10, 1163},
+ dictWord{132, 10, 328},
+ dictWord{9, 11, 14},
+ dictWord{
+ 9,
+ 11,
+ 441,
+ },
+ dictWord{10, 11, 306},
+ dictWord{139, 11, 9},
+ dictWord{4, 10, 101},
+ dictWord{135, 10, 1171},
+ dictWord{5, 10, 833},
+ dictWord{136, 10, 744},
+ dictWord{5, 11, 161},
+ dictWord{7, 11, 839},
+ dictWord{135, 11, 887},
+ dictWord{7, 0, 196},
+ dictWord{10, 0, 765},
+ dictWord{11, 0, 347},
+ dictWord{11, 0, 552},
+ dictWord{11, 0, 790},
+ dictWord{12, 0, 263},
+ dictWord{13, 0, 246},
+ dictWord{13, 0, 270},
+ dictWord{13, 0, 395},
+ dictWord{14, 0, 176},
+ dictWord{14, 0, 190},
+ dictWord{
+ 14,
+ 0,
+ 398,
+ },
+ dictWord{14, 0, 412},
+ dictWord{15, 0, 32},
+ dictWord{15, 0, 63},
+ dictWord{16, 0, 88},
+ dictWord{147, 0, 105},
+ dictWord{6, 10, 9},
+ dictWord{6, 10, 397},
+ dictWord{7, 10, 53},
+ dictWord{7, 10, 1742},
+ dictWord{10, 10, 632},
+ dictWord{11, 10, 828},
+ dictWord{140, 10, 146},
+ dictWord{5, 0, 381},
+ dictWord{135, 0, 1792},
+ dictWord{134, 0, 1452},
+ dictWord{135, 11, 429},
+ dictWord{8, 0, 367},
+ dictWord{10, 0, 760},
+ dictWord{14, 0, 79},
+ dictWord{20, 0, 17},
+ dictWord{152, 0, 0},
+ dictWord{7, 0, 616},
+ dictWord{138, 0, 413},
+ dictWord{11, 10, 417},
+ dictWord{12, 10, 223},
+ dictWord{140, 10, 265},
+ dictWord{7, 11, 1611},
+ dictWord{13, 11, 14},
+ dictWord{15, 11, 44},
+ dictWord{19, 11, 13},
+ dictWord{148, 11, 76},
+ dictWord{135, 0, 1229},
+ dictWord{6, 0, 120},
+ dictWord{7, 0, 1188},
+ dictWord{7, 0, 1710},
+ dictWord{8, 0, 286},
+ dictWord{9, 0, 667},
+ dictWord{11, 0, 592},
+ dictWord{139, 0, 730},
+ dictWord{135, 11, 1814},
+ dictWord{135, 0, 1146},
+ dictWord{4, 10, 186},
+ dictWord{5, 10, 157},
+ dictWord{8, 10, 168},
+ dictWord{138, 10, 6},
+ dictWord{4, 0, 352},
+ dictWord{135, 0, 687},
+ dictWord{4, 0, 192},
+ dictWord{5, 0, 49},
+ dictWord{
+ 6,
+ 0,
+ 200,
+ },
+ dictWord{6, 0, 293},
+ dictWord{6, 0, 1696},
+ dictWord{135, 0, 1151},
+ dictWord{133, 10, 875},
+ dictWord{5, 10, 773},
+ dictWord{5, 10, 991},
+ dictWord{
+ 6,
+ 10,
+ 1635,
+ },
+ dictWord{134, 10, 1788},
+ dictWord{7, 10, 111},
+ dictWord{136, 10, 581},
+ dictWord{6, 0, 935},
+ dictWord{134, 0, 1151},
+ dictWord{134, 0, 1050},
+ dictWord{132, 0, 650},
+ dictWord{132, 0, 147},
+ dictWord{11, 0, 194},
+ dictWord{12, 0, 62},
+ dictWord{12, 0, 88},
+ dictWord{11, 11, 194},
+ dictWord{12, 11, 62},
+ dictWord{140, 11, 88},
+ dictWord{6, 0, 339},
+ dictWord{135, 0, 923},
+ dictWord{134, 10, 1747},
+ dictWord{7, 11, 643},
+ dictWord{136, 11, 236},
+ dictWord{
+ 133,
+ 0,
+ 934,
+ },
+ dictWord{7, 10, 1364},
+ dictWord{7, 10, 1907},
+ dictWord{141, 10, 158},
+ dictWord{132, 10, 659},
+ dictWord{4, 10, 404},
+ dictWord{135, 10, 675},
+ dictWord{7, 11, 581},
+ dictWord{9, 11, 644},
+ dictWord{137, 11, 699},
+ dictWord{13, 0, 211},
+ dictWord{14, 0, 133},
+ dictWord{14, 0, 204},
+ dictWord{15, 0, 64},
+ dictWord{
+ 15,
+ 0,
+ 69,
+ },
+ dictWord{15, 0, 114},
+ dictWord{16, 0, 10},
+ dictWord{19, 0, 23},
+ dictWord{19, 0, 35},
+ dictWord{19, 0, 39},
+ dictWord{19, 0, 51},
+ dictWord{19, 0, 71},
+ dictWord{19, 0, 75},
+ dictWord{152, 0, 15},
+ dictWord{133, 10, 391},
+ dictWord{5, 11, 54},
+ dictWord{135, 11, 1513},
+ dictWord{7, 0, 222},
+ dictWord{8, 0, 341},
+ dictWord{
+ 5,
+ 10,
+ 540,
+ },
+ dictWord{134, 10, 1697},
+ dictWord{134, 10, 78},
+ dictWord{132, 11, 744},
+ dictWord{136, 0, 293},
+ dictWord{137, 11, 701},
+ dictWord{
+ 7,
+ 11,
+ 930,
+ },
+ dictWord{10, 11, 402},
+ dictWord{10, 11, 476},
+ dictWord{13, 11, 452},
+ dictWord{18, 11, 55},
+ dictWord{147, 11, 104},
+ dictWord{132, 0, 637},
+ dictWord{133, 10, 460},
+ dictWord{8, 11, 50},
+ dictWord{137, 11, 624},
+ dictWord{132, 11, 572},
+ dictWord{134, 0, 1159},
+ dictWord{4, 10, 199},
+ dictWord{
+ 139,
+ 10,
+ 34,
+ },
+ dictWord{134, 0, 847},
+ dictWord{134, 10, 388},
+ dictWord{6, 11, 43},
+ dictWord{7, 11, 38},
+ dictWord{8, 11, 248},
+ dictWord{9, 11, 504},
+ dictWord{
+ 138,
+ 11,
+ 513,
+ },
+ dictWord{9, 0, 683},
+ dictWord{4, 10, 511},
+ dictWord{6, 10, 608},
+ dictWord{9, 10, 333},
+ dictWord{10, 10, 602},
+ dictWord{11, 10, 441},
+ dictWord{
+ 11,
+ 10,
+ 723,
+ },
+ dictWord{11, 10, 976},
+ dictWord{140, 10, 357},
+ dictWord{9, 0, 867},
+ dictWord{138, 0, 837},
+ dictWord{6, 0, 944},
+ dictWord{135, 11, 326},
+ dictWord{
+ 135,
+ 0,
+ 1809,
+ },
+ dictWord{5, 10, 938},
+ dictWord{7, 11, 783},
+ dictWord{136, 10, 707},
+ dictWord{133, 11, 766},
+ dictWord{133, 11, 363},
+ dictWord{6, 0, 170},
+ dictWord{7, 0, 1080},
+ dictWord{8, 0, 395},
+ dictWord{8, 0, 487},
+ dictWord{141, 0, 147},
+ dictWord{6, 11, 258},
+ dictWord{140, 11, 409},
+ dictWord{4, 0, 535},
+ dictWord{
+ 8,
+ 0,
+ 618,
+ },
+ dictWord{5, 11, 249},
+ dictWord{148, 11, 82},
+ dictWord{6, 0, 1379},
+ dictWord{149, 11, 15},
+ dictWord{135, 0, 1625},
+ dictWord{150, 0, 23},
+ dictWord{
+ 5,
+ 11,
+ 393,
+ },
+ dictWord{6, 11, 378},
+ dictWord{7, 11, 1981},
+ dictWord{9, 11, 32},
+ dictWord{9, 11, 591},
+ dictWord{10, 11, 685},
+ dictWord{10, 11, 741},
+ dictWord{
+ 142,
+ 11,
+ 382,
+ },
+ dictWord{133, 11, 788},
+ dictWord{7, 11, 1968},
+ dictWord{10, 11, 19},
+ dictWord{139, 11, 911},
+ dictWord{7, 11, 1401},
+ dictWord{
+ 135,
+ 11,
+ 1476,
+ },
+ dictWord{4, 11, 61},
+ dictWord{5, 11, 58},
+ dictWord{5, 11, 171},
+ dictWord{5, 11, 635},
+ dictWord{5, 11, 683},
+ dictWord{5, 11, 700},
+ dictWord{6, 11, 291},
+ dictWord{6, 11, 566},
+ dictWord{7, 11, 1650},
+ dictWord{11, 11, 523},
+ dictWord{12, 11, 273},
+ dictWord{12, 11, 303},
+ dictWord{15, 11, 39},
+ dictWord{
+ 143,
+ 11,
+ 111,
+ },
+ dictWord{6, 10, 469},
+ dictWord{7, 10, 1709},
+ dictWord{138, 10, 515},
+ dictWord{4, 0, 778},
+ dictWord{134, 11, 589},
+ dictWord{132, 0, 46},
+ dictWord{
+ 5,
+ 0,
+ 811,
+ },
+ dictWord{6, 0, 1679},
+ dictWord{6, 0, 1714},
+ dictWord{135, 0, 2032},
+ dictWord{7, 0, 1458},
+ dictWord{9, 0, 407},
+ dictWord{11, 0, 15},
+ dictWord{12, 0, 651},
+ dictWord{149, 0, 37},
+ dictWord{7, 0, 938},
+ dictWord{132, 10, 500},
+ dictWord{6, 0, 34},
+ dictWord{7, 0, 69},
+ dictWord{7, 0, 1089},
+ dictWord{7, 0, 1281},
+ dictWord{
+ 8,
+ 0,
+ 708,
+ },
+ dictWord{8, 0, 721},
+ dictWord{9, 0, 363},
+ dictWord{148, 0, 98},
+ dictWord{10, 11, 231},
+ dictWord{147, 11, 124},
+ dictWord{7, 11, 726},
+ dictWord{
+ 152,
+ 11,
+ 9,
+ },
+ dictWord{5, 10, 68},
+ dictWord{134, 10, 383},
+ dictWord{136, 11, 583},
+ dictWord{4, 11, 917},
+ dictWord{133, 11, 1005},
+ dictWord{11, 10, 216},
+ dictWord{139, 10, 340},
+ dictWord{135, 11, 1675},
+ dictWord{8, 0, 441},
+ dictWord{10, 0, 314},
+ dictWord{143, 0, 3},
+ dictWord{132, 11, 919},
+ dictWord{4, 10, 337},
+ dictWord{6, 10, 353},
+ dictWord{7, 10, 1934},
+ dictWord{8, 10, 488},
+ dictWord{137, 10, 429},
+ dictWord{7, 0, 889},
+ dictWord{7, 10, 1795},
+ dictWord{8, 10, 259},
+ dictWord{9, 10, 135},
+ dictWord{9, 10, 177},
+ dictWord{9, 10, 860},
+ dictWord{10, 10, 825},
+ dictWord{11, 10, 115},
+ dictWord{11, 10, 370},
+ dictWord{11, 10, 405},
+ dictWord{11, 10, 604},
+ dictWord{12, 10, 10},
+ dictWord{12, 10, 667},
+ dictWord{12, 10, 669},
+ dictWord{13, 10, 76},
+ dictWord{14, 10, 310},
+ dictWord{
+ 15,
+ 10,
+ 76,
+ },
+ dictWord{15, 10, 147},
+ dictWord{148, 10, 23},
+ dictWord{4, 10, 15},
+ dictWord{4, 11, 255},
+ dictWord{5, 10, 22},
+ dictWord{5, 11, 302},
+ dictWord{6, 11, 132},
+ dictWord{6, 10, 244},
+ dictWord{7, 10, 40},
+ dictWord{7, 11, 128},
+ dictWord{7, 10, 200},
+ dictWord{7, 11, 283},
+ dictWord{7, 10, 906},
+ dictWord{7, 10, 1199},
+ dictWord{
+ 7,
+ 11,
+ 1299,
+ },
+ dictWord{9, 10, 616},
+ dictWord{10, 11, 52},
+ dictWord{10, 11, 514},
+ dictWord{10, 10, 716},
+ dictWord{11, 10, 635},
+ dictWord{11, 10, 801},
+ dictWord{11, 11, 925},
+ dictWord{12, 10, 458},
+ dictWord{13, 11, 92},
+ dictWord{142, 11, 309},
+ dictWord{132, 0, 462},
+ dictWord{137, 11, 173},
+ dictWord{
+ 135,
+ 10,
+ 1735,
+ },
+ dictWord{8, 0, 525},
+ dictWord{5, 10, 598},
+ dictWord{7, 10, 791},
+ dictWord{8, 10, 108},
+ dictWord{137, 10, 123},
+ dictWord{5, 0, 73},
+ dictWord{6, 0, 23},
+ dictWord{134, 0, 338},
+ dictWord{132, 0, 676},
+ dictWord{132, 10, 683},
+ dictWord{7, 0, 725},
+ dictWord{8, 0, 498},
+ dictWord{139, 0, 268},
+ dictWord{12, 0, 21},
+ dictWord{151, 0, 7},
+ dictWord{135, 0, 773},
+ dictWord{4, 10, 155},
+ dictWord{135, 10, 1689},
+ dictWord{4, 0, 164},
+ dictWord{5, 0, 730},
+ dictWord{5, 10, 151},
+ dictWord{
+ 5,
+ 10,
+ 741,
+ },
+ dictWord{6, 11, 210},
+ dictWord{7, 10, 498},
+ dictWord{7, 10, 870},
+ dictWord{7, 10, 1542},
+ dictWord{12, 10, 213},
+ dictWord{14, 10, 36},
+ dictWord{
+ 14,
+ 10,
+ 391,
+ },
+ dictWord{17, 10, 111},
+ dictWord{18, 10, 6},
+ dictWord{18, 10, 46},
+ dictWord{18, 10, 151},
+ dictWord{19, 10, 36},
+ dictWord{20, 10, 32},
+ dictWord{
+ 20,
+ 10,
+ 56,
+ },
+ dictWord{20, 10, 69},
+ dictWord{20, 10, 102},
+ dictWord{21, 10, 4},
+ dictWord{22, 10, 8},
+ dictWord{22, 10, 10},
+ dictWord{22, 10, 14},
+ dictWord{
+ 150,
+ 10,
+ 31,
+ },
+ dictWord{4, 10, 624},
+ dictWord{135, 10, 1752},
+ dictWord{4, 0, 583},
+ dictWord{9, 0, 936},
+ dictWord{15, 0, 214},
+ dictWord{18, 0, 199},
+ dictWord{24, 0, 26},
+ dictWord{134, 11, 588},
+ dictWord{7, 0, 1462},
+ dictWord{11, 0, 659},
+ dictWord{4, 11, 284},
+ dictWord{134, 11, 223},
+ dictWord{133, 0, 220},
+ dictWord{
+ 139,
+ 0,
+ 803,
+ },
+ dictWord{132, 0, 544},
+ dictWord{4, 10, 492},
+ dictWord{133, 10, 451},
+ dictWord{16, 0, 98},
+ dictWord{148, 0, 119},
+ dictWord{4, 11, 218},
+ dictWord{
+ 7,
+ 11,
+ 526,
+ },
+ dictWord{143, 11, 137},
+ dictWord{135, 10, 835},
+ dictWord{4, 11, 270},
+ dictWord{5, 11, 192},
+ dictWord{6, 11, 332},
+ dictWord{7, 11, 1322},
+ dictWord{
+ 13,
+ 11,
+ 9,
+ },
+ dictWord{13, 10, 70},
+ dictWord{14, 11, 104},
+ dictWord{142, 11, 311},
+ dictWord{132, 10, 539},
+ dictWord{140, 11, 661},
+ dictWord{5, 0, 176},
+ dictWord{
+ 6,
+ 0,
+ 437,
+ },
+ dictWord{6, 0, 564},
+ dictWord{11, 0, 181},
+ dictWord{141, 0, 183},
+ dictWord{135, 0, 1192},
+ dictWord{6, 10, 113},
+ dictWord{135, 10, 436},
+ dictWord{136, 10, 718},
+ dictWord{135, 10, 520},
+ dictWord{135, 0, 1878},
+ dictWord{140, 11, 196},
+ dictWord{7, 11, 379},
+ dictWord{8, 11, 481},
+ dictWord{
+ 137,
+ 11,
+ 377,
+ },
+ dictWord{5, 11, 1003},
+ dictWord{6, 11, 149},
+ dictWord{137, 11, 746},
+ dictWord{8, 11, 262},
+ dictWord{9, 11, 627},
+ dictWord{10, 11, 18},
+ dictWord{
+ 11,
+ 11,
+ 214,
+ },
+ dictWord{11, 11, 404},
+ dictWord{11, 11, 457},
+ dictWord{11, 11, 780},
+ dictWord{11, 11, 849},
+ dictWord{11, 11, 913},
+ dictWord{13, 11, 330},
+ dictWord{13, 11, 401},
+ dictWord{142, 11, 200},
+ dictWord{149, 0, 26},
+ dictWord{136, 11, 304},
+ dictWord{132, 11, 142},
+ dictWord{135, 0, 944},
+ dictWord{
+ 4,
+ 0,
+ 790,
+ },
+ dictWord{5, 0, 273},
+ dictWord{134, 0, 394},
+ dictWord{134, 0, 855},
+ dictWord{4, 0, 135},
+ dictWord{6, 0, 127},
+ dictWord{7, 0, 1185},
+ dictWord{7, 0, 1511},
+ dictWord{8, 0, 613},
+ dictWord{11, 0, 5},
+ dictWord{12, 0, 336},
+ dictWord{12, 0, 495},
+ dictWord{12, 0, 586},
+ dictWord{12, 0, 660},
+ dictWord{12, 0, 668},
+ dictWord{
+ 14,
+ 0,
+ 385,
+ },
+ dictWord{15, 0, 118},
+ dictWord{17, 0, 20},
+ dictWord{146, 0, 98},
+ dictWord{6, 0, 230},
+ dictWord{9, 0, 752},
+ dictWord{18, 0, 109},
+ dictWord{12, 10, 610},
+ dictWord{13, 10, 431},
+ dictWord{144, 10, 59},
+ dictWord{7, 0, 1954},
+ dictWord{135, 11, 925},
+ dictWord{4, 11, 471},
+ dictWord{5, 11, 51},
+ dictWord{6, 11, 602},
+ dictWord{8, 11, 484},
+ dictWord{10, 11, 195},
+ dictWord{140, 11, 159},
+ dictWord{132, 10, 307},
+ dictWord{136, 11, 688},
+ dictWord{132, 11, 697},
+ dictWord{
+ 7,
+ 11,
+ 812,
+ },
+ dictWord{7, 11, 1261},
+ dictWord{7, 11, 1360},
+ dictWord{9, 11, 632},
+ dictWord{140, 11, 352},
+ dictWord{5, 0, 162},
+ dictWord{8, 0, 68},
+ dictWord{
+ 133,
+ 10,
+ 964,
+ },
+ dictWord{4, 0, 654},
+ dictWord{136, 11, 212},
+ dictWord{4, 0, 156},
+ dictWord{7, 0, 998},
+ dictWord{7, 0, 1045},
+ dictWord{7, 0, 1860},
+ dictWord{9, 0, 48},
+ dictWord{9, 0, 692},
+ dictWord{11, 0, 419},
+ dictWord{139, 0, 602},
+ dictWord{133, 11, 221},
+ dictWord{4, 11, 373},
+ dictWord{5, 11, 283},
+ dictWord{6, 11, 480},
+ dictWord{135, 11, 609},
+ dictWord{142, 11, 216},
+ dictWord{132, 0, 240},
+ dictWord{6, 11, 192},
+ dictWord{9, 11, 793},
+ dictWord{145, 11, 55},
+ dictWord{
+ 4,
+ 10,
+ 75,
+ },
+ dictWord{5, 10, 180},
+ dictWord{6, 10, 500},
+ dictWord{7, 10, 58},
+ dictWord{7, 10, 710},
+ dictWord{138, 10, 645},
+ dictWord{4, 11, 132},
+ dictWord{5, 11, 69},
+ dictWord{5, 10, 649},
+ dictWord{135, 11, 1242},
+ dictWord{6, 10, 276},
+ dictWord{7, 10, 282},
+ dictWord{7, 10, 879},
+ dictWord{7, 10, 924},
+ dictWord{8, 10, 459},
+ dictWord{9, 10, 599},
+ dictWord{9, 10, 754},
+ dictWord{11, 10, 574},
+ dictWord{12, 10, 128},
+ dictWord{12, 10, 494},
+ dictWord{13, 10, 52},
+ dictWord{13, 10, 301},
+ dictWord{15, 10, 30},
+ dictWord{143, 10, 132},
+ dictWord{132, 10, 200},
+ dictWord{4, 11, 111},
+ dictWord{135, 11, 302},
+ dictWord{9, 0, 197},
+ dictWord{
+ 10,
+ 0,
+ 300,
+ },
+ dictWord{12, 0, 473},
+ dictWord{13, 0, 90},
+ dictWord{141, 0, 405},
+ dictWord{132, 11, 767},
+ dictWord{6, 11, 42},
+ dictWord{7, 11, 1416},
+ dictWord{
+ 7,
+ 11,
+ 1590,
+ },
+ dictWord{7, 11, 2005},
+ dictWord{8, 11, 131},
+ dictWord{8, 11, 466},
+ dictWord{9, 11, 672},
+ dictWord{13, 11, 252},
+ dictWord{148, 11, 103},
+ dictWord{
+ 8,
+ 0,
+ 958,
+ },
+ dictWord{8, 0, 999},
+ dictWord{10, 0, 963},
+ dictWord{138, 0, 1001},
+ dictWord{135, 10, 1621},
+ dictWord{135, 0, 858},
+ dictWord{4, 0, 606},
+ dictWord{
+ 137,
+ 11,
+ 444,
+ },
+ dictWord{6, 11, 44},
+ dictWord{136, 11, 368},
+ dictWord{139, 11, 172},
+ dictWord{4, 11, 570},
+ dictWord{133, 11, 120},
+ dictWord{139, 11, 624},
+ dictWord{7, 0, 1978},
+ dictWord{8, 0, 676},
+ dictWord{6, 10, 225},
+ dictWord{137, 10, 211},
+ dictWord{7, 0, 972},
+ dictWord{11, 0, 102},
+ dictWord{136, 10, 687},
+ dictWord{6, 11, 227},
+ dictWord{135, 11, 1589},
+ dictWord{8, 10, 58},
+ dictWord{9, 10, 724},
+ dictWord{11, 10, 809},
+ dictWord{13, 10, 113},
+ dictWord{
+ 145,
+ 10,
+ 72,
+ },
+ dictWord{4, 0, 361},
+ dictWord{133, 0, 315},
+ dictWord{132, 0, 461},
+ dictWord{6, 10, 345},
+ dictWord{135, 10, 1247},
+ dictWord{132, 0, 472},
+ dictWord{
+ 8,
+ 10,
+ 767,
+ },
+ dictWord{8, 10, 803},
+ dictWord{9, 10, 301},
+ dictWord{137, 10, 903},
+ dictWord{135, 11, 1333},
+ dictWord{135, 11, 477},
+ dictWord{7, 10, 1949},
+ dictWord{136, 10, 674},
+ dictWord{6, 0, 905},
+ dictWord{138, 0, 747},
+ dictWord{133, 0, 155},
+ dictWord{134, 10, 259},
+ dictWord{7, 0, 163},
+ dictWord{8, 0, 319},
+ dictWord{9, 0, 402},
+ dictWord{10, 0, 24},
+ dictWord{10, 0, 681},
+ dictWord{11, 0, 200},
+ dictWord{12, 0, 253},
+ dictWord{12, 0, 410},
+ dictWord{142, 0, 219},
+ dictWord{
+ 5,
+ 0,
+ 475,
+ },
+ dictWord{7, 0, 1780},
+ dictWord{9, 0, 230},
+ dictWord{11, 0, 297},
+ dictWord{11, 0, 558},
+ dictWord{14, 0, 322},
+ dictWord{19, 0, 76},
+ dictWord{6, 11, 1667},
+ dictWord{7, 11, 2036},
+ dictWord{138, 11, 600},
+ dictWord{136, 10, 254},
+ dictWord{6, 0, 848},
+ dictWord{135, 0, 1956},
+ dictWord{6, 11, 511},
+ dictWord{
+ 140,
+ 11,
+ 132,
+ },
+ dictWord{5, 11, 568},
+ dictWord{6, 11, 138},
+ dictWord{135, 11, 1293},
+ dictWord{6, 0, 631},
+ dictWord{137, 0, 838},
+ dictWord{149, 0, 36},
+ dictWord{
+ 4,
+ 11,
+ 565,
+ },
+ dictWord{8, 11, 23},
+ dictWord{136, 11, 827},
+ dictWord{5, 0, 944},
+ dictWord{134, 0, 1769},
+ dictWord{4, 0, 144},
+ dictWord{6, 0, 842},
+ dictWord{
+ 6,
+ 0,
+ 1400,
+ },
+ dictWord{4, 11, 922},
+ dictWord{133, 11, 1023},
+ dictWord{133, 10, 248},
+ dictWord{9, 10, 800},
+ dictWord{10, 10, 693},
+ dictWord{11, 10, 482},
+ dictWord{11, 10, 734},
+ dictWord{139, 10, 789},
+ dictWord{7, 11, 1002},
+ dictWord{139, 11, 145},
+ dictWord{4, 10, 116},
+ dictWord{5, 10, 95},
+ dictWord{5, 10, 445},
+ dictWord{7, 10, 1688},
+ dictWord{8, 10, 29},
+ dictWord{9, 10, 272},
+ dictWord{11, 10, 509},
+ dictWord{139, 10, 915},
+ dictWord{14, 0, 369},
+ dictWord{146, 0, 72},
+ dictWord{135, 10, 1641},
+ dictWord{132, 11, 740},
+ dictWord{133, 10, 543},
+ dictWord{140, 11, 116},
+ dictWord{6, 0, 247},
+ dictWord{9, 0, 555},
+ dictWord{
+ 5,
+ 10,
+ 181,
+ },
+ dictWord{136, 10, 41},
+ dictWord{133, 10, 657},
+ dictWord{136, 0, 996},
+ dictWord{138, 10, 709},
+ dictWord{7, 0, 189},
+ dictWord{8, 10, 202},
+ dictWord{
+ 138,
+ 10,
+ 536,
+ },
+ dictWord{136, 11, 402},
+ dictWord{4, 11, 716},
+ dictWord{141, 11, 31},
+ dictWord{10, 0, 280},
+ dictWord{138, 0, 797},
+ dictWord{9, 10, 423},
+ dictWord{140, 10, 89},
+ dictWord{8, 10, 113},
+ dictWord{9, 10, 877},
+ dictWord{10, 10, 554},
+ dictWord{11, 10, 83},
+ dictWord{12, 10, 136},
+ dictWord{147, 10, 109},
+ dictWord{133, 10, 976},
+ dictWord{7, 0, 746},
+ dictWord{132, 10, 206},
+ dictWord{136, 0, 526},
+ dictWord{139, 0, 345},
+ dictWord{136, 0, 1017},
+ dictWord{
+ 8,
+ 11,
+ 152,
+ },
+ dictWord{9, 11, 53},
+ dictWord{9, 11, 268},
+ dictWord{9, 11, 901},
+ dictWord{10, 11, 518},
+ dictWord{10, 11, 829},
+ dictWord{11, 11, 188},
+ dictWord{
+ 13,
+ 11,
+ 74,
+ },
+ dictWord{14, 11, 46},
+ dictWord{15, 11, 17},
+ dictWord{15, 11, 33},
+ dictWord{17, 11, 40},
+ dictWord{18, 11, 36},
+ dictWord{19, 11, 20},
+ dictWord{22, 11, 1},
+ dictWord{152, 11, 2},
+ dictWord{133, 11, 736},
+ dictWord{136, 11, 532},
+ dictWord{5, 0, 428},
+ dictWord{138, 0, 651},
+ dictWord{135, 11, 681},
+ dictWord{
+ 135,
+ 0,
+ 1162,
+ },
+ dictWord{7, 0, 327},
+ dictWord{13, 0, 230},
+ dictWord{17, 0, 113},
+ dictWord{8, 10, 226},
+ dictWord{10, 10, 537},
+ dictWord{11, 10, 570},
+ dictWord{
+ 11,
+ 10,
+ 605,
+ },
+ dictWord{11, 10, 799},
+ dictWord{11, 10, 804},
+ dictWord{12, 10, 85},
+ dictWord{12, 10, 516},
+ dictWord{12, 10, 623},
+ dictWord{12, 11, 677},
+ dictWord{
+ 13,
+ 10,
+ 361,
+ },
+ dictWord{14, 10, 77},
+ dictWord{14, 10, 78},
+ dictWord{147, 10, 110},
+ dictWord{4, 0, 792},
+ dictWord{7, 0, 1717},
+ dictWord{10, 0, 546},
+ dictWord{
+ 132,
+ 10,
+ 769,
+ },
+ dictWord{4, 11, 684},
+ dictWord{136, 11, 384},
+ dictWord{132, 10, 551},
+ dictWord{134, 0, 1203},
+ dictWord{9, 10, 57},
+ dictWord{9, 10, 459},
+ dictWord{10, 10, 425},
+ dictWord{11, 10, 119},
+ dictWord{12, 10, 184},
+ dictWord{12, 10, 371},
+ dictWord{13, 10, 358},
+ dictWord{145, 10, 51},
+ dictWord{5, 0, 672},
+ dictWord{5, 10, 814},
+ dictWord{8, 10, 10},
+ dictWord{9, 10, 421},
+ dictWord{9, 10, 729},
+ dictWord{10, 10, 609},
+ dictWord{139, 10, 689},
+ dictWord{138, 0, 189},
+ dictWord{134, 10, 624},
+ dictWord{7, 11, 110},
+ dictWord{7, 11, 188},
+ dictWord{8, 11, 290},
+ dictWord{8, 11, 591},
+ dictWord{9, 11, 382},
+ dictWord{9, 11, 649},
+ dictWord{11, 11, 71},
+ dictWord{11, 11, 155},
+ dictWord{11, 11, 313},
+ dictWord{12, 11, 5},
+ dictWord{13, 11, 325},
+ dictWord{142, 11, 287},
+ dictWord{133, 0, 99},
+ dictWord{6, 0, 1053},
+ dictWord{135, 0, 298},
+ dictWord{7, 11, 360},
+ dictWord{7, 11, 425},
+ dictWord{9, 11, 66},
+ dictWord{9, 11, 278},
+ dictWord{138, 11, 644},
+ dictWord{4, 0, 397},
+ dictWord{136, 0, 555},
+ dictWord{137, 10, 269},
+ dictWord{132, 10, 528},
+ dictWord{4, 11, 900},
+ dictWord{133, 11, 861},
+ dictWord{
+ 6,
+ 0,
+ 1157,
+ },
+ dictWord{5, 11, 254},
+ dictWord{7, 11, 985},
+ dictWord{136, 11, 73},
+ dictWord{7, 11, 1959},
+ dictWord{136, 11, 683},
+ dictWord{12, 0, 398},
+ dictWord{
+ 20,
+ 0,
+ 39,
+ },
+ dictWord{21, 0, 11},
+ dictWord{150, 0, 41},
+ dictWord{4, 0, 485},
+ dictWord{7, 0, 353},
+ dictWord{135, 0, 1523},
+ dictWord{6, 0, 366},
+ dictWord{7, 0, 1384},
+ dictWord{135, 0, 1601},
+ dictWord{138, 0, 787},
+ dictWord{137, 0, 282},
+ dictWord{5, 10, 104},
+ dictWord{6, 10, 173},
+ dictWord{135, 10, 1631},
+ dictWord{
+ 139,
+ 11,
+ 146,
+ },
+ dictWord{4, 0, 157},
+ dictWord{133, 0, 471},
+ dictWord{134, 0, 941},
+ dictWord{132, 11, 725},
+ dictWord{7, 0, 1336},
+ dictWord{8, 10, 138},
+ dictWord{
+ 8,
+ 10,
+ 342,
+ },
+ dictWord{9, 10, 84},
+ dictWord{10, 10, 193},
+ dictWord{11, 10, 883},
+ dictWord{140, 10, 359},
+ dictWord{134, 11, 196},
+ dictWord{136, 0, 116},
+ dictWord{133, 11, 831},
+ dictWord{134, 0, 787},
+ dictWord{134, 10, 95},
+ dictWord{6, 10, 406},
+ dictWord{10, 10, 409},
+ dictWord{10, 10, 447},
+ dictWord{
+ 11,
+ 10,
+ 44,
+ },
+ dictWord{140, 10, 100},
+ dictWord{5, 0, 160},
+ dictWord{7, 0, 363},
+ dictWord{7, 0, 589},
+ dictWord{10, 0, 170},
+ dictWord{141, 0, 55},
+ dictWord{134, 0, 1815},
+ dictWord{132, 0, 866},
+ dictWord{6, 0, 889},
+ dictWord{6, 0, 1067},
+ dictWord{6, 0, 1183},
+ dictWord{4, 11, 321},
+ dictWord{134, 11, 569},
+ dictWord{5, 11, 848},
+ dictWord{134, 11, 66},
+ dictWord{4, 11, 36},
+ dictWord{6, 10, 1636},
+ dictWord{7, 11, 1387},
+ dictWord{10, 11, 205},
+ dictWord{11, 11, 755},
+ dictWord{
+ 141,
+ 11,
+ 271,
+ },
+ dictWord{132, 0, 689},
+ dictWord{9, 0, 820},
+ dictWord{4, 10, 282},
+ dictWord{7, 10, 1034},
+ dictWord{11, 10, 398},
+ dictWord{11, 10, 634},
+ dictWord{
+ 12,
+ 10,
+ 1,
+ },
+ dictWord{12, 10, 79},
+ dictWord{12, 10, 544},
+ dictWord{14, 10, 237},
+ dictWord{17, 10, 10},
+ dictWord{146, 10, 20},
+ dictWord{4, 0, 108},
+ dictWord{7, 0, 804},
+ dictWord{139, 0, 498},
+ dictWord{132, 11, 887},
+ dictWord{6, 0, 1119},
+ dictWord{135, 11, 620},
+ dictWord{6, 11, 165},
+ dictWord{138, 11, 388},
+ dictWord{
+ 5,
+ 0,
+ 244,
+ },
+ dictWord{5, 10, 499},
+ dictWord{6, 10, 476},
+ dictWord{7, 10, 600},
+ dictWord{7, 10, 888},
+ dictWord{135, 10, 1096},
+ dictWord{140, 0, 609},
+ dictWord{
+ 135,
+ 0,
+ 1005,
+ },
+ dictWord{4, 0, 412},
+ dictWord{133, 0, 581},
+ dictWord{4, 11, 719},
+ dictWord{135, 11, 155},
+ dictWord{7, 10, 296},
+ dictWord{7, 10, 596},
+ dictWord{
+ 8,
+ 10,
+ 560,
+ },
+ dictWord{8, 10, 586},
+ dictWord{9, 10, 612},
+ dictWord{11, 10, 304},
+ dictWord{12, 10, 46},
+ dictWord{13, 10, 89},
+ dictWord{14, 10, 112},
+ dictWord{
+ 145,
+ 10,
+ 122,
+ },
+ dictWord{4, 0, 895},
+ dictWord{133, 0, 772},
+ dictWord{142, 11, 307},
+ dictWord{135, 0, 1898},
+ dictWord{4, 0, 926},
+ dictWord{133, 0, 983},
+ dictWord{4, 11, 353},
+ dictWord{6, 11, 146},
+ dictWord{6, 11, 1789},
+ dictWord{7, 11, 288},
+ dictWord{7, 11, 990},
+ dictWord{7, 11, 1348},
+ dictWord{9, 11, 665},
+ dictWord{
+ 9,
+ 11,
+ 898,
+ },
+ dictWord{11, 11, 893},
+ dictWord{142, 11, 212},
+ dictWord{132, 0, 538},
+ dictWord{133, 11, 532},
+ dictWord{6, 0, 294},
+ dictWord{7, 0, 1267},
+ dictWord{8, 0, 624},
+ dictWord{141, 0, 496},
+ dictWord{7, 0, 1325},
+ dictWord{4, 11, 45},
+ dictWord{135, 11, 1257},
+ dictWord{138, 0, 301},
+ dictWord{9, 0, 298},
+ dictWord{12, 0, 291},
+ dictWord{13, 0, 276},
+ dictWord{14, 0, 6},
+ dictWord{17, 0, 18},
+ dictWord{21, 0, 32},
+ dictWord{7, 10, 1599},
+ dictWord{7, 10, 1723},
+ dictWord{
+ 8,
+ 10,
+ 79,
+ },
+ dictWord{8, 10, 106},
+ dictWord{8, 10, 190},
+ dictWord{8, 10, 302},
+ dictWord{8, 10, 383},
+ dictWord{8, 10, 713},
+ dictWord{9, 10, 119},
+ dictWord{9, 10, 233},
+ dictWord{9, 10, 419},
+ dictWord{9, 10, 471},
+ dictWord{10, 10, 181},
+ dictWord{10, 10, 406},
+ dictWord{11, 10, 57},
+ dictWord{11, 10, 85},
+ dictWord{11, 10, 120},
+ dictWord{11, 10, 177},
+ dictWord{11, 10, 296},
+ dictWord{11, 10, 382},
+ dictWord{11, 10, 454},
+ dictWord{11, 10, 758},
+ dictWord{11, 10, 999},
+ dictWord{
+ 12,
+ 10,
+ 27,
+ },
+ dictWord{12, 10, 131},
+ dictWord{12, 10, 245},
+ dictWord{12, 10, 312},
+ dictWord{12, 10, 446},
+ dictWord{12, 10, 454},
+ dictWord{13, 10, 98},
+ dictWord{
+ 13,
+ 10,
+ 426,
+ },
+ dictWord{13, 10, 508},
+ dictWord{14, 10, 163},
+ dictWord{14, 10, 272},
+ dictWord{14, 10, 277},
+ dictWord{14, 10, 370},
+ dictWord{15, 10, 95},
+ dictWord{15, 10, 138},
+ dictWord{15, 10, 167},
+ dictWord{17, 10, 38},
+ dictWord{148, 10, 96},
+ dictWord{132, 0, 757},
+ dictWord{134, 0, 1263},
+ dictWord{4, 0, 820},
+ dictWord{134, 10, 1759},
+ dictWord{133, 0, 722},
+ dictWord{136, 11, 816},
+ dictWord{138, 10, 372},
+ dictWord{145, 10, 16},
+ dictWord{134, 0, 1039},
+ dictWord{
+ 4,
+ 0,
+ 991,
+ },
+ dictWord{134, 0, 2028},
+ dictWord{133, 10, 258},
+ dictWord{7, 0, 1875},
+ dictWord{139, 0, 124},
+ dictWord{6, 11, 559},
+ dictWord{6, 11, 1691},
+ dictWord{135, 11, 586},
+ dictWord{5, 0, 324},
+ dictWord{7, 0, 881},
+ dictWord{8, 10, 134},
+ dictWord{9, 10, 788},
+ dictWord{140, 10, 438},
+ dictWord{7, 11, 1823},
+ dictWord{139, 11, 693},
+ dictWord{6, 0, 1348},
+ dictWord{134, 0, 1545},
+ dictWord{134, 0, 911},
+ dictWord{132, 0, 954},
+ dictWord{8, 0, 329},
+ dictWord{8, 0, 414},
+ dictWord{7, 10, 1948},
+ dictWord{135, 10, 2004},
+ dictWord{5, 0, 517},
+ dictWord{6, 10, 439},
+ dictWord{7, 10, 780},
+ dictWord{135, 10, 1040},
+ dictWord{
+ 132,
+ 0,
+ 816,
+ },
+ dictWord{5, 10, 1},
+ dictWord{6, 10, 81},
+ dictWord{138, 10, 520},
+ dictWord{9, 0, 713},
+ dictWord{10, 0, 222},
+ dictWord{5, 10, 482},
+ dictWord{8, 10, 98},
+ dictWord{10, 10, 700},
+ dictWord{10, 10, 822},
+ dictWord{11, 10, 302},
+ dictWord{11, 10, 778},
+ dictWord{12, 10, 50},
+ dictWord{12, 10, 127},
+ dictWord{12, 10, 396},
+ dictWord{13, 10, 62},
+ dictWord{13, 10, 328},
+ dictWord{14, 10, 122},
+ dictWord{147, 10, 72},
+ dictWord{137, 0, 33},
+ dictWord{5, 10, 2},
+ dictWord{7, 10, 1494},
+ dictWord{136, 10, 589},
+ dictWord{6, 10, 512},
+ dictWord{7, 10, 797},
+ dictWord{8, 10, 253},
+ dictWord{9, 10, 77},
+ dictWord{10, 10, 1},
+ dictWord{10, 11, 108},
+ dictWord{10, 10, 129},
+ dictWord{10, 10, 225},
+ dictWord{11, 11, 116},
+ dictWord{11, 10, 118},
+ dictWord{11, 10, 226},
+ dictWord{11, 10, 251},
+ dictWord{
+ 11,
+ 10,
+ 430,
+ },
+ dictWord{11, 10, 701},
+ dictWord{11, 10, 974},
+ dictWord{11, 10, 982},
+ dictWord{12, 10, 64},
+ dictWord{12, 10, 260},
+ dictWord{12, 10, 488},
+ dictWord{
+ 140,
+ 10,
+ 690,
+ },
+ dictWord{134, 11, 456},
+ dictWord{133, 11, 925},
+ dictWord{5, 0, 150},
+ dictWord{7, 0, 106},
+ dictWord{7, 0, 774},
+ dictWord{8, 0, 603},
+ dictWord{
+ 9,
+ 0,
+ 593,
+ },
+ dictWord{9, 0, 634},
+ dictWord{10, 0, 44},
+ dictWord{10, 0, 173},
+ dictWord{11, 0, 462},
+ dictWord{11, 0, 515},
+ dictWord{13, 0, 216},
+ dictWord{13, 0, 288},
+ dictWord{142, 0, 400},
+ dictWord{137, 10, 347},
+ dictWord{5, 0, 748},
+ dictWord{134, 0, 553},
+ dictWord{12, 0, 108},
+ dictWord{141, 0, 291},
+ dictWord{7, 0, 420},
+ dictWord{4, 10, 12},
+ dictWord{7, 10, 522},
+ dictWord{7, 10, 809},
+ dictWord{8, 10, 797},
+ dictWord{141, 10, 88},
+ dictWord{6, 11, 193},
+ dictWord{7, 11, 240},
+ dictWord{
+ 7,
+ 11,
+ 1682,
+ },
+ dictWord{10, 11, 51},
+ dictWord{10, 11, 640},
+ dictWord{11, 11, 410},
+ dictWord{13, 11, 82},
+ dictWord{14, 11, 247},
+ dictWord{14, 11, 331},
+ dictWord{142, 11, 377},
+ dictWord{133, 10, 528},
+ dictWord{135, 0, 1777},
+ dictWord{4, 0, 493},
+ dictWord{144, 0, 55},
+ dictWord{136, 11, 633},
+ dictWord{
+ 139,
+ 0,
+ 81,
+ },
+ dictWord{6, 0, 980},
+ dictWord{136, 0, 321},
+ dictWord{148, 10, 109},
+ dictWord{5, 10, 266},
+ dictWord{9, 10, 290},
+ dictWord{9, 10, 364},
+ dictWord{
+ 10,
+ 10,
+ 293,
+ },
+ dictWord{11, 10, 606},
+ dictWord{142, 10, 45},
+ dictWord{6, 0, 568},
+ dictWord{7, 0, 112},
+ dictWord{7, 0, 1804},
+ dictWord{8, 0, 362},
+ dictWord{8, 0, 410},
+ dictWord{8, 0, 830},
+ dictWord{9, 0, 514},
+ dictWord{11, 0, 649},
+ dictWord{142, 0, 157},
+ dictWord{4, 0, 74},
+ dictWord{6, 0, 510},
+ dictWord{6, 10, 594},
+ dictWord{
+ 9,
+ 10,
+ 121,
+ },
+ dictWord{10, 10, 49},
+ dictWord{10, 10, 412},
+ dictWord{139, 10, 834},
+ dictWord{134, 0, 838},
+ dictWord{136, 10, 748},
+ dictWord{132, 10, 466},
+ dictWord{132, 0, 625},
+ dictWord{135, 11, 1443},
+ dictWord{4, 11, 237},
+ dictWord{135, 11, 514},
+ dictWord{9, 10, 378},
+ dictWord{141, 10, 162},
+ dictWord{6, 0, 16},
+ dictWord{6, 0, 158},
+ dictWord{7, 0, 43},
+ dictWord{7, 0, 129},
+ dictWord{7, 0, 181},
+ dictWord{8, 0, 276},
+ dictWord{8, 0, 377},
+ dictWord{10, 0, 523},
+ dictWord{
+ 11,
+ 0,
+ 816,
+ },
+ dictWord{12, 0, 455},
+ dictWord{13, 0, 303},
+ dictWord{142, 0, 135},
+ dictWord{135, 0, 281},
+ dictWord{4, 0, 1},
+ dictWord{7, 0, 1143},
+ dictWord{7, 0, 1463},
+ dictWord{8, 0, 61},
+ dictWord{9, 0, 207},
+ dictWord{9, 0, 390},
+ dictWord{9, 0, 467},
+ dictWord{139, 0, 836},
+ dictWord{6, 11, 392},
+ dictWord{7, 11, 65},
+ dictWord{
+ 135,
+ 11,
+ 2019,
+ },
+ dictWord{132, 10, 667},
+ dictWord{4, 0, 723},
+ dictWord{5, 0, 895},
+ dictWord{7, 0, 1031},
+ dictWord{8, 0, 199},
+ dictWord{8, 0, 340},
+ dictWord{9, 0, 153},
+ dictWord{9, 0, 215},
+ dictWord{10, 0, 21},
+ dictWord{10, 0, 59},
+ dictWord{10, 0, 80},
+ dictWord{10, 0, 224},
+ dictWord{10, 0, 838},
+ dictWord{11, 0, 229},
+ dictWord{
+ 11,
+ 0,
+ 652,
+ },
+ dictWord{12, 0, 192},
+ dictWord{13, 0, 146},
+ dictWord{142, 0, 91},
+ dictWord{132, 0, 295},
+ dictWord{137, 0, 51},
+ dictWord{9, 11, 222},
+ dictWord{
+ 10,
+ 11,
+ 43,
+ },
+ dictWord{139, 11, 900},
+ dictWord{5, 0, 309},
+ dictWord{140, 0, 211},
+ dictWord{5, 0, 125},
+ dictWord{8, 0, 77},
+ dictWord{138, 0, 15},
+ dictWord{136, 11, 604},
+ dictWord{138, 0, 789},
+ dictWord{5, 0, 173},
+ dictWord{4, 10, 39},
+ dictWord{7, 10, 1843},
+ dictWord{8, 10, 407},
+ dictWord{11, 10, 144},
+ dictWord{140, 10, 523},
+ dictWord{138, 11, 265},
+ dictWord{133, 0, 439},
+ dictWord{132, 10, 510},
+ dictWord{7, 0, 648},
+ dictWord{7, 0, 874},
+ dictWord{11, 0, 164},
+ dictWord{12, 0, 76},
+ dictWord{18, 0, 9},
+ dictWord{7, 10, 1980},
+ dictWord{10, 10, 487},
+ dictWord{138, 10, 809},
+ dictWord{12, 0, 111},
+ dictWord{14, 0, 294},
+ dictWord{19, 0, 45},
+ dictWord{13, 10, 260},
+ dictWord{146, 10, 63},
+ dictWord{133, 11, 549},
+ dictWord{134, 10, 570},
+ dictWord{4, 0, 8},
+ dictWord{7, 0, 1152},
+ dictWord{7, 0, 1153},
+ dictWord{7, 0, 1715},
+ dictWord{9, 0, 374},
+ dictWord{10, 0, 478},
+ dictWord{139, 0, 648},
+ dictWord{135, 0, 1099},
+ dictWord{5, 0, 575},
+ dictWord{6, 0, 354},
+ dictWord{
+ 135,
+ 0,
+ 701,
+ },
+ dictWord{7, 11, 36},
+ dictWord{8, 11, 201},
+ dictWord{136, 11, 605},
+ dictWord{4, 10, 787},
+ dictWord{136, 11, 156},
+ dictWord{6, 0, 518},
+ dictWord{
+ 149,
+ 11,
+ 13,
+ },
+ dictWord{140, 11, 224},
+ dictWord{134, 0, 702},
+ dictWord{132, 10, 516},
+ dictWord{5, 11, 724},
+ dictWord{10, 11, 305},
+ dictWord{11, 11, 151},
+ dictWord{12, 11, 33},
+ dictWord{12, 11, 121},
+ dictWord{12, 11, 381},
+ dictWord{17, 11, 3},
+ dictWord{17, 11, 27},
+ dictWord{17, 11, 78},
+ dictWord{18, 11, 18},
+ dictWord{19, 11, 54},
+ dictWord{149, 11, 5},
+ dictWord{8, 0, 87},
+ dictWord{4, 11, 523},
+ dictWord{5, 11, 638},
+ dictWord{11, 10, 887},
+ dictWord{14, 10, 365},
+ dictWord{
+ 142,
+ 10,
+ 375,
+ },
+ dictWord{138, 0, 438},
+ dictWord{136, 10, 821},
+ dictWord{135, 11, 1908},
+ dictWord{6, 11, 242},
+ dictWord{7, 11, 227},
+ dictWord{7, 11, 1581},
+ dictWord{8, 11, 104},
+ dictWord{9, 11, 113},
+ dictWord{9, 11, 220},
+ dictWord{9, 11, 427},
+ dictWord{10, 11, 74},
+ dictWord{10, 11, 239},
+ dictWord{11, 11, 579},
+ dictWord{11, 11, 1023},
+ dictWord{13, 11, 4},
+ dictWord{13, 11, 204},
+ dictWord{13, 11, 316},
+ dictWord{18, 11, 95},
+ dictWord{148, 11, 86},
+ dictWord{4, 0, 69},
+ dictWord{5, 0, 122},
+ dictWord{5, 0, 849},
+ dictWord{6, 0, 1633},
+ dictWord{9, 0, 656},
+ dictWord{138, 0, 464},
+ dictWord{7, 0, 1802},
+ dictWord{4, 10, 10},
+ dictWord{
+ 139,
+ 10,
+ 786,
+ },
+ dictWord{135, 11, 861},
+ dictWord{139, 0, 499},
+ dictWord{7, 0, 476},
+ dictWord{7, 0, 1592},
+ dictWord{138, 0, 87},
+ dictWord{133, 10, 684},
+ dictWord{
+ 4,
+ 0,
+ 840,
+ },
+ dictWord{134, 10, 27},
+ dictWord{142, 0, 283},
+ dictWord{6, 0, 1620},
+ dictWord{7, 11, 1328},
+ dictWord{136, 11, 494},
+ dictWord{5, 0, 859},
+ dictWord{
+ 7,
+ 0,
+ 1160,
+ },
+ dictWord{8, 0, 107},
+ dictWord{9, 0, 291},
+ dictWord{9, 0, 439},
+ dictWord{10, 0, 663},
+ dictWord{11, 0, 609},
+ dictWord{140, 0, 197},
+ dictWord{
+ 7,
+ 11,
+ 1306,
+ },
+ dictWord{8, 11, 505},
+ dictWord{9, 11, 482},
+ dictWord{10, 11, 126},
+ dictWord{11, 11, 225},
+ dictWord{12, 11, 347},
+ dictWord{12, 11, 449},
+ dictWord{
+ 13,
+ 11,
+ 19,
+ },
+ dictWord{142, 11, 218},
+ dictWord{5, 11, 268},
+ dictWord{10, 11, 764},
+ dictWord{12, 11, 120},
+ dictWord{13, 11, 39},
+ dictWord{145, 11, 127},
+ dictWord{145, 10, 56},
+ dictWord{7, 11, 1672},
+ dictWord{10, 11, 472},
+ dictWord{11, 11, 189},
+ dictWord{143, 11, 51},
+ dictWord{6, 10, 342},
+ dictWord{6, 10, 496},
+ dictWord{8, 10, 275},
+ dictWord{137, 10, 206},
+ dictWord{133, 0, 600},
+ dictWord{4, 0, 117},
+ dictWord{6, 0, 372},
+ dictWord{7, 0, 1905},
+ dictWord{142, 0, 323},
+ dictWord{4, 10, 909},
+ dictWord{5, 10, 940},
+ dictWord{135, 11, 1471},
+ dictWord{132, 10, 891},
+ dictWord{4, 0, 722},
+ dictWord{139, 0, 471},
+ dictWord{4, 11, 384},
+ dictWord{135, 11, 1022},
+ dictWord{132, 10, 687},
+ dictWord{9, 0, 5},
+ dictWord{12, 0, 216},
+ dictWord{12, 0, 294},
+ dictWord{12, 0, 298},
+ dictWord{12, 0, 400},
+ dictWord{12, 0, 518},
+ dictWord{13, 0, 229},
+ dictWord{143, 0, 139},
+ dictWord{135, 11, 1703},
+ dictWord{7, 11, 1602},
+ dictWord{10, 11, 698},
+ dictWord{
+ 12,
+ 11,
+ 212,
+ },
+ dictWord{141, 11, 307},
+ dictWord{6, 10, 41},
+ dictWord{141, 10, 160},
+ dictWord{135, 11, 1077},
+ dictWord{9, 11, 159},
+ dictWord{11, 11, 28},
+ dictWord{140, 11, 603},
+ dictWord{4, 0, 514},
+ dictWord{7, 0, 1304},
+ dictWord{138, 0, 477},
+ dictWord{134, 0, 1774},
+ dictWord{9, 0, 88},
+ dictWord{139, 0, 270},
+ dictWord{5, 0, 12},
+ dictWord{7, 0, 375},
+ dictWord{9, 0, 438},
+ dictWord{134, 10, 1718},
+ dictWord{132, 11, 515},
+ dictWord{136, 10, 778},
+ dictWord{8, 11, 632},
+ dictWord{8, 11, 697},
+ dictWord{137, 11, 854},
+ dictWord{6, 0, 362},
+ dictWord{6, 0, 997},
+ dictWord{146, 0, 51},
+ dictWord{7, 0, 816},
+ dictWord{7, 0, 1241},
+ dictWord{
+ 9,
+ 0,
+ 283,
+ },
+ dictWord{9, 0, 520},
+ dictWord{10, 0, 213},
+ dictWord{10, 0, 307},
+ dictWord{10, 0, 463},
+ dictWord{10, 0, 671},
+ dictWord{10, 0, 746},
+ dictWord{11, 0, 401},
+ dictWord{11, 0, 794},
+ dictWord{12, 0, 517},
+ dictWord{18, 0, 107},
+ dictWord{147, 0, 115},
+ dictWord{133, 10, 115},
+ dictWord{150, 11, 28},
+ dictWord{4, 11, 136},
+ dictWord{133, 11, 551},
+ dictWord{142, 10, 314},
+ dictWord{132, 0, 258},
+ dictWord{6, 0, 22},
+ dictWord{7, 0, 903},
+ dictWord{7, 0, 1963},
+ dictWord{8, 0, 639},
+ dictWord{138, 0, 577},
+ dictWord{5, 0, 681},
+ dictWord{8, 0, 782},
+ dictWord{13, 0, 130},
+ dictWord{17, 0, 84},
+ dictWord{5, 10, 193},
+ dictWord{140, 10, 178},
+ dictWord{
+ 9,
+ 11,
+ 17,
+ },
+ dictWord{138, 11, 291},
+ dictWord{7, 11, 1287},
+ dictWord{9, 11, 44},
+ dictWord{10, 11, 552},
+ dictWord{10, 11, 642},
+ dictWord{11, 11, 839},
+ dictWord{12, 11, 274},
+ dictWord{12, 11, 275},
+ dictWord{12, 11, 372},
+ dictWord{13, 11, 91},
+ dictWord{142, 11, 125},
+ dictWord{135, 10, 174},
+ dictWord{4, 0, 664},
+ dictWord{5, 0, 804},
+ dictWord{139, 0, 1013},
+ dictWord{134, 0, 942},
+ dictWord{6, 0, 1349},
+ dictWord{6, 0, 1353},
+ dictWord{6, 0, 1450},
+ dictWord{7, 11, 1518},
+ dictWord{139, 11, 694},
+ dictWord{11, 0, 356},
+ dictWord{4, 10, 122},
+ dictWord{5, 10, 796},
+ dictWord{5, 10, 952},
+ dictWord{6, 10, 1660},
+ dictWord{
+ 6,
+ 10,
+ 1671,
+ },
+ dictWord{8, 10, 567},
+ dictWord{9, 10, 687},
+ dictWord{9, 10, 742},
+ dictWord{10, 10, 686},
+ dictWord{11, 10, 682},
+ dictWord{140, 10, 281},
+ dictWord{
+ 5,
+ 0,
+ 32,
+ },
+ dictWord{6, 11, 147},
+ dictWord{7, 11, 886},
+ dictWord{9, 11, 753},
+ dictWord{138, 11, 268},
+ dictWord{5, 10, 179},
+ dictWord{7, 10, 1095},
+ dictWord{
+ 135,
+ 10,
+ 1213,
+ },
+ dictWord{4, 10, 66},
+ dictWord{7, 10, 722},
+ dictWord{135, 10, 904},
+ dictWord{135, 10, 352},
+ dictWord{9, 11, 245},
+ dictWord{138, 11, 137},
+ dictWord{4, 0, 289},
+ dictWord{7, 0, 629},
+ dictWord{7, 0, 1698},
+ dictWord{7, 0, 1711},
+ dictWord{12, 0, 215},
+ dictWord{133, 11, 414},
+ dictWord{6, 0, 1975},
+ dictWord{135, 11, 1762},
+ dictWord{6, 0, 450},
+ dictWord{136, 0, 109},
+ dictWord{141, 10, 35},
+ dictWord{134, 11, 599},
+ dictWord{136, 0, 705},
+ dictWord{
+ 133,
+ 0,
+ 664,
+ },
+ dictWord{134, 11, 1749},
+ dictWord{11, 11, 402},
+ dictWord{12, 11, 109},
+ dictWord{12, 11, 431},
+ dictWord{13, 11, 179},
+ dictWord{13, 11, 206},
+ dictWord{14, 11, 175},
+ dictWord{14, 11, 217},
+ dictWord{16, 11, 3},
+ dictWord{148, 11, 53},
+ dictWord{135, 0, 1238},
+ dictWord{134, 11, 1627},
+ dictWord{
+ 132,
+ 11,
+ 488,
+ },
+ dictWord{13, 0, 318},
+ dictWord{10, 10, 592},
+ dictWord{10, 10, 753},
+ dictWord{12, 10, 317},
+ dictWord{12, 10, 355},
+ dictWord{12, 10, 465},
+ dictWord{
+ 12,
+ 10,
+ 469,
+ },
+ dictWord{12, 10, 560},
+ dictWord{140, 10, 578},
+ dictWord{133, 10, 564},
+ dictWord{132, 11, 83},
+ dictWord{140, 11, 676},
+ dictWord{6, 0, 1872},
+ dictWord{6, 0, 1906},
+ dictWord{6, 0, 1907},
+ dictWord{9, 0, 934},
+ dictWord{9, 0, 956},
+ dictWord{9, 0, 960},
+ dictWord{9, 0, 996},
+ dictWord{12, 0, 794},
+ dictWord{
+ 12,
+ 0,
+ 876,
+ },
+ dictWord{12, 0, 880},
+ dictWord{12, 0, 918},
+ dictWord{15, 0, 230},
+ dictWord{18, 0, 234},
+ dictWord{18, 0, 238},
+ dictWord{21, 0, 38},
+ dictWord{149, 0, 62},
+ dictWord{134, 10, 556},
+ dictWord{134, 11, 278},
+ dictWord{137, 0, 103},
+ dictWord{7, 10, 544},
+ dictWord{8, 10, 719},
+ dictWord{138, 10, 61},
+ dictWord{
+ 4,
+ 10,
+ 5,
+ },
+ dictWord{5, 10, 498},
+ dictWord{8, 10, 637},
+ dictWord{137, 10, 521},
+ dictWord{7, 0, 777},
+ dictWord{12, 0, 229},
+ dictWord{12, 0, 239},
+ dictWord{15, 0, 12},
+ dictWord{12, 11, 229},
+ dictWord{12, 11, 239},
+ dictWord{143, 11, 12},
+ dictWord{6, 0, 26},
+ dictWord{7, 11, 388},
+ dictWord{7, 11, 644},
+ dictWord{139, 11, 781},
+ dictWord{7, 11, 229},
+ dictWord{8, 11, 59},
+ dictWord{9, 11, 190},
+ dictWord{9, 11, 257},
+ dictWord{10, 11, 378},
+ dictWord{140, 11, 191},
+ dictWord{133, 10, 927},
+ dictWord{135, 10, 1441},
+ dictWord{4, 10, 893},
+ dictWord{5, 10, 780},
+ dictWord{133, 10, 893},
+ dictWord{4, 0, 414},
+ dictWord{5, 0, 467},
+ dictWord{9, 0, 654},
+ dictWord{10, 0, 451},
+ dictWord{12, 0, 59},
+ dictWord{141, 0, 375},
+ dictWord{142, 0, 173},
+ dictWord{135, 0, 17},
+ dictWord{7, 0, 1350},
+ dictWord{133, 10, 238},
+ dictWord{135, 0, 955},
+ dictWord{4, 0, 960},
+ dictWord{10, 0, 887},
+ dictWord{12, 0, 753},
+ dictWord{18, 0, 161},
+ dictWord{18, 0, 162},
+ dictWord{152, 0, 19},
+ dictWord{136, 11, 344},
+ dictWord{6, 10, 1729},
+ dictWord{137, 11, 288},
+ dictWord{132, 11, 660},
+ dictWord{4, 0, 217},
+ dictWord{5, 0, 710},
+ dictWord{7, 0, 760},
+ dictWord{7, 0, 1926},
+ dictWord{9, 0, 428},
+ dictWord{9, 0, 708},
+ dictWord{10, 0, 254},
+ dictWord{10, 0, 296},
+ dictWord{10, 0, 720},
+ dictWord{11, 0, 109},
+ dictWord{
+ 11,
+ 0,
+ 255,
+ },
+ dictWord{12, 0, 165},
+ dictWord{12, 0, 315},
+ dictWord{13, 0, 107},
+ dictWord{13, 0, 203},
+ dictWord{14, 0, 54},
+ dictWord{14, 0, 99},
+ dictWord{14, 0, 114},
+ dictWord{14, 0, 388},
+ dictWord{16, 0, 85},
+ dictWord{17, 0, 9},
+ dictWord{17, 0, 33},
+ dictWord{20, 0, 25},
+ dictWord{20, 0, 28},
+ dictWord{20, 0, 29},
+ dictWord{21, 0, 9},
+ dictWord{21, 0, 10},
+ dictWord{21, 0, 34},
+ dictWord{22, 0, 17},
+ dictWord{4, 10, 60},
+ dictWord{7, 10, 1800},
+ dictWord{8, 10, 314},
+ dictWord{9, 10, 700},
+ dictWord{
+ 139,
+ 10,
+ 487,
+ },
+ dictWord{7, 11, 1035},
+ dictWord{138, 11, 737},
+ dictWord{7, 11, 690},
+ dictWord{9, 11, 217},
+ dictWord{9, 11, 587},
+ dictWord{140, 11, 521},
+ dictWord{6, 0, 919},
+ dictWord{7, 11, 706},
+ dictWord{7, 11, 1058},
+ dictWord{138, 11, 538},
+ dictWord{7, 10, 1853},
+ dictWord{138, 10, 437},
+ dictWord{
+ 136,
+ 10,
+ 419,
+ },
+ dictWord{6, 0, 280},
+ dictWord{10, 0, 502},
+ dictWord{11, 0, 344},
+ dictWord{140, 0, 38},
+ dictWord{5, 0, 45},
+ dictWord{7, 0, 1161},
+ dictWord{11, 0, 448},
+ dictWord{11, 0, 880},
+ dictWord{13, 0, 139},
+ dictWord{13, 0, 407},
+ dictWord{15, 0, 16},
+ dictWord{17, 0, 95},
+ dictWord{18, 0, 66},
+ dictWord{18, 0, 88},
+ dictWord{
+ 18,
+ 0,
+ 123,
+ },
+ dictWord{149, 0, 7},
+ dictWord{11, 11, 92},
+ dictWord{11, 11, 196},
+ dictWord{11, 11, 409},
+ dictWord{11, 11, 450},
+ dictWord{11, 11, 666},
+ dictWord{
+ 11,
+ 11,
+ 777,
+ },
+ dictWord{12, 11, 262},
+ dictWord{13, 11, 385},
+ dictWord{13, 11, 393},
+ dictWord{15, 11, 115},
+ dictWord{16, 11, 45},
+ dictWord{145, 11, 82},
+ dictWord{136, 0, 777},
+ dictWord{134, 11, 1744},
+ dictWord{4, 0, 410},
+ dictWord{7, 0, 521},
+ dictWord{133, 10, 828},
+ dictWord{134, 0, 673},
+ dictWord{7, 0, 1110},
+ dictWord{7, 0, 1778},
+ dictWord{7, 10, 176},
+ dictWord{135, 10, 178},
+ dictWord{5, 10, 806},
+ dictWord{7, 11, 268},
+ dictWord{7, 10, 1976},
+ dictWord{
+ 136,
+ 11,
+ 569,
+ },
+ dictWord{4, 11, 733},
+ dictWord{9, 11, 194},
+ dictWord{10, 11, 92},
+ dictWord{11, 11, 198},
+ dictWord{12, 11, 84},
+ dictWord{12, 11, 87},
+ dictWord{
+ 13,
+ 11,
+ 128,
+ },
+ dictWord{144, 11, 74},
+ dictWord{5, 0, 341},
+ dictWord{7, 0, 1129},
+ dictWord{11, 0, 414},
+ dictWord{4, 10, 51},
+ dictWord{6, 10, 4},
+ dictWord{7, 10, 591},
+ dictWord{7, 10, 849},
+ dictWord{7, 10, 951},
+ dictWord{7, 10, 1613},
+ dictWord{7, 10, 1760},
+ dictWord{7, 10, 1988},
+ dictWord{9, 10, 434},
+ dictWord{10, 10, 754},
+ dictWord{11, 10, 25},
+ dictWord{139, 10, 37},
+ dictWord{133, 10, 902},
+ dictWord{135, 10, 928},
+ dictWord{135, 0, 787},
+ dictWord{132, 0, 436},
+ dictWord{
+ 134,
+ 10,
+ 270,
+ },
+ dictWord{7, 0, 1587},
+ dictWord{135, 0, 1707},
+ dictWord{6, 0, 377},
+ dictWord{7, 0, 1025},
+ dictWord{9, 0, 613},
+ dictWord{145, 0, 104},
+ dictWord{
+ 7,
+ 11,
+ 982,
+ },
+ dictWord{7, 11, 1361},
+ dictWord{10, 11, 32},
+ dictWord{143, 11, 56},
+ dictWord{139, 0, 96},
+ dictWord{132, 0, 451},
+ dictWord{132, 10, 416},
+ dictWord{
+ 142,
+ 10,
+ 372,
+ },
+ dictWord{5, 10, 152},
+ dictWord{5, 10, 197},
+ dictWord{7, 11, 306},
+ dictWord{7, 10, 340},
+ dictWord{7, 10, 867},
+ dictWord{10, 10, 548},
+ dictWord{
+ 10,
+ 10,
+ 581,
+ },
+ dictWord{11, 10, 6},
+ dictWord{12, 10, 3},
+ dictWord{12, 10, 19},
+ dictWord{14, 10, 110},
+ dictWord{142, 10, 289},
+ dictWord{134, 0, 680},
+ dictWord{
+ 134,
+ 11,
+ 609,
+ },
+ dictWord{7, 0, 483},
+ dictWord{7, 10, 190},
+ dictWord{8, 10, 28},
+ dictWord{8, 10, 141},
+ dictWord{8, 10, 444},
+ dictWord{8, 10, 811},
+ dictWord{
+ 9,
+ 10,
+ 468,
+ },
+ dictWord{11, 10, 334},
+ dictWord{12, 10, 24},
+ dictWord{12, 10, 386},
+ dictWord{140, 10, 576},
+ dictWord{10, 0, 916},
+ dictWord{133, 10, 757},
+ dictWord{
+ 5,
+ 10,
+ 721,
+ },
+ dictWord{135, 10, 1553},
+ dictWord{133, 11, 178},
+ dictWord{134, 0, 937},
+ dictWord{132, 10, 898},
+ dictWord{133, 0, 739},
+ dictWord{
+ 147,
+ 0,
+ 82,
+ },
+ dictWord{135, 0, 663},
+ dictWord{146, 0, 128},
+ dictWord{5, 10, 277},
+ dictWord{141, 10, 247},
+ dictWord{134, 0, 1087},
+ dictWord{132, 10, 435},
+ dictWord{
+ 6,
+ 11,
+ 381,
+ },
+ dictWord{7, 11, 645},
+ dictWord{7, 11, 694},
+ dictWord{136, 11, 546},
+ dictWord{7, 0, 503},
+ dictWord{135, 0, 1885},
+ dictWord{6, 0, 1965},
+ dictWord{
+ 8,
+ 0,
+ 925,
+ },
+ dictWord{138, 0, 955},
+ dictWord{4, 0, 113},
+ dictWord{5, 0, 163},
+ dictWord{5, 0, 735},
+ dictWord{7, 0, 1009},
+ dictWord{9, 0, 9},
+ dictWord{9, 0, 771},
+ dictWord{12, 0, 90},
+ dictWord{13, 0, 138},
+ dictWord{13, 0, 410},
+ dictWord{143, 0, 128},
+ dictWord{4, 0, 324},
+ dictWord{138, 0, 104},
+ dictWord{7, 0, 460},
+ dictWord{
+ 5,
+ 10,
+ 265,
+ },
+ dictWord{134, 10, 212},
+ dictWord{133, 11, 105},
+ dictWord{7, 11, 261},
+ dictWord{7, 11, 1107},
+ dictWord{7, 11, 1115},
+ dictWord{7, 11, 1354},
+ dictWord{7, 11, 1588},
+ dictWord{7, 11, 1705},
+ dictWord{7, 11, 1902},
+ dictWord{9, 11, 465},
+ dictWord{10, 11, 248},
+ dictWord{10, 11, 349},
+ dictWord{10, 11, 647},
+ dictWord{11, 11, 527},
+ dictWord{11, 11, 660},
+ dictWord{11, 11, 669},
+ dictWord{12, 11, 529},
+ dictWord{141, 11, 305},
+ dictWord{5, 11, 438},
+ dictWord{
+ 9,
+ 11,
+ 694,
+ },
+ dictWord{12, 11, 627},
+ dictWord{141, 11, 210},
+ dictWord{152, 11, 11},
+ dictWord{4, 0, 935},
+ dictWord{133, 0, 823},
+ dictWord{132, 10, 702},
+ dictWord{
+ 5,
+ 0,
+ 269,
+ },
+ dictWord{7, 0, 434},
+ dictWord{7, 0, 891},
+ dictWord{8, 0, 339},
+ dictWord{9, 0, 702},
+ dictWord{11, 0, 594},
+ dictWord{11, 0, 718},
+ dictWord{17, 0, 100},
+ dictWord{5, 10, 808},
+ dictWord{135, 10, 2045},
+ dictWord{7, 0, 1014},
+ dictWord{9, 0, 485},
+ dictWord{141, 0, 264},
+ dictWord{134, 0, 1713},
+ dictWord{7, 0, 1810},
+ dictWord{11, 0, 866},
+ dictWord{12, 0, 103},
+ dictWord{13, 0, 495},
+ dictWord{140, 11, 233},
+ dictWord{4, 0, 423},
+ dictWord{10, 0, 949},
+ dictWord{138, 0, 1013},
+ dictWord{135, 0, 900},
+ dictWord{8, 11, 25},
+ dictWord{138, 11, 826},
+ dictWord{5, 10, 166},
+ dictWord{8, 10, 739},
+ dictWord{140, 10, 511},
+ dictWord{
+ 134,
+ 0,
+ 2018,
+ },
+ dictWord{7, 11, 1270},
+ dictWord{139, 11, 612},
+ dictWord{4, 10, 119},
+ dictWord{5, 10, 170},
+ dictWord{5, 10, 447},
+ dictWord{7, 10, 1708},
+ dictWord{
+ 7,
+ 10,
+ 1889,
+ },
+ dictWord{9, 10, 357},
+ dictWord{9, 10, 719},
+ dictWord{12, 10, 486},
+ dictWord{140, 10, 596},
+ dictWord{12, 0, 574},
+ dictWord{140, 11, 574},
+ dictWord{132, 11, 308},
+ dictWord{6, 0, 964},
+ dictWord{6, 0, 1206},
+ dictWord{134, 0, 1302},
+ dictWord{4, 10, 450},
+ dictWord{135, 10, 1158},
+ dictWord{
+ 135,
+ 11,
+ 150,
+ },
+ dictWord{136, 11, 649},
+ dictWord{14, 0, 213},
+ dictWord{148, 0, 38},
+ dictWord{9, 11, 45},
+ dictWord{9, 11, 311},
+ dictWord{141, 11, 42},
+ dictWord{
+ 134,
+ 11,
+ 521,
+ },
+ dictWord{7, 10, 1375},
+ dictWord{7, 10, 1466},
+ dictWord{138, 10, 331},
+ dictWord{132, 10, 754},
+ dictWord{5, 11, 339},
+ dictWord{7, 11, 1442},
+ dictWord{14, 11, 3},
+ dictWord{15, 11, 41},
+ dictWord{147, 11, 66},
+ dictWord{136, 11, 378},
+ dictWord{134, 0, 1022},
+ dictWord{5, 10, 850},
+ dictWord{136, 10, 799},
+ dictWord{142, 0, 143},
+ dictWord{135, 0, 2029},
+ dictWord{134, 11, 1628},
+ dictWord{8, 0, 523},
+ dictWord{150, 0, 34},
+ dictWord{5, 0, 625},
+ dictWord{
+ 135,
+ 0,
+ 1617,
+ },
+ dictWord{7, 0, 275},
+ dictWord{7, 10, 238},
+ dictWord{7, 10, 2033},
+ dictWord{8, 10, 120},
+ dictWord{8, 10, 188},
+ dictWord{8, 10, 659},
+ dictWord{
+ 9,
+ 10,
+ 598,
+ },
+ dictWord{10, 10, 466},
+ dictWord{12, 10, 342},
+ dictWord{12, 10, 588},
+ dictWord{13, 10, 503},
+ dictWord{14, 10, 246},
+ dictWord{143, 10, 92},
+ dictWord{
+ 7,
+ 0,
+ 37,
+ },
+ dictWord{8, 0, 425},
+ dictWord{8, 0, 693},
+ dictWord{9, 0, 720},
+ dictWord{10, 0, 380},
+ dictWord{10, 0, 638},
+ dictWord{11, 0, 273},
+ dictWord{11, 0, 473},
+ dictWord{12, 0, 61},
+ dictWord{143, 0, 43},
+ dictWord{135, 11, 829},
+ dictWord{135, 0, 1943},
+ dictWord{132, 0, 765},
+ dictWord{5, 11, 486},
+ dictWord{
+ 135,
+ 11,
+ 1349,
+ },
+ dictWord{7, 11, 1635},
+ dictWord{8, 11, 17},
+ dictWord{10, 11, 217},
+ dictWord{138, 11, 295},
+ dictWord{4, 10, 201},
+ dictWord{7, 10, 1744},
+ dictWord{
+ 8,
+ 10,
+ 602,
+ },
+ dictWord{11, 10, 247},
+ dictWord{11, 10, 826},
+ dictWord{145, 10, 65},
+ dictWord{138, 11, 558},
+ dictWord{11, 0, 551},
+ dictWord{142, 0, 159},
+ dictWord{8, 10, 164},
+ dictWord{146, 10, 62},
+ dictWord{139, 11, 176},
+ dictWord{132, 0, 168},
+ dictWord{136, 0, 1010},
+ dictWord{134, 0, 1994},
+ dictWord{
+ 135,
+ 0,
+ 91,
+ },
+ dictWord{138, 0, 532},
+ dictWord{135, 10, 1243},
+ dictWord{135, 0, 1884},
+ dictWord{132, 10, 907},
+ dictWord{5, 10, 100},
+ dictWord{10, 10, 329},
+ dictWord{12, 10, 416},
+ dictWord{149, 10, 29},
+ dictWord{134, 11, 447},
+ dictWord{132, 10, 176},
+ dictWord{5, 10, 636},
+ dictWord{5, 10, 998},
+ dictWord{7, 10, 9},
+ dictWord{7, 10, 1508},
+ dictWord{8, 10, 26},
+ dictWord{9, 10, 317},
+ dictWord{9, 10, 358},
+ dictWord{10, 10, 210},
+ dictWord{10, 10, 292},
+ dictWord{10, 10, 533},
+ dictWord{11, 10, 555},
+ dictWord{12, 10, 526},
+ dictWord{12, 10, 607},
+ dictWord{13, 10, 263},
+ dictWord{13, 10, 459},
+ dictWord{142, 10, 271},
+ dictWord{
+ 4,
+ 11,
+ 609,
+ },
+ dictWord{135, 11, 756},
+ dictWord{6, 0, 15},
+ dictWord{7, 0, 70},
+ dictWord{10, 0, 240},
+ dictWord{147, 0, 93},
+ dictWord{4, 11, 930},
+ dictWord{133, 11, 947},
+ dictWord{134, 0, 1227},
+ dictWord{134, 0, 1534},
+ dictWord{133, 11, 939},
+ dictWord{133, 11, 962},
+ dictWord{5, 11, 651},
+ dictWord{8, 11, 170},
+ dictWord{
+ 9,
+ 11,
+ 61,
+ },
+ dictWord{9, 11, 63},
+ dictWord{10, 11, 23},
+ dictWord{10, 11, 37},
+ dictWord{10, 11, 834},
+ dictWord{11, 11, 4},
+ dictWord{11, 11, 187},
+ dictWord{
+ 11,
+ 11,
+ 281,
+ },
+ dictWord{11, 11, 503},
+ dictWord{11, 11, 677},
+ dictWord{12, 11, 96},
+ dictWord{12, 11, 130},
+ dictWord{12, 11, 244},
+ dictWord{14, 11, 5},
+ dictWord{
+ 14,
+ 11,
+ 40,
+ },
+ dictWord{14, 11, 162},
+ dictWord{14, 11, 202},
+ dictWord{146, 11, 133},
+ dictWord{4, 11, 406},
+ dictWord{5, 11, 579},
+ dictWord{12, 11, 492},
+ dictWord{
+ 150,
+ 11,
+ 15,
+ },
+ dictWord{139, 0, 392},
+ dictWord{6, 10, 610},
+ dictWord{10, 10, 127},
+ dictWord{141, 10, 27},
+ dictWord{7, 0, 655},
+ dictWord{7, 0, 1844},
+ dictWord{
+ 136,
+ 10,
+ 119,
+ },
+ dictWord{4, 0, 145},
+ dictWord{6, 0, 176},
+ dictWord{7, 0, 395},
+ dictWord{137, 0, 562},
+ dictWord{132, 0, 501},
+ dictWord{140, 11, 145},
+ dictWord{
+ 136,
+ 0,
+ 1019,
+ },
+ dictWord{134, 0, 509},
+ dictWord{139, 0, 267},
+ dictWord{6, 11, 17},
+ dictWord{7, 11, 16},
+ dictWord{7, 11, 1001},
+ dictWord{7, 11, 1982},
+ dictWord{
+ 9,
+ 11,
+ 886,
+ },
+ dictWord{10, 11, 489},
+ dictWord{10, 11, 800},
+ dictWord{11, 11, 782},
+ dictWord{12, 11, 320},
+ dictWord{13, 11, 467},
+ dictWord{14, 11, 145},
+ dictWord{14, 11, 387},
+ dictWord{143, 11, 119},
+ dictWord{145, 11, 17},
+ dictWord{6, 0, 1099},
+ dictWord{133, 11, 458},
+ dictWord{7, 11, 1983},
+ dictWord{8, 11, 0},
+ dictWord{8, 11, 171},
+ dictWord{9, 11, 120},
+ dictWord{9, 11, 732},
+ dictWord{10, 11, 473},
+ dictWord{11, 11, 656},
+ dictWord{11, 11, 998},
+ dictWord{18, 11, 0},
+ dictWord{18, 11, 2},
+ dictWord{147, 11, 21},
+ dictWord{12, 11, 427},
+ dictWord{146, 11, 38},
+ dictWord{10, 0, 948},
+ dictWord{138, 0, 968},
+ dictWord{7, 10, 126},
+ dictWord{136, 10, 84},
+ dictWord{136, 10, 790},
+ dictWord{4, 0, 114},
+ dictWord{9, 0, 492},
+ dictWord{13, 0, 462},
+ dictWord{142, 0, 215},
+ dictWord{6, 10, 64},
+ dictWord{12, 10, 377},
+ dictWord{141, 10, 309},
+ dictWord{4, 0, 77},
+ dictWord{5, 0, 361},
+ dictWord{6, 0, 139},
+ dictWord{6, 0, 401},
+ dictWord{6, 0, 404},
+ dictWord{
+ 7,
+ 0,
+ 413,
+ },
+ dictWord{7, 0, 715},
+ dictWord{7, 0, 1716},
+ dictWord{11, 0, 279},
+ dictWord{12, 0, 179},
+ dictWord{12, 0, 258},
+ dictWord{13, 0, 244},
+ dictWord{142, 0, 358},
+ dictWord{134, 0, 1717},
+ dictWord{7, 0, 772},
+ dictWord{7, 0, 1061},
+ dictWord{7, 0, 1647},
+ dictWord{8, 0, 82},
+ dictWord{11, 0, 250},
+ dictWord{11, 0, 607},
+ dictWord{12, 0, 311},
+ dictWord{12, 0, 420},
+ dictWord{13, 0, 184},
+ dictWord{13, 0, 367},
+ dictWord{7, 10, 1104},
+ dictWord{11, 10, 269},
+ dictWord{11, 10, 539},
+ dictWord{11, 10, 627},
+ dictWord{11, 10, 706},
+ dictWord{11, 10, 975},
+ dictWord{12, 10, 248},
+ dictWord{12, 10, 434},
+ dictWord{12, 10, 600},
+ dictWord{
+ 12,
+ 10,
+ 622,
+ },
+ dictWord{13, 10, 297},
+ dictWord{13, 10, 485},
+ dictWord{14, 10, 69},
+ dictWord{14, 10, 409},
+ dictWord{143, 10, 108},
+ dictWord{135, 0, 724},
+ dictWord{
+ 4,
+ 11,
+ 512,
+ },
+ dictWord{4, 11, 519},
+ dictWord{133, 11, 342},
+ dictWord{134, 0, 1133},
+ dictWord{145, 11, 29},
+ dictWord{11, 10, 977},
+ dictWord{141, 10, 507},
+ dictWord{6, 0, 841},
+ dictWord{6, 0, 1042},
+ dictWord{6, 0, 1194},
+ dictWord{10, 0, 993},
+ dictWord{140, 0, 1021},
+ dictWord{6, 11, 31},
+ dictWord{7, 11, 491},
+ dictWord{7, 11, 530},
+ dictWord{8, 11, 592},
+ dictWord{9, 10, 34},
+ dictWord{11, 11, 53},
+ dictWord{11, 10, 484},
+ dictWord{11, 11, 779},
+ dictWord{12, 11, 167},
+ dictWord{12, 11, 411},
+ dictWord{14, 11, 14},
+ dictWord{14, 11, 136},
+ dictWord{15, 11, 72},
+ dictWord{16, 11, 17},
+ dictWord{144, 11, 72},
+ dictWord{4, 0, 1021},
+ dictWord{6, 0, 2037},
+ dictWord{133, 11, 907},
+ dictWord{7, 0, 373},
+ dictWord{8, 0, 335},
+ dictWord{8, 0, 596},
+ dictWord{9, 0, 488},
+ dictWord{6, 10, 1700},
+ dictWord{
+ 7,
+ 10,
+ 293,
+ },
+ dictWord{7, 10, 382},
+ dictWord{7, 10, 1026},
+ dictWord{7, 10, 1087},
+ dictWord{7, 10, 2027},
+ dictWord{8, 10, 252},
+ dictWord{8, 10, 727},
+ dictWord{
+ 8,
+ 10,
+ 729,
+ },
+ dictWord{9, 10, 30},
+ dictWord{9, 10, 199},
+ dictWord{9, 10, 231},
+ dictWord{9, 10, 251},
+ dictWord{9, 10, 334},
+ dictWord{9, 10, 361},
+ dictWord{9, 10, 712},
+ dictWord{10, 10, 55},
+ dictWord{10, 10, 60},
+ dictWord{10, 10, 232},
+ dictWord{10, 10, 332},
+ dictWord{10, 10, 384},
+ dictWord{10, 10, 396},
+ dictWord{
+ 10,
+ 10,
+ 504,
+ },
+ dictWord{10, 10, 542},
+ dictWord{10, 10, 652},
+ dictWord{11, 10, 20},
+ dictWord{11, 10, 48},
+ dictWord{11, 10, 207},
+ dictWord{11, 10, 291},
+ dictWord{
+ 11,
+ 10,
+ 298,
+ },
+ dictWord{11, 10, 342},
+ dictWord{11, 10, 365},
+ dictWord{11, 10, 394},
+ dictWord{11, 10, 620},
+ dictWord{11, 10, 705},
+ dictWord{11, 10, 1017},
+ dictWord{12, 10, 123},
+ dictWord{12, 10, 340},
+ dictWord{12, 10, 406},
+ dictWord{12, 10, 643},
+ dictWord{13, 10, 61},
+ dictWord{13, 10, 269},
+ dictWord{
+ 13,
+ 10,
+ 311,
+ },
+ dictWord{13, 10, 319},
+ dictWord{13, 10, 486},
+ dictWord{14, 10, 234},
+ dictWord{15, 10, 62},
+ dictWord{15, 10, 85},
+ dictWord{16, 10, 71},
+ dictWord{
+ 18,
+ 10,
+ 119,
+ },
+ dictWord{148, 10, 105},
+ dictWord{150, 0, 37},
+ dictWord{4, 11, 208},
+ dictWord{5, 11, 106},
+ dictWord{6, 11, 531},
+ dictWord{8, 11, 408},
+ dictWord{
+ 9,
+ 11,
+ 188,
+ },
+ dictWord{138, 11, 572},
+ dictWord{132, 0, 564},
+ dictWord{6, 0, 513},
+ dictWord{135, 0, 1052},
+ dictWord{132, 0, 825},
+ dictWord{9, 0, 899},
+ dictWord{
+ 140,
+ 11,
+ 441,
+ },
+ dictWord{134, 0, 778},
+ dictWord{133, 11, 379},
+ dictWord{7, 0, 1417},
+ dictWord{12, 0, 382},
+ dictWord{17, 0, 48},
+ dictWord{152, 0, 12},
+ dictWord{
+ 132,
+ 11,
+ 241,
+ },
+ dictWord{7, 0, 1116},
+ dictWord{6, 10, 379},
+ dictWord{7, 10, 270},
+ dictWord{8, 10, 176},
+ dictWord{8, 10, 183},
+ dictWord{9, 10, 432},
+ dictWord{
+ 9,
+ 10,
+ 661,
+ },
+ dictWord{12, 10, 247},
+ dictWord{12, 10, 617},
+ dictWord{146, 10, 125},
+ dictWord{5, 10, 792},
+ dictWord{133, 10, 900},
+ dictWord{6, 0, 545},
+ dictWord{
+ 7,
+ 0,
+ 565,
+ },
+ dictWord{7, 0, 1669},
+ dictWord{10, 0, 114},
+ dictWord{11, 0, 642},
+ dictWord{140, 0, 618},
+ dictWord{133, 0, 5},
+ dictWord{138, 11, 7},
+ dictWord{
+ 132,
+ 11,
+ 259,
+ },
+ dictWord{135, 0, 192},
+ dictWord{134, 0, 701},
+ dictWord{136, 0, 763},
+ dictWord{135, 10, 1979},
+ dictWord{4, 10, 901},
+ dictWord{133, 10, 776},
+ dictWord{10, 0, 755},
+ dictWord{147, 0, 29},
+ dictWord{133, 0, 759},
+ dictWord{4, 11, 173},
+ dictWord{5, 11, 312},
+ dictWord{5, 11, 512},
+ dictWord{135, 11, 1285},
+ dictWord{7, 11, 1603},
+ dictWord{7, 11, 1691},
+ dictWord{9, 11, 464},
+ dictWord{11, 11, 195},
+ dictWord{12, 11, 279},
+ dictWord{12, 11, 448},
+ dictWord{
+ 14,
+ 11,
+ 11,
+ },
+ dictWord{147, 11, 102},
+ dictWord{7, 0, 370},
+ dictWord{7, 0, 1007},
+ dictWord{7, 0, 1177},
+ dictWord{135, 0, 1565},
+ dictWord{135, 0, 1237},
+ dictWord{
+ 4,
+ 0,
+ 87,
+ },
+ dictWord{5, 0, 250},
+ dictWord{141, 0, 298},
+ dictWord{4, 11, 452},
+ dictWord{5, 11, 583},
+ dictWord{5, 11, 817},
+ dictWord{6, 11, 433},
+ dictWord{7, 11, 593},
+ dictWord{7, 11, 720},
+ dictWord{7, 11, 1378},
+ dictWord{8, 11, 161},
+ dictWord{9, 11, 284},
+ dictWord{10, 11, 313},
+ dictWord{139, 11, 886},
+ dictWord{4, 11, 547},
+ dictWord{135, 11, 1409},
+ dictWord{136, 11, 722},
+ dictWord{4, 10, 37},
+ dictWord{5, 10, 334},
+ dictWord{135, 10, 1253},
+ dictWord{132, 10, 508},
+ dictWord{
+ 12,
+ 0,
+ 107,
+ },
+ dictWord{146, 0, 31},
+ dictWord{8, 11, 420},
+ dictWord{139, 11, 193},
+ dictWord{135, 0, 814},
+ dictWord{135, 11, 409},
+ dictWord{140, 0, 991},
+ dictWord{4, 0, 57},
+ dictWord{7, 0, 1195},
+ dictWord{7, 0, 1438},
+ dictWord{7, 0, 1548},
+ dictWord{7, 0, 1835},
+ dictWord{7, 0, 1904},
+ dictWord{9, 0, 757},
+ dictWord{
+ 10,
+ 0,
+ 604,
+ },
+ dictWord{139, 0, 519},
+ dictWord{132, 0, 540},
+ dictWord{138, 11, 308},
+ dictWord{132, 10, 533},
+ dictWord{136, 0, 608},
+ dictWord{144, 11, 65},
+ dictWord{4, 0, 1014},
+ dictWord{134, 0, 2029},
+ dictWord{4, 0, 209},
+ dictWord{7, 0, 902},
+ dictWord{5, 11, 1002},
+ dictWord{136, 11, 745},
+ dictWord{134, 0, 2030},
+ dictWord{6, 0, 303},
+ dictWord{7, 0, 335},
+ dictWord{7, 0, 1437},
+ dictWord{7, 0, 1668},
+ dictWord{8, 0, 553},
+ dictWord{8, 0, 652},
+ dictWord{8, 0, 656},
+ dictWord{
+ 9,
+ 0,
+ 558,
+ },
+ dictWord{11, 0, 743},
+ dictWord{149, 0, 18},
+ dictWord{5, 11, 575},
+ dictWord{6, 11, 354},
+ dictWord{135, 11, 701},
+ dictWord{4, 11, 239},
+ dictWord{
+ 6,
+ 11,
+ 477,
+ },
+ dictWord{7, 11, 1607},
+ dictWord{11, 11, 68},
+ dictWord{139, 11, 617},
+ dictWord{132, 0, 559},
+ dictWord{8, 0, 527},
+ dictWord{18, 0, 60},
+ dictWord{
+ 147,
+ 0,
+ 24,
+ },
+ dictWord{133, 10, 920},
+ dictWord{138, 0, 511},
+ dictWord{133, 0, 1017},
+ dictWord{133, 0, 675},
+ dictWord{138, 10, 391},
+ dictWord{11, 0, 156},
+ dictWord{135, 10, 1952},
+ dictWord{138, 11, 369},
+ dictWord{132, 11, 367},
+ dictWord{133, 0, 709},
+ dictWord{6, 0, 698},
+ dictWord{134, 0, 887},
+ dictWord{
+ 142,
+ 10,
+ 126,
+ },
+ dictWord{134, 0, 1745},
+ dictWord{132, 10, 483},
+ dictWord{13, 11, 299},
+ dictWord{142, 11, 75},
+ dictWord{133, 0, 714},
+ dictWord{7, 0, 8},
+ dictWord{
+ 136,
+ 0,
+ 206,
+ },
+ dictWord{138, 10, 480},
+ dictWord{4, 11, 694},
+ dictWord{9, 10, 495},
+ dictWord{146, 10, 104},
+ dictWord{7, 11, 1248},
+ dictWord{11, 11, 621},
+ dictWord{139, 11, 702},
+ dictWord{140, 11, 687},
+ dictWord{132, 0, 776},
+ dictWord{139, 10, 1009},
+ dictWord{135, 0, 1272},
+ dictWord{134, 0, 1059},
+ dictWord{
+ 8,
+ 10,
+ 653,
+ },
+ dictWord{13, 10, 93},
+ dictWord{147, 10, 14},
+ dictWord{135, 11, 213},
+ dictWord{136, 0, 406},
+ dictWord{133, 10, 172},
+ dictWord{132, 0, 947},
+ dictWord{8, 0, 175},
+ dictWord{10, 0, 168},
+ dictWord{138, 0, 573},
+ dictWord{132, 0, 870},
+ dictWord{6, 0, 1567},
+ dictWord{151, 11, 28},
+ dictWord{
+ 134,
+ 11,
+ 472,
+ },
+ dictWord{5, 10, 260},
+ dictWord{136, 11, 132},
+ dictWord{4, 11, 751},
+ dictWord{11, 11, 390},
+ dictWord{140, 11, 32},
+ dictWord{4, 11, 409},
+ dictWord{
+ 133,
+ 11,
+ 78,
+ },
+ dictWord{12, 0, 554},
+ dictWord{6, 11, 473},
+ dictWord{145, 11, 105},
+ dictWord{133, 0, 784},
+ dictWord{8, 0, 908},
+ dictWord{136, 11, 306},
+ dictWord{139, 0, 882},
+ dictWord{6, 0, 358},
+ dictWord{7, 0, 1393},
+ dictWord{8, 0, 396},
+ dictWord{10, 0, 263},
+ dictWord{14, 0, 154},
+ dictWord{16, 0, 48},
+ dictWord{
+ 17,
+ 0,
+ 8,
+ },
+ dictWord{7, 11, 1759},
+ dictWord{8, 11, 396},
+ dictWord{10, 11, 263},
+ dictWord{14, 11, 154},
+ dictWord{16, 11, 48},
+ dictWord{145, 11, 8},
+ dictWord{
+ 13,
+ 11,
+ 163,
+ },
+ dictWord{13, 11, 180},
+ dictWord{18, 11, 78},
+ dictWord{148, 11, 35},
+ dictWord{14, 0, 32},
+ dictWord{18, 0, 85},
+ dictWord{20, 0, 2},
+ dictWord{152, 0, 16},
+ dictWord{7, 0, 228},
+ dictWord{10, 0, 770},
+ dictWord{8, 10, 167},
+ dictWord{8, 10, 375},
+ dictWord{9, 10, 82},
+ dictWord{9, 10, 561},
+ dictWord{138, 10, 620},
+ dictWord{132, 0, 845},
+ dictWord{9, 0, 14},
+ dictWord{9, 0, 441},
+ dictWord{10, 0, 306},
+ dictWord{139, 0, 9},
+ dictWord{11, 0, 966},
+ dictWord{12, 0, 287},
+ dictWord{
+ 13,
+ 0,
+ 342,
+ },
+ dictWord{13, 0, 402},
+ dictWord{15, 0, 110},
+ dictWord{15, 0, 163},
+ dictWord{8, 10, 194},
+ dictWord{136, 10, 756},
+ dictWord{134, 0, 1578},
+ dictWord{
+ 4,
+ 0,
+ 967,
+ },
+ dictWord{6, 0, 1820},
+ dictWord{6, 0, 1847},
+ dictWord{140, 0, 716},
+ dictWord{136, 0, 594},
+ dictWord{7, 0, 1428},
+ dictWord{7, 0, 1640},
+ dictWord{
+ 7,
+ 0,
+ 1867,
+ },
+ dictWord{9, 0, 169},
+ dictWord{9, 0, 182},
+ dictWord{9, 0, 367},
+ dictWord{9, 0, 478},
+ dictWord{9, 0, 506},
+ dictWord{9, 0, 551},
+ dictWord{9, 0, 557},
+ dictWord{
+ 9,
+ 0,
+ 648,
+ },
+ dictWord{9, 0, 697},
+ dictWord{9, 0, 705},
+ dictWord{9, 0, 725},
+ dictWord{9, 0, 787},
+ dictWord{9, 0, 794},
+ dictWord{10, 0, 198},
+ dictWord{10, 0, 214},
+ dictWord{10, 0, 267},
+ dictWord{10, 0, 275},
+ dictWord{10, 0, 456},
+ dictWord{10, 0, 551},
+ dictWord{10, 0, 561},
+ dictWord{10, 0, 613},
+ dictWord{10, 0, 627},
+ dictWord{
+ 10,
+ 0,
+ 668,
+ },
+ dictWord{10, 0, 675},
+ dictWord{10, 0, 691},
+ dictWord{10, 0, 695},
+ dictWord{10, 0, 707},
+ dictWord{10, 0, 715},
+ dictWord{11, 0, 183},
+ dictWord{
+ 11,
+ 0,
+ 201,
+ },
+ dictWord{11, 0, 244},
+ dictWord{11, 0, 262},
+ dictWord{11, 0, 352},
+ dictWord{11, 0, 439},
+ dictWord{11, 0, 493},
+ dictWord{11, 0, 572},
+ dictWord{11, 0, 591},
+ dictWord{11, 0, 608},
+ dictWord{11, 0, 611},
+ dictWord{11, 0, 646},
+ dictWord{11, 0, 674},
+ dictWord{11, 0, 711},
+ dictWord{11, 0, 751},
+ dictWord{11, 0, 761},
+ dictWord{11, 0, 776},
+ dictWord{11, 0, 785},
+ dictWord{11, 0, 850},
+ dictWord{11, 0, 853},
+ dictWord{11, 0, 862},
+ dictWord{11, 0, 865},
+ dictWord{11, 0, 868},
+ dictWord{
+ 11,
+ 0,
+ 875,
+ },
+ dictWord{11, 0, 898},
+ dictWord{11, 0, 902},
+ dictWord{11, 0, 903},
+ dictWord{11, 0, 910},
+ dictWord{11, 0, 932},
+ dictWord{11, 0, 942},
+ dictWord{
+ 11,
+ 0,
+ 957,
+ },
+ dictWord{11, 0, 967},
+ dictWord{11, 0, 972},
+ dictWord{12, 0, 148},
+ dictWord{12, 0, 195},
+ dictWord{12, 0, 220},
+ dictWord{12, 0, 237},
+ dictWord{12, 0, 318},
+ dictWord{12, 0, 339},
+ dictWord{12, 0, 393},
+ dictWord{12, 0, 445},
+ dictWord{12, 0, 450},
+ dictWord{12, 0, 474},
+ dictWord{12, 0, 505},
+ dictWord{12, 0, 509},
+ dictWord{12, 0, 533},
+ dictWord{12, 0, 591},
+ dictWord{12, 0, 594},
+ dictWord{12, 0, 597},
+ dictWord{12, 0, 621},
+ dictWord{12, 0, 633},
+ dictWord{12, 0, 642},
+ dictWord{
+ 13,
+ 0,
+ 59,
+ },
+ dictWord{13, 0, 60},
+ dictWord{13, 0, 145},
+ dictWord{13, 0, 239},
+ dictWord{13, 0, 250},
+ dictWord{13, 0, 329},
+ dictWord{13, 0, 344},
+ dictWord{13, 0, 365},
+ dictWord{13, 0, 372},
+ dictWord{13, 0, 387},
+ dictWord{13, 0, 403},
+ dictWord{13, 0, 414},
+ dictWord{13, 0, 456},
+ dictWord{13, 0, 470},
+ dictWord{13, 0, 478},
+ dictWord{13, 0, 483},
+ dictWord{13, 0, 489},
+ dictWord{14, 0, 55},
+ dictWord{14, 0, 57},
+ dictWord{14, 0, 81},
+ dictWord{14, 0, 90},
+ dictWord{14, 0, 148},
+ dictWord{
+ 14,
+ 0,
+ 239,
+ },
+ dictWord{14, 0, 266},
+ dictWord{14, 0, 321},
+ dictWord{14, 0, 326},
+ dictWord{14, 0, 327},
+ dictWord{14, 0, 330},
+ dictWord{14, 0, 347},
+ dictWord{14, 0, 355},
+ dictWord{14, 0, 401},
+ dictWord{14, 0, 404},
+ dictWord{14, 0, 411},
+ dictWord{14, 0, 414},
+ dictWord{14, 0, 416},
+ dictWord{14, 0, 420},
+ dictWord{15, 0, 61},
+ dictWord{15, 0, 74},
+ dictWord{15, 0, 87},
+ dictWord{15, 0, 88},
+ dictWord{15, 0, 94},
+ dictWord{15, 0, 96},
+ dictWord{15, 0, 116},
+ dictWord{15, 0, 149},
+ dictWord{15, 0, 154},
+ dictWord{16, 0, 50},
+ dictWord{16, 0, 63},
+ dictWord{16, 0, 73},
+ dictWord{17, 0, 2},
+ dictWord{17, 0, 66},
+ dictWord{17, 0, 92},
+ dictWord{17, 0, 103},
+ dictWord{
+ 17,
+ 0,
+ 112,
+ },
+ dictWord{17, 0, 120},
+ dictWord{18, 0, 50},
+ dictWord{18, 0, 54},
+ dictWord{18, 0, 82},
+ dictWord{18, 0, 86},
+ dictWord{18, 0, 90},
+ dictWord{18, 0, 111},
+ dictWord{
+ 18,
+ 0,
+ 115,
+ },
+ dictWord{18, 0, 156},
+ dictWord{19, 0, 40},
+ dictWord{19, 0, 79},
+ dictWord{20, 0, 78},
+ dictWord{21, 0, 22},
+ dictWord{135, 11, 883},
+ dictWord{5, 0, 161},
+ dictWord{135, 0, 839},
+ dictWord{4, 0, 782},
+ dictWord{13, 11, 293},
+ dictWord{142, 11, 56},
+ dictWord{133, 11, 617},
+ dictWord{139, 11, 50},
+ dictWord{
+ 135,
+ 10,
+ 22,
+ },
+ dictWord{145, 0, 64},
+ dictWord{5, 10, 639},
+ dictWord{7, 10, 1249},
+ dictWord{139, 10, 896},
+ dictWord{138, 0, 998},
+ dictWord{135, 11, 2042},
+ dictWord{
+ 4,
+ 11,
+ 546,
+ },
+ dictWord{142, 11, 233},
+ dictWord{6, 0, 1043},
+ dictWord{134, 0, 1574},
+ dictWord{134, 0, 1496},
+ dictWord{4, 10, 102},
+ dictWord{7, 10, 815},
+ dictWord{7, 10, 1699},
+ dictWord{139, 10, 964},
+ dictWord{12, 0, 781},
+ dictWord{142, 0, 461},
+ dictWord{4, 11, 313},
+ dictWord{133, 11, 577},
+ dictWord{
+ 6,
+ 0,
+ 639,
+ },
+ dictWord{6, 0, 1114},
+ dictWord{137, 0, 817},
+ dictWord{8, 11, 184},
+ dictWord{141, 11, 433},
+ dictWord{7, 0, 1814},
+ dictWord{135, 11, 935},
+ dictWord{
+ 10,
+ 0,
+ 997,
+ },
+ dictWord{140, 0, 958},
+ dictWord{4, 0, 812},
+ dictWord{137, 11, 625},
+ dictWord{132, 10, 899},
+ dictWord{136, 10, 795},
+ dictWord{5, 11, 886},
+ dictWord{6, 11, 46},
+ dictWord{6, 11, 1790},
+ dictWord{7, 11, 14},
+ dictWord{7, 11, 732},
+ dictWord{7, 11, 1654},
+ dictWord{8, 11, 95},
+ dictWord{8, 11, 327},
+ dictWord{
+ 8,
+ 11,
+ 616,
+ },
+ dictWord{10, 11, 598},
+ dictWord{10, 11, 769},
+ dictWord{11, 11, 134},
+ dictWord{11, 11, 747},
+ dictWord{12, 11, 378},
+ dictWord{142, 11, 97},
+ dictWord{136, 0, 139},
+ dictWord{6, 10, 52},
+ dictWord{9, 10, 104},
+ dictWord{9, 10, 559},
+ dictWord{12, 10, 308},
+ dictWord{147, 10, 87},
+ dictWord{133, 11, 1021},
+ dictWord{132, 10, 604},
+ dictWord{132, 10, 301},
+ dictWord{136, 10, 779},
+ dictWord{7, 0, 643},
+ dictWord{136, 0, 236},
+ dictWord{132, 11, 153},
+ dictWord{
+ 134,
+ 0,
+ 1172,
+ },
+ dictWord{147, 10, 32},
+ dictWord{133, 11, 798},
+ dictWord{6, 0, 1338},
+ dictWord{132, 11, 587},
+ dictWord{6, 11, 598},
+ dictWord{7, 11, 42},
+ dictWord{
+ 8,
+ 11,
+ 695,
+ },
+ dictWord{10, 11, 212},
+ dictWord{11, 11, 158},
+ dictWord{14, 11, 196},
+ dictWord{145, 11, 85},
+ dictWord{135, 10, 508},
+ dictWord{5, 11, 957},
+ dictWord{5, 11, 1008},
+ dictWord{135, 11, 249},
+ dictWord{4, 11, 129},
+ dictWord{135, 11, 465},
+ dictWord{5, 0, 54},
+ dictWord{7, 11, 470},
+ dictWord{7, 11, 1057},
+ dictWord{7, 11, 1201},
+ dictWord{9, 11, 755},
+ dictWord{11, 11, 906},
+ dictWord{140, 11, 527},
+ dictWord{7, 11, 908},
+ dictWord{146, 11, 7},
+ dictWord{
+ 5,
+ 11,
+ 148,
+ },
+ dictWord{136, 11, 450},
+ dictWord{144, 11, 1},
+ dictWord{4, 0, 256},
+ dictWord{135, 0, 1488},
+ dictWord{9, 0, 351},
+ dictWord{6, 10, 310},
+ dictWord{
+ 7,
+ 10,
+ 1849,
+ },
+ dictWord{8, 10, 72},
+ dictWord{8, 10, 272},
+ dictWord{8, 10, 431},
+ dictWord{9, 10, 12},
+ dictWord{10, 10, 563},
+ dictWord{10, 10, 630},
+ dictWord{
+ 10,
+ 10,
+ 796,
+ },
+ dictWord{10, 10, 810},
+ dictWord{11, 10, 367},
+ dictWord{11, 10, 599},
+ dictWord{11, 10, 686},
+ dictWord{140, 10, 672},
+ dictWord{6, 0, 1885},
+ dictWord{
+ 6,
+ 0,
+ 1898,
+ },
+ dictWord{6, 0, 1899},
+ dictWord{140, 0, 955},
+ dictWord{4, 0, 714},
+ dictWord{133, 0, 469},
+ dictWord{6, 0, 1270},
+ dictWord{134, 0, 1456},
+ dictWord{132, 0, 744},
+ dictWord{6, 0, 313},
+ dictWord{7, 10, 537},
+ dictWord{8, 10, 64},
+ dictWord{9, 10, 127},
+ dictWord{10, 10, 496},
+ dictWord{12, 10, 510},
+ dictWord{141, 10, 384},
+ dictWord{4, 11, 217},
+ dictWord{4, 10, 244},
+ dictWord{5, 11, 710},
+ dictWord{7, 10, 233},
+ dictWord{7, 11, 1926},
+ dictWord{9, 11, 428},
+ dictWord{9, 11, 708},
+ dictWord{10, 11, 254},
+ dictWord{10, 11, 296},
+ dictWord{10, 11, 720},
+ dictWord{11, 11, 109},
+ dictWord{11, 11, 255},
+ dictWord{12, 11, 165},
+ dictWord{12, 11, 315},
+ dictWord{13, 11, 107},
+ dictWord{13, 11, 203},
+ dictWord{14, 11, 54},
+ dictWord{14, 11, 99},
+ dictWord{14, 11, 114},
+ dictWord{
+ 14,
+ 11,
+ 388,
+ },
+ dictWord{16, 11, 85},
+ dictWord{17, 11, 9},
+ dictWord{17, 11, 33},
+ dictWord{20, 11, 25},
+ dictWord{20, 11, 28},
+ dictWord{20, 11, 29},
+ dictWord{21, 11, 9},
+ dictWord{21, 11, 10},
+ dictWord{21, 11, 34},
+ dictWord{150, 11, 17},
+ dictWord{138, 0, 402},
+ dictWord{7, 0, 969},
+ dictWord{146, 0, 55},
+ dictWord{8, 0, 50},
+ dictWord{
+ 137,
+ 0,
+ 624,
+ },
+ dictWord{134, 0, 1355},
+ dictWord{132, 0, 572},
+ dictWord{134, 10, 1650},
+ dictWord{10, 10, 702},
+ dictWord{139, 10, 245},
+ dictWord{
+ 10,
+ 0,
+ 847,
+ },
+ dictWord{142, 0, 445},
+ dictWord{6, 0, 43},
+ dictWord{7, 0, 38},
+ dictWord{8, 0, 248},
+ dictWord{138, 0, 513},
+ dictWord{133, 0, 369},
+ dictWord{137, 10, 338},
+ dictWord{133, 0, 766},
+ dictWord{133, 0, 363},
+ dictWord{133, 10, 896},
+ dictWord{8, 11, 392},
+ dictWord{11, 11, 54},
+ dictWord{13, 11, 173},
+ dictWord{
+ 13,
+ 11,
+ 294,
+ },
+ dictWord{148, 11, 7},
+ dictWord{134, 0, 678},
+ dictWord{7, 11, 1230},
+ dictWord{136, 11, 531},
+ dictWord{6, 0, 258},
+ dictWord{140, 0, 409},
+ dictWord{
+ 5,
+ 0,
+ 249,
+ },
+ dictWord{148, 0, 82},
+ dictWord{7, 10, 1117},
+ dictWord{136, 10, 539},
+ dictWord{5, 0, 393},
+ dictWord{6, 0, 378},
+ dictWord{7, 0, 1981},
+ dictWord{9, 0, 32},
+ dictWord{9, 0, 591},
+ dictWord{10, 0, 685},
+ dictWord{10, 0, 741},
+ dictWord{142, 0, 382},
+ dictWord{133, 0, 788},
+ dictWord{134, 0, 1281},
+ dictWord{
+ 134,
+ 0,
+ 1295,
+ },
+ dictWord{7, 0, 1968},
+ dictWord{141, 0, 509},
+ dictWord{4, 0, 61},
+ dictWord{5, 0, 58},
+ dictWord{5, 0, 171},
+ dictWord{5, 0, 683},
+ dictWord{6, 0, 291},
+ dictWord{
+ 6,
+ 0,
+ 566,
+ },
+ dictWord{7, 0, 1650},
+ dictWord{11, 0, 523},
+ dictWord{12, 0, 273},
+ dictWord{12, 0, 303},
+ dictWord{15, 0, 39},
+ dictWord{143, 0, 111},
+ dictWord{
+ 6,
+ 0,
+ 706,
+ },
+ dictWord{134, 0, 1283},
+ dictWord{134, 0, 589},
+ dictWord{135, 11, 1433},
+ dictWord{133, 11, 435},
+ dictWord{7, 0, 1059},
+ dictWord{13, 0, 54},
+ dictWord{
+ 5,
+ 10,
+ 4,
+ },
+ dictWord{5, 10, 810},
+ dictWord{6, 10, 13},
+ dictWord{6, 10, 538},
+ dictWord{6, 10, 1690},
+ dictWord{6, 10, 1726},
+ dictWord{7, 10, 1819},
+ dictWord{
+ 8,
+ 10,
+ 148,
+ },
+ dictWord{8, 10, 696},
+ dictWord{8, 10, 791},
+ dictWord{12, 10, 125},
+ dictWord{143, 10, 9},
+ dictWord{135, 10, 1268},
+ dictWord{5, 11, 85},
+ dictWord{
+ 6,
+ 11,
+ 419,
+ },
+ dictWord{7, 11, 134},
+ dictWord{7, 11, 305},
+ dictWord{7, 11, 361},
+ dictWord{7, 11, 1337},
+ dictWord{8, 11, 71},
+ dictWord{140, 11, 519},
+ dictWord{
+ 137,
+ 0,
+ 824,
+ },
+ dictWord{140, 11, 688},
+ dictWord{5, 11, 691},
+ dictWord{7, 11, 345},
+ dictWord{7, 10, 1385},
+ dictWord{9, 11, 94},
+ dictWord{11, 10, 582},
+ dictWord{
+ 11,
+ 10,
+ 650,
+ },
+ dictWord{11, 10, 901},
+ dictWord{11, 10, 949},
+ dictWord{12, 11, 169},
+ dictWord{12, 10, 232},
+ dictWord{12, 10, 236},
+ dictWord{13, 10, 413},
+ dictWord{13, 10, 501},
+ dictWord{146, 10, 116},
+ dictWord{4, 0, 917},
+ dictWord{133, 0, 1005},
+ dictWord{7, 0, 1598},
+ dictWord{5, 11, 183},
+ dictWord{6, 11, 582},
+ dictWord{9, 11, 344},
+ dictWord{10, 11, 679},
+ dictWord{140, 11, 435},
+ dictWord{4, 10, 925},
+ dictWord{5, 10, 803},
+ dictWord{8, 10, 698},
+ dictWord{
+ 138,
+ 10,
+ 828,
+ },
+ dictWord{132, 0, 919},
+ dictWord{135, 11, 511},
+ dictWord{139, 10, 992},
+ dictWord{4, 0, 255},
+ dictWord{5, 0, 302},
+ dictWord{6, 0, 132},
+ dictWord{
+ 7,
+ 0,
+ 128,
+ },
+ dictWord{7, 0, 283},
+ dictWord{7, 0, 1299},
+ dictWord{10, 0, 52},
+ dictWord{10, 0, 514},
+ dictWord{11, 0, 925},
+ dictWord{13, 0, 92},
+ dictWord{142, 0, 309},
+ dictWord{134, 0, 1369},
+ dictWord{135, 10, 1847},
+ dictWord{134, 0, 328},
+ dictWord{7, 11, 1993},
+ dictWord{136, 11, 684},
+ dictWord{133, 10, 383},
+ dictWord{137, 0, 173},
+ dictWord{134, 11, 583},
+ dictWord{134, 0, 1411},
+ dictWord{19, 0, 65},
+ dictWord{5, 11, 704},
+ dictWord{8, 11, 357},
+ dictWord{10, 11, 745},
+ dictWord{14, 11, 426},
+ dictWord{17, 11, 94},
+ dictWord{147, 11, 57},
+ dictWord{9, 10, 660},
+ dictWord{138, 10, 347},
+ dictWord{4, 11, 179},
+ dictWord{5, 11, 198},
+ dictWord{133, 11, 697},
+ dictWord{7, 11, 347},
+ dictWord{7, 11, 971},
+ dictWord{8, 11, 181},
+ dictWord{138, 11, 711},
+ dictWord{141, 0, 442},
+ dictWord{
+ 11,
+ 0,
+ 842,
+ },
+ dictWord{11, 0, 924},
+ dictWord{13, 0, 317},
+ dictWord{13, 0, 370},
+ dictWord{13, 0, 469},
+ dictWord{13, 0, 471},
+ dictWord{14, 0, 397},
+ dictWord{18, 0, 69},
+ dictWord{18, 0, 145},
+ dictWord{7, 10, 572},
+ dictWord{9, 10, 592},
+ dictWord{11, 10, 680},
+ dictWord{12, 10, 356},
+ dictWord{140, 10, 550},
+ dictWord{14, 11, 19},
+ dictWord{14, 11, 28},
+ dictWord{144, 11, 29},
+ dictWord{136, 0, 534},
+ dictWord{4, 11, 243},
+ dictWord{5, 11, 203},
+ dictWord{7, 11, 19},
+ dictWord{7, 11, 71},
+ dictWord{7, 11, 113},
+ dictWord{10, 11, 405},
+ dictWord{11, 11, 357},
+ dictWord{142, 11, 240},
+ dictWord{6, 0, 210},
+ dictWord{10, 0, 845},
+ dictWord{138, 0, 862},
+ dictWord{7, 11, 1351},
+ dictWord{9, 11, 581},
+ dictWord{10, 11, 639},
+ dictWord{11, 11, 453},
+ dictWord{140, 11, 584},
+ dictWord{7, 11, 1450},
+ dictWord{
+ 139,
+ 11,
+ 99,
+ },
+ dictWord{10, 0, 892},
+ dictWord{12, 0, 719},
+ dictWord{144, 0, 105},
+ dictWord{4, 0, 284},
+ dictWord{6, 0, 223},
+ dictWord{134, 11, 492},
+ dictWord{5, 11, 134},
+ dictWord{6, 11, 408},
+ dictWord{6, 11, 495},
+ dictWord{135, 11, 1593},
+ dictWord{136, 0, 529},
+ dictWord{137, 0, 807},
+ dictWord{4, 0, 218},
+ dictWord{7, 0, 526},
+ dictWord{143, 0, 137},
+ dictWord{6, 0, 1444},
+ dictWord{142, 11, 4},
+ dictWord{132, 11, 665},
+ dictWord{4, 0, 270},
+ dictWord{5, 0, 192},
+ dictWord{6, 0, 332},
+ dictWord{7, 0, 1322},
+ dictWord{4, 11, 248},
+ dictWord{7, 11, 137},
+ dictWord{137, 11, 349},
+ dictWord{140, 0, 661},
+ dictWord{7, 0, 1517},
+ dictWord{11, 0, 597},
+ dictWord{14, 0, 76},
+ dictWord{14, 0, 335},
+ dictWord{20, 0, 33},
+ dictWord{7, 10, 748},
+ dictWord{139, 10, 700},
+ dictWord{5, 11, 371},
+ dictWord{135, 11, 563},
+ dictWord{146, 11, 57},
+ dictWord{133, 10, 127},
+ dictWord{133, 0, 418},
+ dictWord{4, 11, 374},
+ dictWord{7, 11, 547},
+ dictWord{7, 11, 1700},
+ dictWord{7, 11, 1833},
+ dictWord{139, 11, 858},
+ dictWord{6, 10, 198},
+ dictWord{140, 10, 83},
+ dictWord{7, 11, 1812},
+ dictWord{13, 11, 259},
+ dictWord{13, 11, 356},
+ dictWord{
+ 14,
+ 11,
+ 242,
+ },
+ dictWord{147, 11, 114},
+ dictWord{7, 0, 379},
+ dictWord{8, 0, 481},
+ dictWord{9, 0, 377},
+ dictWord{5, 10, 276},
+ dictWord{6, 10, 55},
+ dictWord{
+ 135,
+ 10,
+ 1369,
+ },
+ dictWord{138, 11, 286},
+ dictWord{5, 0, 1003},
+ dictWord{6, 0, 149},
+ dictWord{6, 10, 1752},
+ dictWord{136, 10, 726},
+ dictWord{8, 0, 262},
+ dictWord{
+ 9,
+ 0,
+ 627,
+ },
+ dictWord{10, 0, 18},
+ dictWord{11, 0, 214},
+ dictWord{11, 0, 404},
+ dictWord{11, 0, 457},
+ dictWord{11, 0, 780},
+ dictWord{11, 0, 913},
+ dictWord{13, 0, 401},
+ dictWord{14, 0, 200},
+ dictWord{6, 11, 1647},
+ dictWord{7, 11, 1552},
+ dictWord{7, 11, 2010},
+ dictWord{9, 11, 494},
+ dictWord{137, 11, 509},
+ dictWord{
+ 135,
+ 0,
+ 742,
+ },
+ dictWord{136, 0, 304},
+ dictWord{132, 0, 142},
+ dictWord{133, 10, 764},
+ dictWord{6, 10, 309},
+ dictWord{7, 10, 331},
+ dictWord{138, 10, 550},
+ dictWord{135, 10, 1062},
+ dictWord{6, 11, 123},
+ dictWord{7, 11, 214},
+ dictWord{7, 10, 986},
+ dictWord{9, 11, 728},
+ dictWord{10, 11, 157},
+ dictWord{11, 11, 346},
+ dictWord{11, 11, 662},
+ dictWord{143, 11, 106},
+ dictWord{135, 10, 1573},
+ dictWord{7, 0, 925},
+ dictWord{137, 0, 799},
+ dictWord{4, 0, 471},
+ dictWord{5, 0, 51},
+ dictWord{6, 0, 602},
+ dictWord{8, 0, 484},
+ dictWord{138, 0, 195},
+ dictWord{136, 0, 688},
+ dictWord{132, 0, 697},
+ dictWord{6, 0, 1169},
+ dictWord{6, 0, 1241},
+ dictWord{6, 10, 194},
+ dictWord{7, 10, 133},
+ dictWord{10, 10, 493},
+ dictWord{10, 10, 570},
+ dictWord{139, 10, 664},
+ dictWord{140, 0, 751},
+ dictWord{7, 0, 929},
+ dictWord{10, 0, 452},
+ dictWord{11, 0, 878},
+ dictWord{16, 0, 33},
+ dictWord{5, 10, 24},
+ dictWord{5, 10, 569},
+ dictWord{6, 10, 3},
+ dictWord{6, 10, 119},
+ dictWord{
+ 6,
+ 10,
+ 143,
+ },
+ dictWord{6, 10, 440},
+ dictWord{7, 10, 599},
+ dictWord{7, 10, 1686},
+ dictWord{7, 10, 1854},
+ dictWord{8, 10, 424},
+ dictWord{9, 10, 43},
+ dictWord{
+ 9,
+ 10,
+ 584,
+ },
+ dictWord{9, 10, 760},
+ dictWord{10, 10, 328},
+ dictWord{11, 10, 159},
+ dictWord{11, 10, 253},
+ dictWord{12, 10, 487},
+ dictWord{140, 10, 531},
+ dictWord{
+ 4,
+ 11,
+ 707,
+ },
+ dictWord{13, 11, 106},
+ dictWord{18, 11, 49},
+ dictWord{147, 11, 41},
+ dictWord{5, 0, 221},
+ dictWord{5, 11, 588},
+ dictWord{134, 11, 393},
+ dictWord{134, 0, 1437},
+ dictWord{6, 11, 211},
+ dictWord{7, 11, 1690},
+ dictWord{11, 11, 486},
+ dictWord{140, 11, 369},
+ dictWord{5, 10, 14},
+ dictWord{5, 10, 892},
+ dictWord{6, 10, 283},
+ dictWord{7, 10, 234},
+ dictWord{136, 10, 537},
+ dictWord{4, 0, 988},
+ dictWord{136, 0, 955},
+ dictWord{135, 0, 1251},
+ dictWord{4, 10, 126},
+ dictWord{8, 10, 635},
+ dictWord{147, 10, 34},
+ dictWord{4, 10, 316},
+ dictWord{135, 10, 1561},
+ dictWord{137, 10, 861},
+ dictWord{4, 10, 64},
+ dictWord{
+ 5,
+ 10,
+ 352,
+ },
+ dictWord{5, 10, 720},
+ dictWord{6, 10, 368},
+ dictWord{139, 10, 359},
+ dictWord{134, 0, 192},
+ dictWord{4, 0, 132},
+ dictWord{5, 0, 69},
+ dictWord{
+ 135,
+ 0,
+ 1242,
+ },
+ dictWord{7, 10, 1577},
+ dictWord{10, 10, 304},
+ dictWord{10, 10, 549},
+ dictWord{12, 10, 365},
+ dictWord{13, 10, 220},
+ dictWord{13, 10, 240},
+ dictWord{142, 10, 33},
+ dictWord{4, 0, 111},
+ dictWord{7, 0, 865},
+ dictWord{134, 11, 219},
+ dictWord{5, 11, 582},
+ dictWord{6, 11, 1646},
+ dictWord{7, 11, 99},
+ dictWord{
+ 7,
+ 11,
+ 1962,
+ },
+ dictWord{7, 11, 1986},
+ dictWord{8, 11, 515},
+ dictWord{8, 11, 773},
+ dictWord{9, 11, 23},
+ dictWord{9, 11, 491},
+ dictWord{12, 11, 620},
+ dictWord{
+ 14,
+ 11,
+ 52,
+ },
+ dictWord{145, 11, 50},
+ dictWord{132, 0, 767},
+ dictWord{7, 11, 568},
+ dictWord{148, 11, 21},
+ dictWord{6, 0, 42},
+ dictWord{7, 0, 1416},
+ dictWord{
+ 7,
+ 0,
+ 2005,
+ },
+ dictWord{8, 0, 131},
+ dictWord{8, 0, 466},
+ dictWord{9, 0, 672},
+ dictWord{13, 0, 252},
+ dictWord{20, 0, 103},
+ dictWord{133, 11, 851},
+ dictWord{
+ 135,
+ 0,
+ 1050,
+ },
+ dictWord{6, 10, 175},
+ dictWord{137, 10, 289},
+ dictWord{5, 10, 432},
+ dictWord{133, 10, 913},
+ dictWord{6, 0, 44},
+ dictWord{136, 0, 368},
+ dictWord{
+ 135,
+ 11,
+ 784,
+ },
+ dictWord{132, 0, 570},
+ dictWord{133, 0, 120},
+ dictWord{139, 10, 595},
+ dictWord{140, 0, 29},
+ dictWord{6, 0, 227},
+ dictWord{135, 0, 1589},
+ dictWord{4, 11, 98},
+ dictWord{7, 11, 1365},
+ dictWord{9, 11, 422},
+ dictWord{9, 11, 670},
+ dictWord{10, 11, 775},
+ dictWord{11, 11, 210},
+ dictWord{13, 11, 26},
+ dictWord{13, 11, 457},
+ dictWord{141, 11, 476},
+ dictWord{140, 10, 80},
+ dictWord{5, 10, 931},
+ dictWord{134, 10, 1698},
+ dictWord{133, 0, 522},
+ dictWord{
+ 134,
+ 0,
+ 1120,
+ },
+ dictWord{135, 0, 1529},
+ dictWord{12, 0, 739},
+ dictWord{14, 0, 448},
+ dictWord{142, 0, 467},
+ dictWord{11, 10, 526},
+ dictWord{11, 10, 939},
+ dictWord{141, 10, 290},
+ dictWord{5, 10, 774},
+ dictWord{6, 10, 1637},
+ dictWord{6, 10, 1686},
+ dictWord{134, 10, 1751},
+ dictWord{6, 0, 1667},
+ dictWord{
+ 135,
+ 0,
+ 2036,
+ },
+ dictWord{7, 10, 1167},
+ dictWord{11, 10, 934},
+ dictWord{13, 10, 391},
+ dictWord{145, 10, 76},
+ dictWord{137, 11, 147},
+ dictWord{6, 10, 260},
+ dictWord{
+ 7,
+ 10,
+ 1484,
+ },
+ dictWord{11, 11, 821},
+ dictWord{12, 11, 110},
+ dictWord{12, 11, 153},
+ dictWord{18, 11, 41},
+ dictWord{150, 11, 19},
+ dictWord{6, 0, 511},
+ dictWord{12, 0, 132},
+ dictWord{134, 10, 573},
+ dictWord{5, 0, 568},
+ dictWord{6, 0, 138},
+ dictWord{135, 0, 1293},
+ dictWord{132, 0, 1020},
+ dictWord{8, 0, 258},
+ dictWord{9, 0, 208},
+ dictWord{137, 0, 359},
+ dictWord{4, 0, 565},
+ dictWord{8, 0, 23},
+ dictWord{136, 0, 827},
+ dictWord{134, 0, 344},
+ dictWord{4, 0, 922},
+ dictWord{
+ 5,
+ 0,
+ 1023,
+ },
+ dictWord{13, 11, 477},
+ dictWord{14, 11, 120},
+ dictWord{148, 11, 61},
+ dictWord{134, 0, 240},
+ dictWord{5, 11, 209},
+ dictWord{6, 11, 30},
+ dictWord{
+ 11,
+ 11,
+ 56,
+ },
+ dictWord{139, 11, 305},
+ dictWord{6, 0, 171},
+ dictWord{7, 0, 1002},
+ dictWord{7, 0, 1324},
+ dictWord{9, 0, 415},
+ dictWord{14, 0, 230},
+ dictWord{
+ 18,
+ 0,
+ 68,
+ },
+ dictWord{4, 10, 292},
+ dictWord{4, 10, 736},
+ dictWord{5, 10, 871},
+ dictWord{6, 10, 1689},
+ dictWord{7, 10, 1944},
+ dictWord{137, 10, 580},
+ dictWord{
+ 9,
+ 11,
+ 635,
+ },
+ dictWord{139, 11, 559},
+ dictWord{4, 11, 150},
+ dictWord{5, 11, 303},
+ dictWord{134, 11, 327},
+ dictWord{6, 10, 63},
+ dictWord{135, 10, 920},
+ dictWord{
+ 133,
+ 10,
+ 793,
+ },
+ dictWord{8, 11, 192},
+ dictWord{10, 11, 78},
+ dictWord{10, 11, 555},
+ dictWord{11, 11, 308},
+ dictWord{13, 11, 359},
+ dictWord{147, 11, 95},
+ dictWord{135, 11, 786},
+ dictWord{135, 11, 1712},
+ dictWord{136, 0, 402},
+ dictWord{6, 0, 754},
+ dictWord{6, 11, 1638},
+ dictWord{7, 11, 79},
+ dictWord{7, 11, 496},
+ dictWord{9, 11, 138},
+ dictWord{10, 11, 336},
+ dictWord{11, 11, 12},
+ dictWord{12, 11, 412},
+ dictWord{12, 11, 440},
+ dictWord{142, 11, 305},
+ dictWord{4, 0, 716},
+ dictWord{141, 0, 31},
+ dictWord{133, 0, 982},
+ dictWord{8, 0, 691},
+ dictWord{8, 0, 731},
+ dictWord{5, 10, 67},
+ dictWord{6, 10, 62},
+ dictWord{6, 10, 374},
+ dictWord{
+ 135,
+ 10,
+ 1391,
+ },
+ dictWord{9, 10, 790},
+ dictWord{140, 10, 47},
+ dictWord{139, 11, 556},
+ dictWord{151, 11, 1},
+ dictWord{7, 11, 204},
+ dictWord{7, 11, 415},
+ dictWord{8, 11, 42},
+ dictWord{10, 11, 85},
+ dictWord{11, 11, 33},
+ dictWord{11, 11, 564},
+ dictWord{12, 11, 571},
+ dictWord{149, 11, 1},
+ dictWord{8, 0, 888},
+ dictWord{
+ 7,
+ 11,
+ 610,
+ },
+ dictWord{135, 11, 1501},
+ dictWord{4, 10, 391},
+ dictWord{135, 10, 1169},
+ dictWord{5, 0, 847},
+ dictWord{9, 0, 840},
+ dictWord{138, 0, 803},
+ dictWord{137, 0, 823},
+ dictWord{134, 0, 785},
+ dictWord{8, 0, 152},
+ dictWord{9, 0, 53},
+ dictWord{9, 0, 268},
+ dictWord{9, 0, 901},
+ dictWord{10, 0, 518},
+ dictWord{
+ 10,
+ 0,
+ 829,
+ },
+ dictWord{11, 0, 188},
+ dictWord{13, 0, 74},
+ dictWord{14, 0, 46},
+ dictWord{15, 0, 17},
+ dictWord{15, 0, 33},
+ dictWord{17, 0, 40},
+ dictWord{18, 0, 36},
+ dictWord{
+ 19,
+ 0,
+ 20,
+ },
+ dictWord{22, 0, 1},
+ dictWord{152, 0, 2},
+ dictWord{4, 11, 3},
+ dictWord{5, 11, 247},
+ dictWord{5, 11, 644},
+ dictWord{7, 11, 744},
+ dictWord{7, 11, 1207},
+ dictWord{7, 11, 1225},
+ dictWord{7, 11, 1909},
+ dictWord{146, 11, 147},
+ dictWord{136, 0, 532},
+ dictWord{135, 0, 681},
+ dictWord{132, 10, 271},
+ dictWord{
+ 140,
+ 0,
+ 314,
+ },
+ dictWord{140, 0, 677},
+ dictWord{4, 0, 684},
+ dictWord{136, 0, 384},
+ dictWord{5, 11, 285},
+ dictWord{9, 11, 67},
+ dictWord{13, 11, 473},
+ dictWord{
+ 143,
+ 11,
+ 82,
+ },
+ dictWord{4, 10, 253},
+ dictWord{5, 10, 544},
+ dictWord{7, 10, 300},
+ dictWord{137, 10, 340},
+ dictWord{7, 0, 110},
+ dictWord{7, 0, 447},
+ dictWord{8, 0, 290},
+ dictWord{8, 0, 591},
+ dictWord{9, 0, 382},
+ dictWord{9, 0, 649},
+ dictWord{11, 0, 71},
+ dictWord{11, 0, 155},
+ dictWord{11, 0, 313},
+ dictWord{12, 0, 5},
+ dictWord{13, 0, 325},
+ dictWord{142, 0, 287},
+ dictWord{134, 0, 1818},
+ dictWord{136, 0, 1007},
+ dictWord{138, 0, 321},
+ dictWord{7, 0, 360},
+ dictWord{7, 0, 425},
+ dictWord{9, 0, 66},
+ dictWord{9, 0, 278},
+ dictWord{138, 0, 644},
+ dictWord{133, 10, 818},
+ dictWord{5, 0, 385},
+ dictWord{5, 10, 541},
+ dictWord{6, 10, 94},
+ dictWord{6, 10, 499},
+ dictWord{
+ 7,
+ 10,
+ 230,
+ },
+ dictWord{139, 10, 321},
+ dictWord{4, 10, 920},
+ dictWord{5, 10, 25},
+ dictWord{5, 10, 790},
+ dictWord{6, 10, 457},
+ dictWord{7, 10, 853},
+ dictWord{
+ 136,
+ 10,
+ 788,
+ },
+ dictWord{4, 0, 900},
+ dictWord{133, 0, 861},
+ dictWord{5, 0, 254},
+ dictWord{7, 0, 985},
+ dictWord{136, 0, 73},
+ dictWord{7, 0, 1959},
+ dictWord{
+ 136,
+ 0,
+ 683,
+ },
+ dictWord{134, 10, 1765},
+ dictWord{133, 10, 822},
+ dictWord{132, 10, 634},
+ dictWord{4, 11, 29},
+ dictWord{6, 11, 532},
+ dictWord{7, 11, 1628},
+ dictWord{
+ 7,
+ 11,
+ 1648,
+ },
+ dictWord{9, 11, 303},
+ dictWord{9, 11, 350},
+ dictWord{10, 11, 433},
+ dictWord{11, 11, 97},
+ dictWord{11, 11, 557},
+ dictWord{11, 11, 745},
+ dictWord{12, 11, 289},
+ dictWord{12, 11, 335},
+ dictWord{12, 11, 348},
+ dictWord{12, 11, 606},
+ dictWord{13, 11, 116},
+ dictWord{13, 11, 233},
+ dictWord{
+ 13,
+ 11,
+ 466,
+ },
+ dictWord{14, 11, 181},
+ dictWord{14, 11, 209},
+ dictWord{14, 11, 232},
+ dictWord{14, 11, 236},
+ dictWord{14, 11, 300},
+ dictWord{16, 11, 41},
+ dictWord{
+ 148,
+ 11,
+ 97,
+ },
+ dictWord{19, 0, 86},
+ dictWord{6, 10, 36},
+ dictWord{7, 10, 658},
+ dictWord{136, 10, 454},
+ dictWord{135, 11, 1692},
+ dictWord{132, 0, 725},
+ dictWord{
+ 5,
+ 11,
+ 501,
+ },
+ dictWord{7, 11, 1704},
+ dictWord{9, 11, 553},
+ dictWord{11, 11, 520},
+ dictWord{12, 11, 557},
+ dictWord{141, 11, 249},
+ dictWord{134, 0, 196},
+ dictWord{133, 0, 831},
+ dictWord{136, 0, 723},
+ dictWord{7, 0, 1897},
+ dictWord{13, 0, 80},
+ dictWord{13, 0, 437},
+ dictWord{145, 0, 74},
+ dictWord{4, 0, 992},
+ dictWord{
+ 6,
+ 0,
+ 627,
+ },
+ dictWord{136, 0, 994},
+ dictWord{135, 11, 1294},
+ dictWord{132, 10, 104},
+ dictWord{5, 0, 848},
+ dictWord{6, 0, 66},
+ dictWord{136, 0, 764},
+ dictWord{
+ 4,
+ 0,
+ 36,
+ },
+ dictWord{7, 0, 1387},
+ dictWord{10, 0, 205},
+ dictWord{139, 0, 755},
+ dictWord{6, 0, 1046},
+ dictWord{134, 0, 1485},
+ dictWord{134, 0, 950},
+ dictWord{132, 0, 887},
+ dictWord{14, 0, 450},
+ dictWord{148, 0, 111},
+ dictWord{7, 0, 620},
+ dictWord{7, 0, 831},
+ dictWord{9, 10, 542},
+ dictWord{9, 10, 566},
+ dictWord{
+ 138,
+ 10,
+ 728,
+ },
+ dictWord{6, 0, 165},
+ dictWord{138, 0, 388},
+ dictWord{139, 10, 263},
+ dictWord{4, 0, 719},
+ dictWord{135, 0, 155},
+ dictWord{138, 10, 468},
+ dictWord{6, 11, 453},
+ dictWord{144, 11, 36},
+ dictWord{134, 11, 129},
+ dictWord{5, 0, 533},
+ dictWord{7, 0, 755},
+ dictWord{138, 0, 780},
+ dictWord{134, 0, 1465},
+ dictWord{4, 0, 353},
+ dictWord{6, 0, 146},
+ dictWord{6, 0, 1789},
+ dictWord{7, 0, 427},
+ dictWord{7, 0, 990},
+ dictWord{7, 0, 1348},
+ dictWord{9, 0, 665},
+ dictWord{9, 0, 898},
+ dictWord{11, 0, 893},
+ dictWord{142, 0, 212},
+ dictWord{7, 10, 87},
+ dictWord{142, 10, 288},
+ dictWord{4, 0, 45},
+ dictWord{135, 0, 1257},
+ dictWord{12, 0, 7},
+ dictWord{7, 10, 988},
+ dictWord{7, 10, 1939},
+ dictWord{9, 10, 64},
+ dictWord{9, 10, 502},
+ dictWord{12, 10, 34},
+ dictWord{13, 10, 12},
+ dictWord{13, 10, 234},
+ dictWord{147, 10, 77},
+ dictWord{4, 0, 607},
+ dictWord{5, 11, 60},
+ dictWord{6, 11, 504},
+ dictWord{7, 11, 614},
+ dictWord{7, 11, 1155},
+ dictWord{140, 11, 0},
+ dictWord{
+ 135,
+ 10,
+ 141,
+ },
+ dictWord{8, 11, 198},
+ dictWord{11, 11, 29},
+ dictWord{140, 11, 534},
+ dictWord{140, 0, 65},
+ dictWord{136, 0, 816},
+ dictWord{132, 10, 619},
+ dictWord{139, 0, 88},
+ dictWord{5, 10, 246},
+ dictWord{8, 10, 189},
+ dictWord{9, 10, 355},
+ dictWord{9, 10, 512},
+ dictWord{10, 10, 124},
+ dictWord{10, 10, 453},
+ dictWord{11, 10, 143},
+ dictWord{11, 10, 416},
+ dictWord{11, 10, 859},
+ dictWord{141, 10, 341},
+ dictWord{4, 11, 379},
+ dictWord{135, 11, 1397},
+ dictWord{
+ 4,
+ 0,
+ 600,
+ },
+ dictWord{137, 0, 621},
+ dictWord{133, 0, 367},
+ dictWord{134, 0, 561},
+ dictWord{6, 0, 559},
+ dictWord{134, 0, 1691},
+ dictWord{6, 0, 585},
+ dictWord{
+ 134,
+ 11,
+ 585,
+ },
+ dictWord{135, 11, 1228},
+ dictWord{4, 11, 118},
+ dictWord{5, 10, 678},
+ dictWord{6, 11, 274},
+ dictWord{6, 11, 361},
+ dictWord{7, 11, 75},
+ dictWord{
+ 141,
+ 11,
+ 441,
+ },
+ dictWord{135, 11, 1818},
+ dictWord{137, 11, 841},
+ dictWord{5, 0, 573},
+ dictWord{6, 0, 287},
+ dictWord{7, 10, 862},
+ dictWord{7, 10, 1886},
+ dictWord{138, 10, 179},
+ dictWord{132, 10, 517},
+ dictWord{140, 11, 693},
+ dictWord{5, 11, 314},
+ dictWord{6, 11, 221},
+ dictWord{7, 11, 419},
+ dictWord{
+ 10,
+ 11,
+ 650,
+ },
+ dictWord{11, 11, 396},
+ dictWord{12, 11, 156},
+ dictWord{13, 11, 369},
+ dictWord{14, 11, 333},
+ dictWord{145, 11, 47},
+ dictWord{140, 10, 540},
+ dictWord{136, 10, 667},
+ dictWord{11, 10, 403},
+ dictWord{146, 10, 83},
+ dictWord{6, 0, 672},
+ dictWord{133, 10, 761},
+ dictWord{9, 0, 157},
+ dictWord{10, 10, 131},
+ dictWord{140, 10, 72},
+ dictWord{7, 0, 714},
+ dictWord{134, 11, 460},
+ dictWord{134, 0, 456},
+ dictWord{133, 0, 925},
+ dictWord{5, 11, 682},
+ dictWord{
+ 135,
+ 11,
+ 1887,
+ },
+ dictWord{136, 11, 510},
+ dictWord{136, 11, 475},
+ dictWord{133, 11, 1016},
+ dictWord{9, 0, 19},
+ dictWord{7, 11, 602},
+ dictWord{8, 11, 179},
+ dictWord{
+ 10,
+ 11,
+ 781,
+ },
+ dictWord{140, 11, 126},
+ dictWord{6, 11, 329},
+ dictWord{138, 11, 111},
+ dictWord{6, 0, 822},
+ dictWord{134, 0, 1473},
+ dictWord{144, 11, 86},
+ dictWord{11, 0, 113},
+ dictWord{139, 11, 113},
+ dictWord{5, 11, 821},
+ dictWord{134, 11, 1687},
+ dictWord{133, 10, 449},
+ dictWord{7, 0, 463},
+ dictWord{
+ 17,
+ 0,
+ 69,
+ },
+ dictWord{136, 10, 103},
+ dictWord{7, 10, 2028},
+ dictWord{138, 10, 641},
+ dictWord{6, 0, 193},
+ dictWord{7, 0, 240},
+ dictWord{7, 0, 1682},
+ dictWord{
+ 10,
+ 0,
+ 51,
+ },
+ dictWord{10, 0, 640},
+ dictWord{11, 0, 410},
+ dictWord{13, 0, 82},
+ dictWord{14, 0, 247},
+ dictWord{14, 0, 331},
+ dictWord{142, 0, 377},
+ dictWord{6, 0, 471},
+ dictWord{11, 0, 411},
+ dictWord{142, 0, 2},
+ dictWord{5, 11, 71},
+ dictWord{7, 11, 1407},
+ dictWord{9, 11, 388},
+ dictWord{9, 11, 704},
+ dictWord{10, 11, 261},
+ dictWord{
+ 10,
+ 11,
+ 619,
+ },
+ dictWord{11, 11, 547},
+ dictWord{11, 11, 619},
+ dictWord{143, 11, 157},
+ dictWord{136, 0, 633},
+ dictWord{135, 0, 1148},
+ dictWord{6, 0, 554},
+ dictWord{7, 0, 1392},
+ dictWord{12, 0, 129},
+ dictWord{7, 10, 1274},
+ dictWord{7, 10, 1386},
+ dictWord{7, 11, 2008},
+ dictWord{9, 11, 337},
+ dictWord{10, 11, 517},
+ dictWord{146, 10, 87},
+ dictWord{7, 0, 803},
+ dictWord{8, 0, 542},
+ dictWord{6, 10, 187},
+ dictWord{7, 10, 1203},
+ dictWord{8, 10, 380},
+ dictWord{14, 10, 117},
+ dictWord{149, 10, 28},
+ dictWord{6, 10, 297},
+ dictWord{7, 10, 793},
+ dictWord{139, 10, 938},
+ dictWord{8, 0, 438},
+ dictWord{11, 0, 363},
+ dictWord{7, 10, 464},
+ dictWord{11, 10, 105},
+ dictWord{12, 10, 231},
+ dictWord{14, 10, 386},
+ dictWord{15, 10, 102},
+ dictWord{148, 10, 75},
+ dictWord{5, 11, 16},
+ dictWord{6, 11, 86},
+ dictWord{6, 11, 603},
+ dictWord{7, 11, 292},
+ dictWord{7, 11, 561},
+ dictWord{8, 11, 257},
+ dictWord{8, 11, 382},
+ dictWord{9, 11, 721},
+ dictWord{9, 11, 778},
+ dictWord{
+ 11,
+ 11,
+ 581,
+ },
+ dictWord{140, 11, 466},
+ dictWord{6, 0, 717},
+ dictWord{4, 11, 486},
+ dictWord{133, 11, 491},
+ dictWord{132, 0, 875},
+ dictWord{132, 11, 72},
+ dictWord{6, 11, 265},
+ dictWord{135, 11, 847},
+ dictWord{4, 0, 237},
+ dictWord{135, 0, 514},
+ dictWord{6, 0, 392},
+ dictWord{7, 0, 65},
+ dictWord{135, 0, 2019},
+ dictWord{140, 11, 261},
+ dictWord{135, 11, 922},
+ dictWord{137, 11, 404},
+ dictWord{12, 0, 563},
+ dictWord{14, 0, 101},
+ dictWord{18, 0, 129},
+ dictWord{
+ 7,
+ 10,
+ 1010,
+ },
+ dictWord{11, 10, 733},
+ dictWord{11, 10, 759},
+ dictWord{13, 10, 34},
+ dictWord{146, 10, 45},
+ dictWord{7, 10, 1656},
+ dictWord{9, 10, 369},
+ dictWord{
+ 10,
+ 10,
+ 338,
+ },
+ dictWord{10, 10, 490},
+ dictWord{11, 10, 154},
+ dictWord{11, 10, 545},
+ dictWord{11, 10, 775},
+ dictWord{13, 10, 77},
+ dictWord{141, 10, 274},
+ dictWord{4, 0, 444},
+ dictWord{10, 0, 146},
+ dictWord{140, 0, 9},
+ dictWord{139, 11, 163},
+ dictWord{7, 0, 1260},
+ dictWord{135, 0, 1790},
+ dictWord{9, 0, 222},
+ dictWord{10, 0, 43},
+ dictWord{139, 0, 900},
+ dictWord{137, 11, 234},
+ dictWord{138, 0, 971},
+ dictWord{137, 0, 761},
+ dictWord{134, 0, 699},
+ dictWord{
+ 136,
+ 11,
+ 434,
+ },
+ dictWord{6, 0, 1116},
+ dictWord{7, 0, 1366},
+ dictWord{5, 10, 20},
+ dictWord{6, 11, 197},
+ dictWord{6, 10, 298},
+ dictWord{7, 10, 659},
+ dictWord{8, 11, 205},
+ dictWord{137, 10, 219},
+ dictWord{132, 11, 490},
+ dictWord{11, 11, 820},
+ dictWord{150, 11, 51},
+ dictWord{7, 10, 1440},
+ dictWord{11, 10, 854},
+ dictWord{
+ 11,
+ 10,
+ 872,
+ },
+ dictWord{11, 10, 921},
+ dictWord{12, 10, 551},
+ dictWord{13, 10, 472},
+ dictWord{142, 10, 367},
+ dictWord{140, 11, 13},
+ dictWord{132, 0, 829},
+ dictWord{12, 0, 242},
+ dictWord{132, 10, 439},
+ dictWord{136, 10, 669},
+ dictWord{6, 0, 593},
+ dictWord{6, 11, 452},
+ dictWord{7, 11, 312},
+ dictWord{
+ 138,
+ 11,
+ 219,
+ },
+ dictWord{4, 11, 333},
+ dictWord{9, 11, 176},
+ dictWord{12, 11, 353},
+ dictWord{141, 11, 187},
+ dictWord{7, 0, 36},
+ dictWord{8, 0, 201},
+ dictWord{
+ 136,
+ 0,
+ 605,
+ },
+ dictWord{140, 0, 224},
+ dictWord{132, 10, 233},
+ dictWord{134, 0, 1430},
+ dictWord{134, 0, 1806},
+ dictWord{4, 0, 523},
+ dictWord{133, 0, 638},
+ dictWord{
+ 6,
+ 0,
+ 1889,
+ },
+ dictWord{9, 0, 958},
+ dictWord{9, 0, 971},
+ dictWord{9, 0, 976},
+ dictWord{12, 0, 796},
+ dictWord{12, 0, 799},
+ dictWord{12, 0, 808},
+ dictWord{
+ 12,
+ 0,
+ 835,
+ },
+ dictWord{12, 0, 836},
+ dictWord{12, 0, 914},
+ dictWord{12, 0, 946},
+ dictWord{15, 0, 216},
+ dictWord{15, 0, 232},
+ dictWord{18, 0, 183},
+ dictWord{18, 0, 187},
+ dictWord{18, 0, 194},
+ dictWord{18, 0, 212},
+ dictWord{18, 0, 232},
+ dictWord{149, 0, 49},
+ dictWord{132, 10, 482},
+ dictWord{6, 0, 827},
+ dictWord{134, 0, 1434},
+ dictWord{135, 10, 346},
+ dictWord{134, 0, 2043},
+ dictWord{6, 0, 242},
+ dictWord{7, 0, 227},
+ dictWord{7, 0, 1581},
+ dictWord{8, 0, 104},
+ dictWord{9, 0, 113},
+ dictWord{9, 0, 220},
+ dictWord{9, 0, 427},
+ dictWord{10, 0, 136},
+ dictWord{10, 0, 239},
+ dictWord{11, 0, 579},
+ dictWord{11, 0, 1023},
+ dictWord{13, 0, 4},
+ dictWord{
+ 13,
+ 0,
+ 204,
+ },
+ dictWord{13, 0, 316},
+ dictWord{148, 0, 86},
+ dictWord{134, 11, 1685},
+ dictWord{7, 0, 148},
+ dictWord{8, 0, 284},
+ dictWord{141, 0, 63},
+ dictWord{
+ 142,
+ 0,
+ 10,
+ },
+ dictWord{135, 11, 584},
+ dictWord{134, 0, 1249},
+ dictWord{7, 0, 861},
+ dictWord{135, 10, 334},
+ dictWord{5, 10, 795},
+ dictWord{6, 10, 1741},
+ dictWord{
+ 137,
+ 11,
+ 70,
+ },
+ dictWord{132, 0, 807},
+ dictWord{7, 11, 135},
+ dictWord{8, 11, 7},
+ dictWord{8, 11, 62},
+ dictWord{9, 11, 243},
+ dictWord{10, 11, 658},
+ dictWord{
+ 10,
+ 11,
+ 697,
+ },
+ dictWord{11, 11, 456},
+ dictWord{139, 11, 756},
+ dictWord{9, 11, 395},
+ dictWord{138, 11, 79},
+ dictWord{137, 11, 108},
+ dictWord{147, 0, 94},
+ dictWord{136, 0, 494},
+ dictWord{135, 11, 631},
+ dictWord{135, 10, 622},
+ dictWord{7, 0, 1510},
+ dictWord{135, 10, 1750},
+ dictWord{4, 10, 203},
+ dictWord{
+ 135,
+ 10,
+ 1936,
+ },
+ dictWord{7, 11, 406},
+ dictWord{7, 11, 459},
+ dictWord{8, 11, 606},
+ dictWord{139, 11, 726},
+ dictWord{7, 0, 1306},
+ dictWord{8, 0, 505},
+ dictWord{
+ 9,
+ 0,
+ 482,
+ },
+ dictWord{10, 0, 126},
+ dictWord{11, 0, 225},
+ dictWord{12, 0, 347},
+ dictWord{12, 0, 449},
+ dictWord{13, 0, 19},
+ dictWord{14, 0, 218},
+ dictWord{142, 0, 435},
+ dictWord{5, 0, 268},
+ dictWord{10, 0, 764},
+ dictWord{12, 0, 120},
+ dictWord{13, 0, 39},
+ dictWord{145, 0, 127},
+ dictWord{142, 11, 68},
+ dictWord{11, 10, 678},
+ dictWord{140, 10, 307},
+ dictWord{12, 11, 268},
+ dictWord{12, 11, 640},
+ dictWord{142, 11, 119},
+ dictWord{135, 10, 2044},
+ dictWord{133, 11, 612},
+ dictWord{
+ 4,
+ 11,
+ 372,
+ },
+ dictWord{7, 11, 482},
+ dictWord{8, 11, 158},
+ dictWord{9, 11, 602},
+ dictWord{9, 11, 615},
+ dictWord{10, 11, 245},
+ dictWord{10, 11, 678},
+ dictWord{
+ 10,
+ 11,
+ 744,
+ },
+ dictWord{11, 11, 248},
+ dictWord{139, 11, 806},
+ dictWord{7, 10, 311},
+ dictWord{9, 10, 308},
+ dictWord{140, 10, 255},
+ dictWord{4, 0, 384},
+ dictWord{135, 0, 1022},
+ dictWord{5, 11, 854},
+ dictWord{135, 11, 1991},
+ dictWord{135, 10, 1266},
+ dictWord{4, 10, 400},
+ dictWord{5, 10, 267},
+ dictWord{
+ 135,
+ 10,
+ 232,
+ },
+ dictWord{135, 0, 1703},
+ dictWord{9, 0, 159},
+ dictWord{11, 0, 661},
+ dictWord{140, 0, 603},
+ dictWord{4, 0, 964},
+ dictWord{14, 0, 438},
+ dictWord{
+ 14,
+ 0,
+ 444,
+ },
+ dictWord{14, 0, 456},
+ dictWord{22, 0, 60},
+ dictWord{22, 0, 63},
+ dictWord{9, 11, 106},
+ dictWord{9, 11, 163},
+ dictWord{9, 11, 296},
+ dictWord{10, 11, 167},
+ dictWord{10, 11, 172},
+ dictWord{10, 11, 777},
+ dictWord{139, 11, 16},
+ dictWord{136, 0, 583},
+ dictWord{132, 0, 515},
+ dictWord{8, 0, 632},
+ dictWord{8, 0, 697},
+ dictWord{137, 0, 854},
+ dictWord{5, 11, 195},
+ dictWord{135, 11, 1685},
+ dictWord{6, 0, 1123},
+ dictWord{134, 0, 1365},
+ dictWord{134, 11, 328},
+ dictWord{
+ 7,
+ 11,
+ 1997,
+ },
+ dictWord{8, 11, 730},
+ dictWord{139, 11, 1006},
+ dictWord{4, 0, 136},
+ dictWord{133, 0, 551},
+ dictWord{134, 0, 1782},
+ dictWord{7, 0, 1287},
+ dictWord{
+ 9,
+ 0,
+ 44,
+ },
+ dictWord{10, 0, 552},
+ dictWord{10, 0, 642},
+ dictWord{11, 0, 839},
+ dictWord{12, 0, 274},
+ dictWord{12, 0, 275},
+ dictWord{12, 0, 372},
+ dictWord{
+ 13,
+ 0,
+ 91,
+ },
+ dictWord{142, 0, 125},
+ dictWord{5, 11, 751},
+ dictWord{11, 11, 797},
+ dictWord{140, 11, 203},
+ dictWord{133, 0, 732},
+ dictWord{7, 0, 679},
+ dictWord{
+ 8,
+ 0,
+ 313,
+ },
+ dictWord{4, 10, 100},
+ dictWord{135, 11, 821},
+ dictWord{10, 0, 361},
+ dictWord{142, 0, 316},
+ dictWord{134, 0, 595},
+ dictWord{6, 0, 147},
+ dictWord{
+ 7,
+ 0,
+ 886,
+ },
+ dictWord{9, 0, 753},
+ dictWord{138, 0, 268},
+ dictWord{5, 10, 362},
+ dictWord{5, 10, 443},
+ dictWord{6, 10, 318},
+ dictWord{7, 10, 1019},
+ dictWord{
+ 139,
+ 10,
+ 623,
+ },
+ dictWord{5, 10, 463},
+ dictWord{136, 10, 296},
+ dictWord{4, 10, 454},
+ dictWord{5, 11, 950},
+ dictWord{5, 11, 994},
+ dictWord{134, 11, 351},
+ dictWord{
+ 138,
+ 0,
+ 137,
+ },
+ dictWord{5, 10, 48},
+ dictWord{5, 10, 404},
+ dictWord{6, 10, 557},
+ dictWord{7, 10, 458},
+ dictWord{8, 10, 597},
+ dictWord{10, 10, 455},
+ dictWord{
+ 10,
+ 10,
+ 606,
+ },
+ dictWord{11, 10, 49},
+ dictWord{11, 10, 548},
+ dictWord{12, 10, 476},
+ dictWord{13, 10, 18},
+ dictWord{141, 10, 450},
+ dictWord{133, 0, 414},
+ dictWord{
+ 135,
+ 0,
+ 1762,
+ },
+ dictWord{5, 11, 421},
+ dictWord{135, 11, 47},
+ dictWord{5, 10, 442},
+ dictWord{135, 10, 1984},
+ dictWord{134, 0, 599},
+ dictWord{134, 0, 1749},
+ dictWord{134, 0, 1627},
+ dictWord{4, 0, 488},
+ dictWord{132, 11, 350},
+ dictWord{137, 11, 751},
+ dictWord{132, 0, 83},
+ dictWord{140, 0, 676},
+ dictWord{
+ 133,
+ 11,
+ 967,
+ },
+ dictWord{7, 0, 1639},
+ dictWord{5, 10, 55},
+ dictWord{140, 10, 161},
+ dictWord{4, 11, 473},
+ dictWord{7, 11, 623},
+ dictWord{8, 11, 808},
+ dictWord{
+ 9,
+ 11,
+ 871,
+ },
+ dictWord{9, 11, 893},
+ dictWord{11, 11, 38},
+ dictWord{11, 11, 431},
+ dictWord{12, 11, 112},
+ dictWord{12, 11, 217},
+ dictWord{12, 11, 243},
+ dictWord{
+ 12,
+ 11,
+ 562,
+ },
+ dictWord{12, 11, 683},
+ dictWord{13, 11, 141},
+ dictWord{13, 11, 197},
+ dictWord{13, 11, 227},
+ dictWord{13, 11, 406},
+ dictWord{13, 11, 487},
+ dictWord{14, 11, 156},
+ dictWord{14, 11, 203},
+ dictWord{14, 11, 224},
+ dictWord{14, 11, 256},
+ dictWord{18, 11, 58},
+ dictWord{150, 11, 0},
+ dictWord{
+ 133,
+ 10,
+ 450,
+ },
+ dictWord{7, 11, 736},
+ dictWord{139, 11, 264},
+ dictWord{134, 0, 278},
+ dictWord{4, 11, 222},
+ dictWord{7, 11, 286},
+ dictWord{136, 11, 629},
+ dictWord{
+ 135,
+ 10,
+ 869,
+ },
+ dictWord{140, 0, 97},
+ dictWord{144, 0, 14},
+ dictWord{134, 0, 1085},
+ dictWord{4, 10, 213},
+ dictWord{7, 10, 223},
+ dictWord{136, 10, 80},
+ dictWord{
+ 7,
+ 0,
+ 388,
+ },
+ dictWord{7, 0, 644},
+ dictWord{139, 0, 781},
+ dictWord{132, 0, 849},
+ dictWord{7, 0, 229},
+ dictWord{8, 0, 59},
+ dictWord{9, 0, 190},
+ dictWord{10, 0, 378},
+ dictWord{140, 0, 191},
+ dictWord{7, 10, 381},
+ dictWord{7, 10, 806},
+ dictWord{7, 10, 820},
+ dictWord{8, 10, 354},
+ dictWord{8, 10, 437},
+ dictWord{8, 10, 787},
+ dictWord{9, 10, 657},
+ dictWord{10, 10, 58},
+ dictWord{10, 10, 339},
+ dictWord{10, 10, 749},
+ dictWord{11, 10, 914},
+ dictWord{12, 10, 162},
+ dictWord{13, 10, 75},
+ dictWord{14, 10, 106},
+ dictWord{14, 10, 198},
+ dictWord{14, 10, 320},
+ dictWord{14, 10, 413},
+ dictWord{146, 10, 43},
+ dictWord{141, 11, 306},
+ dictWord{
+ 136,
+ 10,
+ 747,
+ },
+ dictWord{134, 0, 1115},
+ dictWord{16, 0, 94},
+ dictWord{16, 0, 108},
+ dictWord{136, 11, 146},
+ dictWord{6, 0, 700},
+ dictWord{6, 0, 817},
+ dictWord{
+ 134,
+ 0,
+ 1002,
+ },
+ dictWord{133, 10, 692},
+ dictWord{4, 11, 465},
+ dictWord{135, 11, 1663},
+ dictWord{134, 10, 191},
+ dictWord{6, 0, 1414},
+ dictWord{
+ 135,
+ 11,
+ 913,
+ },
+ dictWord{132, 0, 660},
+ dictWord{7, 0, 1035},
+ dictWord{138, 0, 737},
+ dictWord{6, 10, 162},
+ dictWord{7, 10, 1960},
+ dictWord{136, 10, 831},
+ dictWord{
+ 132,
+ 10,
+ 706,
+ },
+ dictWord{7, 0, 690},
+ dictWord{9, 0, 217},
+ dictWord{9, 0, 587},
+ dictWord{140, 0, 521},
+ dictWord{138, 10, 426},
+ dictWord{135, 10, 1235},
+ dictWord{
+ 6,
+ 11,
+ 82,
+ },
+ dictWord{7, 11, 138},
+ dictWord{7, 11, 517},
+ dictWord{9, 11, 673},
+ dictWord{139, 11, 238},
+ dictWord{138, 0, 272},
+ dictWord{5, 11, 495},
+ dictWord{
+ 7,
+ 11,
+ 834,
+ },
+ dictWord{9, 11, 733},
+ dictWord{139, 11, 378},
+ dictWord{134, 0, 1744},
+ dictWord{132, 0, 1011},
+ dictWord{7, 11, 828},
+ dictWord{142, 11, 116},
+ dictWord{4, 0, 733},
+ dictWord{9, 0, 194},
+ dictWord{10, 0, 92},
+ dictWord{11, 0, 198},
+ dictWord{12, 0, 84},
+ dictWord{13, 0, 128},
+ dictWord{133, 11, 559},
+ dictWord{
+ 10,
+ 0,
+ 57,
+ },
+ dictWord{10, 0, 277},
+ dictWord{6, 11, 21},
+ dictWord{6, 11, 1737},
+ dictWord{7, 11, 1444},
+ dictWord{136, 11, 224},
+ dictWord{4, 10, 204},
+ dictWord{
+ 137,
+ 10,
+ 902,
+ },
+ dictWord{136, 10, 833},
+ dictWord{11, 0, 348},
+ dictWord{12, 0, 99},
+ dictWord{18, 0, 1},
+ dictWord{18, 0, 11},
+ dictWord{19, 0, 4},
+ dictWord{7, 10, 366},
+ dictWord{9, 10, 287},
+ dictWord{12, 10, 199},
+ dictWord{12, 10, 556},
+ dictWord{140, 10, 577},
+ dictWord{6, 0, 1981},
+ dictWord{136, 0, 936},
+ dictWord{
+ 21,
+ 0,
+ 33,
+ },
+ dictWord{150, 0, 40},
+ dictWord{5, 11, 519},
+ dictWord{138, 11, 204},
+ dictWord{5, 10, 356},
+ dictWord{135, 10, 224},
+ dictWord{134, 0, 775},
+ dictWord{
+ 135,
+ 0,
+ 306,
+ },
+ dictWord{7, 10, 630},
+ dictWord{9, 10, 567},
+ dictWord{11, 10, 150},
+ dictWord{11, 10, 444},
+ dictWord{141, 10, 119},
+ dictWord{5, 0, 979},
+ dictWord{
+ 134,
+ 10,
+ 539,
+ },
+ dictWord{133, 0, 611},
+ dictWord{4, 11, 402},
+ dictWord{135, 11, 1679},
+ dictWord{5, 0, 178},
+ dictWord{7, 11, 2},
+ dictWord{8, 11, 323},
+ dictWord{
+ 136,
+ 11,
+ 479,
+ },
+ dictWord{5, 11, 59},
+ dictWord{135, 11, 672},
+ dictWord{4, 0, 1010},
+ dictWord{6, 0, 1969},
+ dictWord{138, 11, 237},
+ dictWord{133, 11, 412},
+ dictWord{146, 11, 34},
+ dictWord{7, 11, 1740},
+ dictWord{146, 11, 48},
+ dictWord{134, 0, 664},
+ dictWord{139, 10, 814},
+ dictWord{4, 11, 85},
+ dictWord{
+ 135,
+ 11,
+ 549,
+ },
+ dictWord{133, 11, 94},
+ dictWord{133, 11, 457},
+ dictWord{132, 0, 390},
+ dictWord{134, 0, 1510},
+ dictWord{4, 10, 235},
+ dictWord{135, 10, 255},
+ dictWord{4, 10, 194},
+ dictWord{5, 10, 584},
+ dictWord{6, 11, 11},
+ dictWord{6, 10, 384},
+ dictWord{7, 11, 187},
+ dictWord{7, 10, 583},
+ dictWord{10, 10, 761},
+ dictWord{
+ 11,
+ 10,
+ 760,
+ },
+ dictWord{139, 10, 851},
+ dictWord{4, 11, 522},
+ dictWord{139, 11, 802},
+ dictWord{135, 0, 493},
+ dictWord{10, 11, 776},
+ dictWord{13, 11, 345},
+ dictWord{142, 11, 425},
+ dictWord{146, 0, 37},
+ dictWord{4, 11, 52},
+ dictWord{135, 11, 661},
+ dictWord{134, 0, 724},
+ dictWord{134, 0, 829},
+ dictWord{
+ 133,
+ 11,
+ 520,
+ },
+ dictWord{133, 10, 562},
+ dictWord{4, 11, 281},
+ dictWord{5, 11, 38},
+ dictWord{7, 11, 194},
+ dictWord{7, 11, 668},
+ dictWord{7, 11, 1893},
+ dictWord{
+ 137,
+ 11,
+ 397,
+ },
+ dictWord{5, 10, 191},
+ dictWord{137, 10, 271},
+ dictWord{7, 0, 1537},
+ dictWord{14, 0, 96},
+ dictWord{143, 0, 73},
+ dictWord{5, 0, 473},
+ dictWord{
+ 11,
+ 0,
+ 168,
+ },
+ dictWord{4, 10, 470},
+ dictWord{6, 10, 153},
+ dictWord{7, 10, 1503},
+ dictWord{7, 10, 1923},
+ dictWord{10, 10, 701},
+ dictWord{11, 10, 132},
+ dictWord{
+ 11,
+ 10,
+ 227,
+ },
+ dictWord{11, 10, 320},
+ dictWord{11, 10, 436},
+ dictWord{11, 10, 525},
+ dictWord{11, 10, 855},
+ dictWord{12, 10, 41},
+ dictWord{12, 10, 286},
+ dictWord{13, 10, 103},
+ dictWord{13, 10, 284},
+ dictWord{14, 10, 255},
+ dictWord{14, 10, 262},
+ dictWord{15, 10, 117},
+ dictWord{143, 10, 127},
+ dictWord{
+ 133,
+ 0,
+ 105,
+ },
+ dictWord{5, 0, 438},
+ dictWord{9, 0, 694},
+ dictWord{12, 0, 627},
+ dictWord{141, 0, 210},
+ dictWord{133, 10, 327},
+ dictWord{6, 10, 552},
+ dictWord{
+ 7,
+ 10,
+ 1754,
+ },
+ dictWord{137, 10, 604},
+ dictWord{134, 0, 1256},
+ dictWord{152, 0, 11},
+ dictWord{5, 11, 448},
+ dictWord{11, 11, 98},
+ dictWord{139, 11, 524},
+ dictWord{
+ 7,
+ 0,
+ 1626,
+ },
+ dictWord{5, 10, 80},
+ dictWord{6, 10, 405},
+ dictWord{7, 10, 403},
+ dictWord{7, 10, 1502},
+ dictWord{8, 10, 456},
+ dictWord{9, 10, 487},
+ dictWord{
+ 9,
+ 10,
+ 853,
+ },
+ dictWord{9, 10, 889},
+ dictWord{10, 10, 309},
+ dictWord{11, 10, 721},
+ dictWord{11, 10, 994},
+ dictWord{12, 10, 430},
+ dictWord{13, 10, 165},
+ dictWord{
+ 14,
+ 11,
+ 16,
+ },
+ dictWord{146, 11, 44},
+ dictWord{132, 0, 779},
+ dictWord{8, 0, 25},
+ dictWord{138, 0, 826},
+ dictWord{4, 10, 453},
+ dictWord{5, 10, 887},
+ dictWord{
+ 6,
+ 10,
+ 535,
+ },
+ dictWord{8, 10, 6},
+ dictWord{8, 10, 543},
+ dictWord{136, 10, 826},
+ dictWord{137, 11, 461},
+ dictWord{140, 11, 632},
+ dictWord{132, 0, 308},
+ dictWord{135, 0, 741},
+ dictWord{132, 0, 671},
+ dictWord{7, 0, 150},
+ dictWord{8, 0, 649},
+ dictWord{136, 0, 1020},
+ dictWord{9, 0, 99},
+ dictWord{6, 11, 336},
+ dictWord{
+ 8,
+ 11,
+ 552,
+ },
+ dictWord{9, 11, 285},
+ dictWord{10, 11, 99},
+ dictWord{139, 11, 568},
+ dictWord{134, 0, 521},
+ dictWord{5, 0, 339},
+ dictWord{14, 0, 3},
+ dictWord{
+ 15,
+ 0,
+ 41,
+ },
+ dictWord{15, 0, 166},
+ dictWord{147, 0, 66},
+ dictWord{6, 11, 423},
+ dictWord{7, 11, 665},
+ dictWord{7, 11, 1210},
+ dictWord{9, 11, 218},
+ dictWord{
+ 141,
+ 11,
+ 222,
+ },
+ dictWord{6, 0, 543},
+ dictWord{5, 10, 101},
+ dictWord{5, 11, 256},
+ dictWord{6, 10, 88},
+ dictWord{7, 10, 1677},
+ dictWord{9, 10, 100},
+ dictWord{10, 10, 677},
+ dictWord{14, 10, 169},
+ dictWord{14, 10, 302},
+ dictWord{14, 10, 313},
+ dictWord{15, 10, 48},
+ dictWord{143, 10, 84},
+ dictWord{4, 10, 310},
+ dictWord{
+ 7,
+ 10,
+ 708,
+ },
+ dictWord{7, 10, 996},
+ dictWord{9, 10, 795},
+ dictWord{10, 10, 390},
+ dictWord{10, 10, 733},
+ dictWord{11, 10, 451},
+ dictWord{12, 10, 249},
+ dictWord{
+ 14,
+ 10,
+ 115,
+ },
+ dictWord{14, 10, 286},
+ dictWord{143, 10, 100},
+ dictWord{133, 10, 587},
+ dictWord{13, 11, 417},
+ dictWord{14, 11, 129},
+ dictWord{143, 11, 15},
+ dictWord{134, 0, 1358},
+ dictWord{136, 11, 554},
+ dictWord{132, 10, 498},
+ dictWord{7, 10, 217},
+ dictWord{8, 10, 140},
+ dictWord{138, 10, 610},
+ dictWord{
+ 135,
+ 11,
+ 989,
+ },
+ dictWord{135, 11, 634},
+ dictWord{6, 0, 155},
+ dictWord{140, 0, 234},
+ dictWord{135, 11, 462},
+ dictWord{132, 11, 618},
+ dictWord{
+ 134,
+ 0,
+ 1628,
+ },
+ dictWord{132, 0, 766},
+ dictWord{4, 11, 339},
+ dictWord{5, 10, 905},
+ dictWord{135, 11, 259},
+ dictWord{135, 0, 829},
+ dictWord{4, 11, 759},
+ dictWord{
+ 141,
+ 11,
+ 169,
+ },
+ dictWord{7, 0, 1445},
+ dictWord{4, 10, 456},
+ dictWord{7, 10, 358},
+ dictWord{7, 10, 1637},
+ dictWord{8, 10, 643},
+ dictWord{139, 10, 483},
+ dictWord{
+ 5,
+ 0,
+ 486,
+ },
+ dictWord{135, 0, 1349},
+ dictWord{5, 11, 688},
+ dictWord{135, 11, 712},
+ dictWord{7, 0, 1635},
+ dictWord{8, 0, 17},
+ dictWord{10, 0, 217},
+ dictWord{
+ 10,
+ 0,
+ 295,
+ },
+ dictWord{12, 0, 2},
+ dictWord{140, 11, 2},
+ dictWord{138, 0, 558},
+ dictWord{150, 10, 56},
+ dictWord{4, 11, 278},
+ dictWord{5, 11, 465},
+ dictWord{
+ 135,
+ 11,
+ 1367,
+ },
+ dictWord{136, 11, 482},
+ dictWord{133, 10, 535},
+ dictWord{6, 0, 1362},
+ dictWord{6, 0, 1461},
+ dictWord{10, 11, 274},
+ dictWord{10, 11, 625},
+ dictWord{139, 11, 530},
+ dictWord{5, 0, 599},
+ dictWord{5, 11, 336},
+ dictWord{6, 11, 341},
+ dictWord{6, 11, 478},
+ dictWord{6, 11, 1763},
+ dictWord{136, 11, 386},
+ dictWord{7, 10, 1748},
+ dictWord{137, 11, 151},
+ dictWord{134, 0, 1376},
+ dictWord{133, 10, 539},
+ dictWord{135, 11, 73},
+ dictWord{135, 11, 1971},
+ dictWord{139, 11, 283},
+ dictWord{9, 0, 93},
+ dictWord{139, 0, 474},
+ dictWord{6, 10, 91},
+ dictWord{135, 10, 435},
+ dictWord{6, 0, 447},
+ dictWord{5, 11, 396},
+ dictWord{134, 11, 501},
+ dictWord{4, 10, 16},
+ dictWord{5, 10, 316},
+ dictWord{5, 10, 842},
+ dictWord{6, 10, 370},
+ dictWord{6, 10, 1778},
+ dictWord{8, 10, 166},
+ dictWord{11, 10, 812},
+ dictWord{12, 10, 206},
+ dictWord{12, 10, 351},
+ dictWord{14, 10, 418},
+ dictWord{16, 10, 15},
+ dictWord{16, 10, 34},
+ dictWord{18, 10, 3},
+ dictWord{19, 10, 3},
+ dictWord{19, 10, 7},
+ dictWord{20, 10, 4},
+ dictWord{149, 10, 21},
+ dictWord{7, 0, 577},
+ dictWord{7, 0, 1432},
+ dictWord{9, 0, 475},
+ dictWord{9, 0, 505},
+ dictWord{9, 0, 526},
+ dictWord{9, 0, 609},
+ dictWord{9, 0, 689},
+ dictWord{9, 0, 726},
+ dictWord{9, 0, 735},
+ dictWord{9, 0, 738},
+ dictWord{10, 0, 556},
+ dictWord{
+ 10,
+ 0,
+ 674,
+ },
+ dictWord{10, 0, 684},
+ dictWord{11, 0, 89},
+ dictWord{11, 0, 202},
+ dictWord{11, 0, 272},
+ dictWord{11, 0, 380},
+ dictWord{11, 0, 415},
+ dictWord{11, 0, 505},
+ dictWord{11, 0, 537},
+ dictWord{11, 0, 550},
+ dictWord{11, 0, 562},
+ dictWord{11, 0, 640},
+ dictWord{11, 0, 667},
+ dictWord{11, 0, 688},
+ dictWord{11, 0, 847},
+ dictWord{11, 0, 927},
+ dictWord{11, 0, 930},
+ dictWord{11, 0, 940},
+ dictWord{12, 0, 144},
+ dictWord{12, 0, 325},
+ dictWord{12, 0, 329},
+ dictWord{12, 0, 389},
+ dictWord{
+ 12,
+ 0,
+ 403,
+ },
+ dictWord{12, 0, 451},
+ dictWord{12, 0, 515},
+ dictWord{12, 0, 604},
+ dictWord{12, 0, 616},
+ dictWord{12, 0, 626},
+ dictWord{13, 0, 66},
+ dictWord{
+ 13,
+ 0,
+ 131,
+ },
+ dictWord{13, 0, 167},
+ dictWord{13, 0, 236},
+ dictWord{13, 0, 368},
+ dictWord{13, 0, 411},
+ dictWord{13, 0, 434},
+ dictWord{13, 0, 453},
+ dictWord{13, 0, 461},
+ dictWord{13, 0, 474},
+ dictWord{14, 0, 59},
+ dictWord{14, 0, 60},
+ dictWord{14, 0, 139},
+ dictWord{14, 0, 152},
+ dictWord{14, 0, 276},
+ dictWord{14, 0, 353},
+ dictWord{
+ 14,
+ 0,
+ 402,
+ },
+ dictWord{15, 0, 28},
+ dictWord{15, 0, 81},
+ dictWord{15, 0, 123},
+ dictWord{15, 0, 152},
+ dictWord{18, 0, 136},
+ dictWord{148, 0, 88},
+ dictWord{
+ 4,
+ 11,
+ 929,
+ },
+ dictWord{133, 11, 799},
+ dictWord{136, 11, 46},
+ dictWord{142, 0, 307},
+ dictWord{4, 0, 609},
+ dictWord{7, 0, 756},
+ dictWord{9, 0, 544},
+ dictWord{
+ 11,
+ 0,
+ 413,
+ },
+ dictWord{144, 0, 25},
+ dictWord{10, 0, 687},
+ dictWord{7, 10, 619},
+ dictWord{10, 10, 547},
+ dictWord{11, 10, 122},
+ dictWord{140, 10, 601},
+ dictWord{
+ 4,
+ 0,
+ 930,
+ },
+ dictWord{133, 0, 947},
+ dictWord{133, 0, 939},
+ dictWord{142, 0, 21},
+ dictWord{4, 11, 892},
+ dictWord{133, 11, 770},
+ dictWord{133, 0, 962},
+ dictWord{
+ 5,
+ 0,
+ 651,
+ },
+ dictWord{8, 0, 170},
+ dictWord{9, 0, 61},
+ dictWord{9, 0, 63},
+ dictWord{10, 0, 23},
+ dictWord{10, 0, 37},
+ dictWord{10, 0, 834},
+ dictWord{11, 0, 4},
+ dictWord{
+ 11,
+ 0,
+ 187,
+ },
+ dictWord{11, 0, 281},
+ dictWord{11, 0, 503},
+ dictWord{11, 0, 677},
+ dictWord{12, 0, 96},
+ dictWord{12, 0, 130},
+ dictWord{12, 0, 244},
+ dictWord{14, 0, 5},
+ dictWord{14, 0, 40},
+ dictWord{14, 0, 162},
+ dictWord{14, 0, 202},
+ dictWord{146, 0, 133},
+ dictWord{4, 0, 406},
+ dictWord{5, 0, 579},
+ dictWord{12, 0, 492},
+ dictWord{
+ 150,
+ 0,
+ 15,
+ },
+ dictWord{135, 11, 158},
+ dictWord{135, 0, 597},
+ dictWord{132, 0, 981},
+ dictWord{132, 10, 888},
+ dictWord{4, 10, 149},
+ dictWord{138, 10, 368},
+ dictWord{132, 0, 545},
+ dictWord{4, 10, 154},
+ dictWord{7, 10, 1134},
+ dictWord{136, 10, 105},
+ dictWord{135, 11, 2001},
+ dictWord{134, 0, 1558},
+ dictWord{
+ 4,
+ 10,
+ 31,
+ },
+ dictWord{6, 10, 429},
+ dictWord{7, 10, 962},
+ dictWord{9, 10, 458},
+ dictWord{139, 10, 691},
+ dictWord{132, 10, 312},
+ dictWord{135, 10, 1642},
+ dictWord{
+ 6,
+ 0,
+ 17,
+ },
+ dictWord{6, 0, 1304},
+ dictWord{7, 0, 16},
+ dictWord{7, 0, 1001},
+ dictWord{9, 0, 886},
+ dictWord{10, 0, 489},
+ dictWord{10, 0, 800},
+ dictWord{11, 0, 782},
+ dictWord{12, 0, 320},
+ dictWord{13, 0, 467},
+ dictWord{14, 0, 145},
+ dictWord{14, 0, 387},
+ dictWord{143, 0, 119},
+ dictWord{135, 0, 1982},
+ dictWord{17, 0, 17},
+ dictWord{7, 11, 1461},
+ dictWord{140, 11, 91},
+ dictWord{4, 10, 236},
+ dictWord{132, 11, 602},
+ dictWord{138, 0, 907},
+ dictWord{136, 0, 110},
+ dictWord{7, 0, 272},
+ dictWord{19, 0, 53},
+ dictWord{5, 10, 836},
+ dictWord{5, 10, 857},
+ dictWord{134, 10, 1680},
+ dictWord{5, 0, 458},
+ dictWord{7, 11, 1218},
+ dictWord{136, 11, 303},
+ dictWord{7, 0, 1983},
+ dictWord{8, 0, 0},
+ dictWord{8, 0, 171},
+ dictWord{9, 0, 120},
+ dictWord{9, 0, 732},
+ dictWord{10, 0, 473},
+ dictWord{11, 0, 656},
+ dictWord{
+ 11,
+ 0,
+ 998,
+ },
+ dictWord{18, 0, 0},
+ dictWord{18, 0, 2},
+ dictWord{19, 0, 21},
+ dictWord{10, 10, 68},
+ dictWord{139, 10, 494},
+ dictWord{137, 11, 662},
+ dictWord{4, 11, 13},
+ dictWord{5, 11, 567},
+ dictWord{7, 11, 1498},
+ dictWord{9, 11, 124},
+ dictWord{11, 11, 521},
+ dictWord{140, 11, 405},
+ dictWord{4, 10, 81},
+ dictWord{139, 10, 867},
+ dictWord{135, 11, 1006},
+ dictWord{7, 11, 800},
+ dictWord{7, 11, 1783},
+ dictWord{138, 11, 12},
+ dictWord{9, 0, 295},
+ dictWord{10, 0, 443},
+ dictWord{
+ 5,
+ 10,
+ 282,
+ },
+ dictWord{8, 10, 650},
+ dictWord{137, 10, 907},
+ dictWord{132, 11, 735},
+ dictWord{4, 11, 170},
+ dictWord{4, 10, 775},
+ dictWord{135, 11, 323},
+ dictWord{
+ 6,
+ 0,
+ 1844,
+ },
+ dictWord{10, 0, 924},
+ dictWord{11, 11, 844},
+ dictWord{12, 11, 104},
+ dictWord{140, 11, 625},
+ dictWord{5, 11, 304},
+ dictWord{7, 11, 1403},
+ dictWord{140, 11, 498},
+ dictWord{134, 0, 1232},
+ dictWord{4, 0, 519},
+ dictWord{10, 0, 70},
+ dictWord{12, 0, 26},
+ dictWord{14, 0, 17},
+ dictWord{14, 0, 178},
+ dictWord{
+ 15,
+ 0,
+ 34,
+ },
+ dictWord{149, 0, 12},
+ dictWord{132, 0, 993},
+ dictWord{4, 11, 148},
+ dictWord{133, 11, 742},
+ dictWord{6, 0, 31},
+ dictWord{7, 0, 491},
+ dictWord{7, 0, 530},
+ dictWord{8, 0, 592},
+ dictWord{11, 0, 53},
+ dictWord{11, 0, 779},
+ dictWord{12, 0, 167},
+ dictWord{12, 0, 411},
+ dictWord{14, 0, 14},
+ dictWord{14, 0, 136},
+ dictWord{
+ 15,
+ 0,
+ 72,
+ },
+ dictWord{16, 0, 17},
+ dictWord{144, 0, 72},
+ dictWord{133, 0, 907},
+ dictWord{134, 0, 733},
+ dictWord{133, 11, 111},
+ dictWord{4, 10, 71},
+ dictWord{
+ 5,
+ 10,
+ 376,
+ },
+ dictWord{7, 10, 119},
+ dictWord{138, 10, 665},
+ dictWord{136, 0, 55},
+ dictWord{8, 0, 430},
+ dictWord{136, 11, 430},
+ dictWord{4, 0, 208},
+ dictWord{
+ 5,
+ 0,
+ 106,
+ },
+ dictWord{6, 0, 531},
+ dictWord{8, 0, 408},
+ dictWord{9, 0, 188},
+ dictWord{138, 0, 572},
+ dictWord{12, 0, 56},
+ dictWord{11, 10, 827},
+ dictWord{14, 10, 34},
+ dictWord{143, 10, 148},
+ dictWord{134, 0, 1693},
+ dictWord{133, 11, 444},
+ dictWord{132, 10, 479},
+ dictWord{140, 0, 441},
+ dictWord{9, 0, 449},
+ dictWord{
+ 10,
+ 0,
+ 192,
+ },
+ dictWord{138, 0, 740},
+ dictWord{134, 0, 928},
+ dictWord{4, 0, 241},
+ dictWord{7, 10, 607},
+ dictWord{136, 10, 99},
+ dictWord{8, 11, 123},
+ dictWord{
+ 15,
+ 11,
+ 6,
+ },
+ dictWord{144, 11, 7},
+ dictWord{6, 11, 285},
+ dictWord{8, 11, 654},
+ dictWord{11, 11, 749},
+ dictWord{12, 11, 190},
+ dictWord{12, 11, 327},
+ dictWord{
+ 13,
+ 11,
+ 120,
+ },
+ dictWord{13, 11, 121},
+ dictWord{13, 11, 327},
+ dictWord{15, 11, 47},
+ dictWord{146, 11, 40},
+ dictWord{4, 10, 41},
+ dictWord{5, 10, 74},
+ dictWord{
+ 7,
+ 10,
+ 1627,
+ },
+ dictWord{11, 10, 871},
+ dictWord{140, 10, 619},
+ dictWord{7, 0, 1525},
+ dictWord{11, 10, 329},
+ dictWord{11, 10, 965},
+ dictWord{12, 10, 241},
+ dictWord{14, 10, 354},
+ dictWord{15, 10, 22},
+ dictWord{148, 10, 63},
+ dictWord{132, 0, 259},
+ dictWord{135, 11, 183},
+ dictWord{9, 10, 209},
+ dictWord{
+ 137,
+ 10,
+ 300,
+ },
+ dictWord{5, 11, 937},
+ dictWord{135, 11, 100},
+ dictWord{133, 10, 98},
+ dictWord{4, 0, 173},
+ dictWord{5, 0, 312},
+ dictWord{5, 0, 512},
+ dictWord{
+ 135,
+ 0,
+ 1285,
+ },
+ dictWord{141, 0, 185},
+ dictWord{7, 0, 1603},
+ dictWord{7, 0, 1691},
+ dictWord{9, 0, 464},
+ dictWord{11, 0, 195},
+ dictWord{12, 0, 279},
+ dictWord{
+ 12,
+ 0,
+ 448,
+ },
+ dictWord{14, 0, 11},
+ dictWord{147, 0, 102},
+ dictWord{135, 0, 1113},
+ dictWord{133, 10, 984},
+ dictWord{4, 0, 452},
+ dictWord{5, 0, 583},
+ dictWord{
+ 135,
+ 0,
+ 720,
+ },
+ dictWord{4, 0, 547},
+ dictWord{5, 0, 817},
+ dictWord{6, 0, 433},
+ dictWord{7, 0, 593},
+ dictWord{7, 0, 1378},
+ dictWord{8, 0, 161},
+ dictWord{9, 0, 284},
+ dictWord{
+ 10,
+ 0,
+ 313,
+ },
+ dictWord{139, 0, 886},
+ dictWord{8, 0, 722},
+ dictWord{4, 10, 182},
+ dictWord{6, 10, 205},
+ dictWord{135, 10, 220},
+ dictWord{150, 0, 13},
+ dictWord{
+ 4,
+ 10,
+ 42,
+ },
+ dictWord{9, 10, 205},
+ dictWord{9, 10, 786},
+ dictWord{138, 10, 659},
+ dictWord{6, 0, 289},
+ dictWord{7, 0, 1670},
+ dictWord{12, 0, 57},
+ dictWord{151, 0, 4},
+ dictWord{132, 10, 635},
+ dictWord{14, 0, 43},
+ dictWord{146, 0, 21},
+ dictWord{139, 10, 533},
+ dictWord{135, 0, 1694},
+ dictWord{8, 0, 420},
+ dictWord{
+ 139,
+ 0,
+ 193,
+ },
+ dictWord{135, 0, 409},
+ dictWord{132, 10, 371},
+ dictWord{4, 10, 272},
+ dictWord{135, 10, 836},
+ dictWord{5, 10, 825},
+ dictWord{134, 10, 1640},
+ dictWord{5, 11, 251},
+ dictWord{5, 11, 956},
+ dictWord{8, 11, 268},
+ dictWord{9, 11, 214},
+ dictWord{146, 11, 142},
+ dictWord{138, 0, 308},
+ dictWord{6, 0, 1863},
+ dictWord{141, 11, 37},
+ dictWord{137, 10, 879},
+ dictWord{7, 10, 317},
+ dictWord{135, 10, 569},
+ dictWord{132, 11, 294},
+ dictWord{134, 0, 790},
+ dictWord{
+ 5,
+ 0,
+ 1002,
+ },
+ dictWord{136, 0, 745},
+ dictWord{5, 11, 346},
+ dictWord{5, 11, 711},
+ dictWord{136, 11, 390},
+ dictWord{135, 0, 289},
+ dictWord{5, 0, 504},
+ dictWord{
+ 11,
+ 0,
+ 68,
+ },
+ dictWord{137, 10, 307},
+ dictWord{4, 0, 239},
+ dictWord{6, 0, 477},
+ dictWord{7, 0, 1607},
+ dictWord{139, 0, 617},
+ dictWord{149, 0, 13},
+ dictWord{
+ 133,
+ 0,
+ 609,
+ },
+ dictWord{133, 11, 624},
+ dictWord{5, 11, 783},
+ dictWord{7, 11, 1998},
+ dictWord{135, 11, 2047},
+ dictWord{133, 10, 525},
+ dictWord{132, 0, 367},
+ dictWord{132, 11, 594},
+ dictWord{6, 0, 528},
+ dictWord{133, 10, 493},
+ dictWord{4, 10, 174},
+ dictWord{135, 10, 911},
+ dictWord{8, 10, 417},
+ dictWord{
+ 137,
+ 10,
+ 782,
+ },
+ dictWord{132, 0, 694},
+ dictWord{7, 0, 548},
+ dictWord{137, 0, 58},
+ dictWord{4, 10, 32},
+ dictWord{5, 10, 215},
+ dictWord{6, 10, 269},
+ dictWord{7, 10, 1782},
+ dictWord{7, 10, 1892},
+ dictWord{10, 10, 16},
+ dictWord{11, 10, 822},
+ dictWord{11, 10, 954},
+ dictWord{141, 10, 481},
+ dictWord{140, 0, 687},
+ dictWord{
+ 7,
+ 0,
+ 1749,
+ },
+ dictWord{136, 10, 477},
+ dictWord{132, 11, 569},
+ dictWord{133, 10, 308},
+ dictWord{135, 10, 1088},
+ dictWord{4, 0, 661},
+ dictWord{138, 0, 1004},
+ dictWord{5, 11, 37},
+ dictWord{6, 11, 39},
+ dictWord{6, 11, 451},
+ dictWord{7, 11, 218},
+ dictWord{7, 11, 667},
+ dictWord{7, 11, 1166},
+ dictWord{7, 11, 1687},
+ dictWord{8, 11, 662},
+ dictWord{144, 11, 2},
+ dictWord{9, 0, 445},
+ dictWord{12, 0, 53},
+ dictWord{13, 0, 492},
+ dictWord{5, 10, 126},
+ dictWord{8, 10, 297},
+ dictWord{
+ 9,
+ 10,
+ 366,
+ },
+ dictWord{140, 10, 374},
+ dictWord{7, 10, 1551},
+ dictWord{139, 10, 361},
+ dictWord{148, 0, 74},
+ dictWord{134, 11, 508},
+ dictWord{135, 0, 213},
+ dictWord{132, 10, 175},
+ dictWord{132, 10, 685},
+ dictWord{6, 0, 760},
+ dictWord{6, 0, 834},
+ dictWord{134, 0, 1248},
+ dictWord{7, 11, 453},
+ dictWord{7, 11, 635},
+ dictWord{7, 11, 796},
+ dictWord{8, 11, 331},
+ dictWord{9, 11, 328},
+ dictWord{9, 11, 330},
+ dictWord{9, 11, 865},
+ dictWord{10, 11, 119},
+ dictWord{10, 11, 235},
+ dictWord{11, 11, 111},
+ dictWord{11, 11, 129},
+ dictWord{11, 11, 240},
+ dictWord{12, 11, 31},
+ dictWord{12, 11, 66},
+ dictWord{12, 11, 222},
+ dictWord{12, 11, 269},
+ dictWord{12, 11, 599},
+ dictWord{12, 11, 689},
+ dictWord{13, 11, 186},
+ dictWord{13, 11, 364},
+ dictWord{142, 11, 345},
+ dictWord{7, 0, 1672},
+ dictWord{
+ 139,
+ 0,
+ 189,
+ },
+ dictWord{133, 10, 797},
+ dictWord{133, 10, 565},
+ dictWord{6, 0, 1548},
+ dictWord{6, 11, 98},
+ dictWord{7, 11, 585},
+ dictWord{135, 11, 702},
+ dictWord{
+ 9,
+ 0,
+ 968,
+ },
+ dictWord{15, 0, 192},
+ dictWord{149, 0, 56},
+ dictWord{4, 10, 252},
+ dictWord{6, 11, 37},
+ dictWord{7, 11, 299},
+ dictWord{7, 10, 1068},
+ dictWord{
+ 7,
+ 11,
+ 1666,
+ },
+ dictWord{8, 11, 195},
+ dictWord{8, 11, 316},
+ dictWord{9, 11, 178},
+ dictWord{9, 11, 276},
+ dictWord{9, 11, 339},
+ dictWord{9, 11, 536},
+ dictWord{
+ 10,
+ 11,
+ 102,
+ },
+ dictWord{10, 11, 362},
+ dictWord{10, 10, 434},
+ dictWord{10, 11, 785},
+ dictWord{11, 11, 55},
+ dictWord{11, 11, 149},
+ dictWord{11, 10, 228},
+ dictWord{
+ 11,
+ 10,
+ 426,
+ },
+ dictWord{11, 11, 773},
+ dictWord{13, 10, 231},
+ dictWord{13, 11, 416},
+ dictWord{13, 11, 419},
+ dictWord{14, 11, 38},
+ dictWord{14, 11, 41},
+ dictWord{14, 11, 210},
+ dictWord{18, 10, 106},
+ dictWord{148, 10, 87},
+ dictWord{4, 0, 751},
+ dictWord{11, 0, 390},
+ dictWord{140, 0, 32},
+ dictWord{4, 0, 409},
+ dictWord{133, 0, 78},
+ dictWord{11, 11, 458},
+ dictWord{12, 11, 15},
+ dictWord{140, 11, 432},
+ dictWord{7, 0, 1602},
+ dictWord{10, 0, 257},
+ dictWord{10, 0, 698},
+ dictWord{11, 0, 544},
+ dictWord{11, 0, 585},
+ dictWord{12, 0, 212},
+ dictWord{13, 0, 307},
+ dictWord{5, 10, 231},
+ dictWord{7, 10, 601},
+ dictWord{9, 10, 277},
+ dictWord{
+ 9,
+ 10,
+ 674,
+ },
+ dictWord{10, 10, 178},
+ dictWord{10, 10, 418},
+ dictWord{10, 10, 509},
+ dictWord{11, 10, 531},
+ dictWord{12, 10, 113},
+ dictWord{12, 10, 475},
+ dictWord{13, 10, 99},
+ dictWord{142, 10, 428},
+ dictWord{6, 0, 473},
+ dictWord{145, 0, 105},
+ dictWord{6, 0, 1949},
+ dictWord{15, 0, 156},
+ dictWord{133, 11, 645},
+ dictWord{7, 10, 1591},
+ dictWord{144, 10, 43},
+ dictWord{135, 0, 1779},
+ dictWord{135, 10, 1683},
+ dictWord{4, 11, 290},
+ dictWord{135, 11, 1356},
+ dictWord{134, 0, 763},
+ dictWord{6, 11, 70},
+ dictWord{7, 11, 1292},
+ dictWord{10, 11, 762},
+ dictWord{139, 11, 288},
+ dictWord{142, 0, 29},
+ dictWord{140, 11, 428},
+ dictWord{7, 0, 883},
+ dictWord{7, 11, 131},
+ dictWord{7, 11, 422},
+ dictWord{8, 11, 210},
+ dictWord{140, 11, 573},
+ dictWord{134, 0, 488},
+ dictWord{4, 10, 399},
+ dictWord{5, 10, 119},
+ dictWord{5, 10, 494},
+ dictWord{7, 10, 751},
+ dictWord{137, 10, 556},
+ dictWord{133, 0, 617},
+ dictWord{132, 11, 936},
+ dictWord{
+ 139,
+ 0,
+ 50,
+ },
+ dictWord{7, 0, 1518},
+ dictWord{139, 0, 694},
+ dictWord{137, 0, 785},
+ dictWord{4, 0, 546},
+ dictWord{135, 0, 2042},
+ dictWord{7, 11, 716},
+ dictWord{
+ 13,
+ 11,
+ 97,
+ },
+ dictWord{141, 11, 251},
+ dictWord{132, 11, 653},
+ dictWord{145, 0, 22},
+ dictWord{134, 0, 1016},
+ dictWord{4, 0, 313},
+ dictWord{133, 0, 577},
+ dictWord{
+ 136,
+ 11,
+ 657,
+ },
+ dictWord{8, 0, 184},
+ dictWord{141, 0, 433},
+ dictWord{135, 0, 935},
+ dictWord{6, 0, 720},
+ dictWord{9, 0, 114},
+ dictWord{146, 11, 80},
+ dictWord{
+ 12,
+ 0,
+ 186,
+ },
+ dictWord{12, 0, 292},
+ dictWord{14, 0, 100},
+ dictWord{18, 0, 70},
+ dictWord{7, 10, 594},
+ dictWord{7, 10, 851},
+ dictWord{7, 10, 1858},
+ dictWord{
+ 9,
+ 10,
+ 411,
+ },
+ dictWord{9, 10, 574},
+ dictWord{9, 10, 666},
+ dictWord{9, 10, 737},
+ dictWord{10, 10, 346},
+ dictWord{10, 10, 712},
+ dictWord{11, 10, 246},
+ dictWord{
+ 11,
+ 10,
+ 432,
+ },
+ dictWord{11, 10, 517},
+ dictWord{11, 10, 647},
+ dictWord{11, 10, 679},
+ dictWord{11, 10, 727},
+ dictWord{12, 10, 304},
+ dictWord{12, 10, 305},
+ dictWord{12, 10, 323},
+ dictWord{12, 10, 483},
+ dictWord{12, 10, 572},
+ dictWord{12, 10, 593},
+ dictWord{12, 10, 602},
+ dictWord{13, 10, 95},
+ dictWord{13, 10, 101},
+ dictWord{13, 10, 171},
+ dictWord{13, 10, 315},
+ dictWord{13, 10, 378},
+ dictWord{13, 10, 425},
+ dictWord{13, 10, 475},
+ dictWord{14, 10, 63},
+ dictWord{
+ 14,
+ 10,
+ 380,
+ },
+ dictWord{14, 10, 384},
+ dictWord{15, 10, 133},
+ dictWord{18, 10, 112},
+ dictWord{148, 10, 72},
+ dictWord{135, 10, 1093},
+ dictWord{135, 11, 1836},
+ dictWord{132, 10, 679},
+ dictWord{137, 10, 203},
+ dictWord{11, 0, 402},
+ dictWord{12, 0, 109},
+ dictWord{12, 0, 431},
+ dictWord{13, 0, 179},
+ dictWord{13, 0, 206},
+ dictWord{14, 0, 217},
+ dictWord{16, 0, 3},
+ dictWord{148, 0, 53},
+ dictWord{7, 11, 1368},
+ dictWord{8, 11, 232},
+ dictWord{8, 11, 361},
+ dictWord{10, 11, 682},
+ dictWord{138, 11, 742},
+ dictWord{137, 10, 714},
+ dictWord{5, 0, 886},
+ dictWord{6, 0, 46},
+ dictWord{6, 0, 1790},
+ dictWord{7, 0, 14},
+ dictWord{7, 0, 732},
+ dictWord{
+ 7,
+ 0,
+ 1654,
+ },
+ dictWord{8, 0, 95},
+ dictWord{8, 0, 327},
+ dictWord{8, 0, 616},
+ dictWord{9, 0, 892},
+ dictWord{10, 0, 598},
+ dictWord{10, 0, 769},
+ dictWord{11, 0, 134},
+ dictWord{11, 0, 747},
+ dictWord{12, 0, 378},
+ dictWord{14, 0, 97},
+ dictWord{137, 11, 534},
+ dictWord{4, 0, 969},
+ dictWord{136, 10, 825},
+ dictWord{137, 11, 27},
+ dictWord{6, 0, 727},
+ dictWord{142, 11, 12},
+ dictWord{133, 0, 1021},
+ dictWord{134, 0, 1190},
+ dictWord{134, 11, 1657},
+ dictWord{5, 10, 143},
+ dictWord{
+ 5,
+ 10,
+ 769,
+ },
+ dictWord{6, 10, 1760},
+ dictWord{7, 10, 682},
+ dictWord{7, 10, 1992},
+ dictWord{136, 10, 736},
+ dictWord{132, 0, 153},
+ dictWord{135, 11, 127},
+ dictWord{133, 0, 798},
+ dictWord{132, 0, 587},
+ dictWord{6, 0, 598},
+ dictWord{7, 0, 42},
+ dictWord{8, 0, 695},
+ dictWord{10, 0, 212},
+ dictWord{11, 0, 158},
+ dictWord{
+ 14,
+ 0,
+ 196,
+ },
+ dictWord{145, 0, 85},
+ dictWord{133, 10, 860},
+ dictWord{6, 0, 1929},
+ dictWord{134, 0, 1933},
+ dictWord{5, 0, 957},
+ dictWord{5, 0, 1008},
+ dictWord{
+ 9,
+ 0,
+ 577,
+ },
+ dictWord{12, 0, 141},
+ dictWord{6, 10, 422},
+ dictWord{7, 10, 0},
+ dictWord{7, 10, 1544},
+ dictWord{8, 11, 364},
+ dictWord{11, 10, 990},
+ dictWord{
+ 12,
+ 10,
+ 453,
+ },
+ dictWord{13, 10, 47},
+ dictWord{141, 10, 266},
+ dictWord{134, 0, 1319},
+ dictWord{4, 0, 129},
+ dictWord{135, 0, 465},
+ dictWord{7, 0, 470},
+ dictWord{
+ 7,
+ 0,
+ 1057,
+ },
+ dictWord{7, 0, 1201},
+ dictWord{9, 0, 755},
+ dictWord{11, 0, 906},
+ dictWord{140, 0, 527},
+ dictWord{7, 0, 908},
+ dictWord{146, 0, 7},
+ dictWord{5, 0, 148},
+ dictWord{136, 0, 450},
+ dictWord{5, 10, 515},
+ dictWord{137, 10, 131},
+ dictWord{7, 10, 1605},
+ dictWord{11, 10, 962},
+ dictWord{146, 10, 139},
+ dictWord{
+ 132,
+ 10,
+ 646,
+ },
+ dictWord{134, 0, 1166},
+ dictWord{4, 10, 396},
+ dictWord{7, 10, 728},
+ dictWord{9, 10, 117},
+ dictWord{13, 10, 202},
+ dictWord{148, 10, 51},
+ dictWord{
+ 6,
+ 10,
+ 121,
+ },
+ dictWord{6, 10, 124},
+ dictWord{6, 10, 357},
+ dictWord{7, 10, 1138},
+ dictWord{7, 10, 1295},
+ dictWord{8, 10, 162},
+ dictWord{139, 10, 655},
+ dictWord{14, 0, 374},
+ dictWord{142, 11, 374},
+ dictWord{138, 0, 253},
+ dictWord{139, 0, 1003},
+ dictWord{5, 11, 909},
+ dictWord{9, 11, 849},
+ dictWord{
+ 138,
+ 11,
+ 805,
+ },
+ dictWord{133, 10, 237},
+ dictWord{7, 11, 525},
+ dictWord{7, 11, 1579},
+ dictWord{8, 11, 497},
+ dictWord{136, 11, 573},
+ dictWord{137, 0, 46},
+ dictWord{
+ 132,
+ 0,
+ 879,
+ },
+ dictWord{134, 0, 806},
+ dictWord{135, 0, 1868},
+ dictWord{6, 0, 1837},
+ dictWord{134, 0, 1846},
+ dictWord{6, 0, 730},
+ dictWord{134, 0, 881},
+ dictWord{7, 0, 965},
+ dictWord{7, 0, 1460},
+ dictWord{7, 0, 1604},
+ dictWord{7, 11, 193},
+ dictWord{7, 11, 397},
+ dictWord{7, 11, 1105},
+ dictWord{8, 11, 124},
+ dictWord{
+ 8,
+ 11,
+ 619,
+ },
+ dictWord{9, 11, 305},
+ dictWord{10, 11, 264},
+ dictWord{11, 11, 40},
+ dictWord{12, 11, 349},
+ dictWord{13, 11, 134},
+ dictWord{13, 11, 295},
+ dictWord{14, 11, 155},
+ dictWord{15, 11, 120},
+ dictWord{146, 11, 105},
+ dictWord{136, 0, 506},
+ dictWord{143, 0, 10},
+ dictWord{4, 11, 262},
+ dictWord{7, 11, 342},
+ dictWord{7, 10, 571},
+ dictWord{7, 10, 1877},
+ dictWord{10, 10, 366},
+ dictWord{141, 11, 23},
+ dictWord{133, 11, 641},
+ dictWord{10, 0, 22},
+ dictWord{9, 10, 513},
+ dictWord{10, 10, 39},
+ dictWord{12, 10, 122},
+ dictWord{140, 10, 187},
+ dictWord{135, 11, 1431},
+ dictWord{150, 11, 49},
+ dictWord{4, 11, 99},
+ dictWord{
+ 6,
+ 11,
+ 250,
+ },
+ dictWord{6, 11, 346},
+ dictWord{8, 11, 127},
+ dictWord{138, 11, 81},
+ dictWord{6, 0, 2014},
+ dictWord{8, 0, 928},
+ dictWord{10, 0, 960},
+ dictWord{10, 0, 979},
+ dictWord{140, 0, 996},
+ dictWord{134, 0, 296},
+ dictWord{132, 11, 915},
+ dictWord{5, 11, 75},
+ dictWord{9, 11, 517},
+ dictWord{10, 11, 470},
+ dictWord{
+ 12,
+ 11,
+ 155,
+ },
+ dictWord{141, 11, 224},
+ dictWord{137, 10, 873},
+ dictWord{4, 0, 854},
+ dictWord{140, 11, 18},
+ dictWord{134, 0, 587},
+ dictWord{7, 10, 107},
+ dictWord{
+ 7,
+ 10,
+ 838,
+ },
+ dictWord{8, 10, 550},
+ dictWord{138, 10, 401},
+ dictWord{11, 0, 636},
+ dictWord{15, 0, 145},
+ dictWord{17, 0, 34},
+ dictWord{19, 0, 50},
+ dictWord{
+ 23,
+ 0,
+ 20,
+ },
+ dictWord{11, 10, 588},
+ dictWord{11, 10, 864},
+ dictWord{11, 10, 968},
+ dictWord{143, 10, 160},
+ dictWord{135, 11, 216},
+ dictWord{7, 0, 982},
+ dictWord{
+ 10,
+ 0,
+ 32,
+ },
+ dictWord{143, 0, 56},
+ dictWord{133, 10, 768},
+ dictWord{133, 11, 954},
+ dictWord{6, 11, 304},
+ dictWord{7, 11, 1114},
+ dictWord{8, 11, 418},
+ dictWord{
+ 10,
+ 11,
+ 345,
+ },
+ dictWord{11, 11, 341},
+ dictWord{11, 11, 675},
+ dictWord{141, 11, 40},
+ dictWord{9, 11, 410},
+ dictWord{139, 11, 425},
+ dictWord{136, 0, 941},
+ dictWord{5, 0, 435},
+ dictWord{132, 10, 894},
+ dictWord{5, 0, 85},
+ dictWord{6, 0, 419},
+ dictWord{7, 0, 134},
+ dictWord{7, 0, 305},
+ dictWord{7, 0, 361},
+ dictWord{
+ 7,
+ 0,
+ 1337,
+ },
+ dictWord{8, 0, 71},
+ dictWord{140, 0, 519},
+ dictWord{140, 0, 688},
+ dictWord{135, 0, 740},
+ dictWord{5, 0, 691},
+ dictWord{7, 0, 345},
+ dictWord{9, 0, 94},
+ dictWord{140, 0, 169},
+ dictWord{5, 0, 183},
+ dictWord{6, 0, 582},
+ dictWord{10, 0, 679},
+ dictWord{140, 0, 435},
+ dictWord{134, 11, 14},
+ dictWord{6, 0, 945},
+ dictWord{135, 0, 511},
+ dictWord{134, 11, 1708},
+ dictWord{5, 11, 113},
+ dictWord{6, 11, 243},
+ dictWord{7, 11, 1865},
+ dictWord{11, 11, 161},
+ dictWord{16, 11, 37},
+ dictWord{145, 11, 99},
+ dictWord{132, 11, 274},
+ dictWord{137, 0, 539},
+ dictWord{7, 0, 1993},
+ dictWord{8, 0, 684},
+ dictWord{134, 10, 272},
+ dictWord{
+ 6,
+ 0,
+ 659,
+ },
+ dictWord{134, 0, 982},
+ dictWord{4, 10, 9},
+ dictWord{5, 10, 128},
+ dictWord{7, 10, 368},
+ dictWord{11, 10, 480},
+ dictWord{148, 10, 3},
+ dictWord{
+ 134,
+ 0,
+ 583,
+ },
+ dictWord{132, 0, 803},
+ dictWord{133, 0, 704},
+ dictWord{4, 0, 179},
+ dictWord{5, 0, 198},
+ dictWord{133, 0, 697},
+ dictWord{7, 0, 347},
+ dictWord{7, 0, 971},
+ dictWord{8, 0, 181},
+ dictWord{10, 0, 711},
+ dictWord{135, 11, 166},
+ dictWord{136, 10, 682},
+ dictWord{4, 10, 2},
+ dictWord{7, 10, 545},
+ dictWord{7, 10, 894},
+ dictWord{136, 11, 521},
+ dictWord{135, 0, 481},
+ dictWord{132, 0, 243},
+ dictWord{5, 0, 203},
+ dictWord{7, 0, 19},
+ dictWord{7, 0, 71},
+ dictWord{7, 0, 113},
+ dictWord{
+ 10,
+ 0,
+ 405,
+ },
+ dictWord{11, 0, 357},
+ dictWord{142, 0, 240},
+ dictWord{5, 11, 725},
+ dictWord{5, 11, 727},
+ dictWord{135, 11, 1811},
+ dictWord{6, 0, 826},
+ dictWord{
+ 137,
+ 11,
+ 304,
+ },
+ dictWord{7, 0, 1450},
+ dictWord{139, 0, 99},
+ dictWord{133, 11, 654},
+ dictWord{134, 0, 492},
+ dictWord{5, 0, 134},
+ dictWord{6, 0, 408},
+ dictWord{
+ 6,
+ 0,
+ 495,
+ },
+ dictWord{7, 0, 1593},
+ dictWord{6, 11, 273},
+ dictWord{10, 11, 188},
+ dictWord{13, 11, 377},
+ dictWord{146, 11, 77},
+ dictWord{9, 10, 769},
+ dictWord{
+ 140,
+ 10,
+ 185,
+ },
+ dictWord{135, 11, 410},
+ dictWord{142, 0, 4},
+ dictWord{4, 0, 665},
+ dictWord{134, 11, 1785},
+ dictWord{4, 0, 248},
+ dictWord{7, 0, 137},
+ dictWord{
+ 137,
+ 0,
+ 349,
+ },
+ dictWord{5, 10, 530},
+ dictWord{142, 10, 113},
+ dictWord{7, 0, 1270},
+ dictWord{139, 0, 612},
+ dictWord{132, 11, 780},
+ dictWord{5, 0, 371},
+ dictWord{135, 0, 563},
+ dictWord{135, 0, 826},
+ dictWord{6, 0, 1535},
+ dictWord{23, 0, 21},
+ dictWord{151, 0, 23},
+ dictWord{4, 0, 374},
+ dictWord{7, 0, 547},
+ dictWord{
+ 7,
+ 0,
+ 1700,
+ },
+ dictWord{7, 0, 1833},
+ dictWord{139, 0, 858},
+ dictWord{133, 10, 556},
+ dictWord{7, 11, 612},
+ dictWord{8, 11, 545},
+ dictWord{8, 11, 568},
+ dictWord{
+ 8,
+ 11,
+ 642,
+ },
+ dictWord{9, 11, 717},
+ dictWord{10, 11, 541},
+ dictWord{10, 11, 763},
+ dictWord{11, 11, 449},
+ dictWord{12, 11, 489},
+ dictWord{13, 11, 153},
+ dictWord{
+ 13,
+ 11,
+ 296,
+ },
+ dictWord{14, 11, 138},
+ dictWord{14, 11, 392},
+ dictWord{15, 11, 50},
+ dictWord{16, 11, 6},
+ dictWord{16, 11, 12},
+ dictWord{148, 11, 9},
+ dictWord{
+ 9,
+ 0,
+ 311,
+ },
+ dictWord{141, 0, 42},
+ dictWord{8, 10, 16},
+ dictWord{140, 10, 568},
+ dictWord{6, 0, 1968},
+ dictWord{6, 0, 2027},
+ dictWord{138, 0, 991},
+ dictWord{
+ 6,
+ 0,
+ 1647,
+ },
+ dictWord{7, 0, 1552},
+ dictWord{7, 0, 2010},
+ dictWord{9, 0, 494},
+ dictWord{137, 0, 509},
+ dictWord{133, 11, 948},
+ dictWord{6, 10, 186},
+ dictWord{
+ 137,
+ 10,
+ 426,
+ },
+ dictWord{134, 0, 769},
+ dictWord{134, 0, 642},
+ dictWord{132, 10, 585},
+ dictWord{6, 0, 123},
+ dictWord{7, 0, 214},
+ dictWord{9, 0, 728},
+ dictWord{
+ 10,
+ 0,
+ 157,
+ },
+ dictWord{11, 0, 346},
+ dictWord{11, 0, 662},
+ dictWord{143, 0, 106},
+ dictWord{142, 11, 381},
+ dictWord{135, 0, 1435},
+ dictWord{4, 11, 532},
+ dictWord{
+ 5,
+ 11,
+ 706,
+ },
+ dictWord{135, 11, 662},
+ dictWord{5, 11, 837},
+ dictWord{134, 11, 1651},
+ dictWord{4, 10, 93},
+ dictWord{5, 10, 252},
+ dictWord{6, 10, 229},
+ dictWord{
+ 7,
+ 10,
+ 291,
+ },
+ dictWord{9, 10, 550},
+ dictWord{139, 10, 644},
+ dictWord{148, 0, 79},
+ dictWord{137, 10, 749},
+ dictWord{134, 0, 1425},
+ dictWord{
+ 137,
+ 10,
+ 162,
+ },
+ dictWord{4, 11, 362},
+ dictWord{7, 11, 52},
+ dictWord{7, 11, 303},
+ dictWord{140, 11, 166},
+ dictWord{132, 10, 381},
+ dictWord{4, 11, 330},
+ dictWord{
+ 7,
+ 11,
+ 933,
+ },
+ dictWord{7, 11, 2012},
+ dictWord{136, 11, 292},
+ dictWord{135, 11, 767},
+ dictWord{4, 0, 707},
+ dictWord{5, 0, 588},
+ dictWord{6, 0, 393},
+ dictWord{
+ 13,
+ 0,
+ 106,
+ },
+ dictWord{18, 0, 49},
+ dictWord{147, 0, 41},
+ dictWord{6, 0, 211},
+ dictWord{7, 0, 1690},
+ dictWord{11, 0, 486},
+ dictWord{140, 0, 369},
+ dictWord{
+ 137,
+ 11,
+ 883,
+ },
+ dictWord{4, 11, 703},
+ dictWord{135, 11, 207},
+ dictWord{4, 0, 187},
+ dictWord{5, 0, 184},
+ dictWord{5, 0, 690},
+ dictWord{7, 0, 1869},
+ dictWord{10, 0, 756},
+ dictWord{139, 0, 783},
+ dictWord{132, 11, 571},
+ dictWord{134, 0, 1382},
+ dictWord{5, 0, 175},
+ dictWord{6, 10, 77},
+ dictWord{6, 10, 157},
+ dictWord{7, 10, 974},
+ dictWord{7, 10, 1301},
+ dictWord{7, 10, 1339},
+ dictWord{7, 10, 1490},
+ dictWord{7, 10, 1873},
+ dictWord{137, 10, 628},
+ dictWord{134, 0, 1493},
+ dictWord{
+ 5,
+ 11,
+ 873,
+ },
+ dictWord{133, 11, 960},
+ dictWord{134, 0, 1007},
+ dictWord{12, 11, 93},
+ dictWord{12, 11, 501},
+ dictWord{13, 11, 362},
+ dictWord{14, 11, 151},
+ dictWord{15, 11, 40},
+ dictWord{15, 11, 59},
+ dictWord{16, 11, 46},
+ dictWord{17, 11, 25},
+ dictWord{18, 11, 14},
+ dictWord{18, 11, 134},
+ dictWord{19, 11, 25},
+ dictWord{
+ 19,
+ 11,
+ 69,
+ },
+ dictWord{20, 11, 16},
+ dictWord{20, 11, 19},
+ dictWord{20, 11, 66},
+ dictWord{21, 11, 23},
+ dictWord{21, 11, 25},
+ dictWord{150, 11, 42},
+ dictWord{
+ 11,
+ 10,
+ 919,
+ },
+ dictWord{141, 10, 409},
+ dictWord{134, 0, 219},
+ dictWord{5, 0, 582},
+ dictWord{6, 0, 1646},
+ dictWord{7, 0, 99},
+ dictWord{7, 0, 1962},
+ dictWord{
+ 7,
+ 0,
+ 1986,
+ },
+ dictWord{8, 0, 515},
+ dictWord{8, 0, 773},
+ dictWord{9, 0, 23},
+ dictWord{9, 0, 491},
+ dictWord{12, 0, 620},
+ dictWord{142, 0, 93},
+ dictWord{133, 0, 851},
+ dictWord{5, 11, 33},
+ dictWord{134, 11, 470},
+ dictWord{135, 11, 1291},
+ dictWord{134, 0, 1278},
+ dictWord{135, 11, 1882},
+ dictWord{135, 10, 1489},
+ dictWord{132, 0, 1000},
+ dictWord{138, 0, 982},
+ dictWord{8, 0, 762},
+ dictWord{8, 0, 812},
+ dictWord{137, 0, 910},
+ dictWord{6, 11, 47},
+ dictWord{7, 11, 90},
+ dictWord{
+ 7,
+ 11,
+ 664,
+ },
+ dictWord{7, 11, 830},
+ dictWord{7, 11, 1380},
+ dictWord{7, 11, 2025},
+ dictWord{8, 11, 448},
+ dictWord{136, 11, 828},
+ dictWord{4, 0, 98},
+ dictWord{
+ 4,
+ 0,
+ 940,
+ },
+ dictWord{6, 0, 1819},
+ dictWord{6, 0, 1834},
+ dictWord{6, 0, 1841},
+ dictWord{7, 0, 1365},
+ dictWord{8, 0, 859},
+ dictWord{8, 0, 897},
+ dictWord{8, 0, 918},
+ dictWord{9, 0, 422},
+ dictWord{9, 0, 670},
+ dictWord{10, 0, 775},
+ dictWord{10, 0, 894},
+ dictWord{10, 0, 909},
+ dictWord{10, 0, 910},
+ dictWord{10, 0, 935},
+ dictWord{
+ 11,
+ 0,
+ 210,
+ },
+ dictWord{12, 0, 750},
+ dictWord{12, 0, 755},
+ dictWord{13, 0, 26},
+ dictWord{13, 0, 457},
+ dictWord{13, 0, 476},
+ dictWord{16, 0, 100},
+ dictWord{16, 0, 109},
+ dictWord{18, 0, 173},
+ dictWord{18, 0, 175},
+ dictWord{8, 10, 398},
+ dictWord{9, 10, 681},
+ dictWord{139, 10, 632},
+ dictWord{9, 11, 417},
+ dictWord{
+ 137,
+ 11,
+ 493,
+ },
+ dictWord{136, 10, 645},
+ dictWord{138, 0, 906},
+ dictWord{134, 0, 1730},
+ dictWord{134, 10, 20},
+ dictWord{133, 11, 1019},
+ dictWord{134, 0, 1185},
+ dictWord{10, 0, 40},
+ dictWord{136, 10, 769},
+ dictWord{9, 0, 147},
+ dictWord{134, 11, 208},
+ dictWord{140, 0, 650},
+ dictWord{5, 0, 209},
+ dictWord{6, 0, 30},
+ dictWord{11, 0, 56},
+ dictWord{139, 0, 305},
+ dictWord{132, 0, 553},
+ dictWord{138, 11, 344},
+ dictWord{6, 11, 68},
+ dictWord{7, 11, 398},
+ dictWord{7, 11, 448},
+ dictWord{
+ 7,
+ 11,
+ 1629,
+ },
+ dictWord{7, 11, 1813},
+ dictWord{8, 11, 387},
+ dictWord{8, 11, 442},
+ dictWord{9, 11, 710},
+ dictWord{10, 11, 282},
+ dictWord{138, 11, 722},
+ dictWord{5, 0, 597},
+ dictWord{14, 0, 20},
+ dictWord{142, 11, 20},
+ dictWord{135, 0, 1614},
+ dictWord{135, 10, 1757},
+ dictWord{4, 0, 150},
+ dictWord{5, 0, 303},
+ dictWord{6, 0, 327},
+ dictWord{135, 10, 937},
+ dictWord{16, 0, 49},
+ dictWord{7, 10, 1652},
+ dictWord{144, 11, 49},
+ dictWord{8, 0, 192},
+ dictWord{10, 0, 78},
+ dictWord{
+ 141,
+ 0,
+ 359,
+ },
+ dictWord{135, 0, 786},
+ dictWord{143, 0, 134},
+ dictWord{6, 0, 1638},
+ dictWord{7, 0, 79},
+ dictWord{7, 0, 496},
+ dictWord{9, 0, 138},
+ dictWord{
+ 10,
+ 0,
+ 336,
+ },
+ dictWord{11, 0, 12},
+ dictWord{12, 0, 412},
+ dictWord{12, 0, 440},
+ dictWord{142, 0, 305},
+ dictWord{136, 11, 491},
+ dictWord{4, 10, 579},
+ dictWord{
+ 5,
+ 10,
+ 226,
+ },
+ dictWord{5, 10, 323},
+ dictWord{135, 10, 960},
+ dictWord{7, 0, 204},
+ dictWord{7, 0, 415},
+ dictWord{8, 0, 42},
+ dictWord{10, 0, 85},
+ dictWord{139, 0, 564},
+ dictWord{132, 0, 614},
+ dictWord{4, 11, 403},
+ dictWord{5, 11, 441},
+ dictWord{7, 11, 450},
+ dictWord{11, 11, 101},
+ dictWord{12, 11, 193},
+ dictWord{141, 11, 430},
+ dictWord{135, 11, 1927},
+ dictWord{135, 11, 1330},
+ dictWord{4, 0, 3},
+ dictWord{5, 0, 247},
+ dictWord{5, 0, 644},
+ dictWord{7, 0, 744},
+ dictWord{7, 0, 1207},
+ dictWord{7, 0, 1225},
+ dictWord{7, 0, 1909},
+ dictWord{146, 0, 147},
+ dictWord{136, 0, 942},
+ dictWord{4, 0, 1019},
+ dictWord{134, 0, 2023},
+ dictWord{5, 11, 679},
+ dictWord{133, 10, 973},
+ dictWord{5, 0, 285},
+ dictWord{9, 0, 67},
+ dictWord{13, 0, 473},
+ dictWord{143, 0, 82},
+ dictWord{7, 11, 328},
+ dictWord{137, 11, 326},
+ dictWord{151, 0, 8},
+ dictWord{6, 10, 135},
+ dictWord{135, 10, 1176},
+ dictWord{135, 11, 1128},
+ dictWord{134, 0, 1309},
+ dictWord{135, 11, 1796},
+ dictWord{
+ 135,
+ 10,
+ 314,
+ },
+ dictWord{4, 11, 574},
+ dictWord{7, 11, 350},
+ dictWord{7, 11, 1024},
+ dictWord{8, 11, 338},
+ dictWord{9, 11, 677},
+ dictWord{10, 11, 808},
+ dictWord{
+ 139,
+ 11,
+ 508,
+ },
+ dictWord{7, 11, 818},
+ dictWord{17, 11, 14},
+ dictWord{17, 11, 45},
+ dictWord{18, 11, 75},
+ dictWord{148, 11, 18},
+ dictWord{146, 10, 4},
+ dictWord{
+ 135,
+ 11,
+ 1081,
+ },
+ dictWord{4, 0, 29},
+ dictWord{6, 0, 532},
+ dictWord{7, 0, 1628},
+ dictWord{7, 0, 1648},
+ dictWord{9, 0, 350},
+ dictWord{10, 0, 433},
+ dictWord{11, 0, 97},
+ dictWord{11, 0, 557},
+ dictWord{11, 0, 745},
+ dictWord{12, 0, 289},
+ dictWord{12, 0, 335},
+ dictWord{12, 0, 348},
+ dictWord{12, 0, 606},
+ dictWord{13, 0, 116},
+ dictWord{13, 0, 233},
+ dictWord{13, 0, 466},
+ dictWord{14, 0, 181},
+ dictWord{14, 0, 209},
+ dictWord{14, 0, 232},
+ dictWord{14, 0, 236},
+ dictWord{14, 0, 300},
+ dictWord{
+ 16,
+ 0,
+ 41,
+ },
+ dictWord{148, 0, 97},
+ dictWord{7, 0, 318},
+ dictWord{6, 10, 281},
+ dictWord{8, 10, 282},
+ dictWord{8, 10, 480},
+ dictWord{8, 10, 499},
+ dictWord{9, 10, 198},
+ dictWord{10, 10, 143},
+ dictWord{10, 10, 169},
+ dictWord{10, 10, 211},
+ dictWord{10, 10, 417},
+ dictWord{10, 10, 574},
+ dictWord{11, 10, 147},
+ dictWord{
+ 11,
+ 10,
+ 395,
+ },
+ dictWord{12, 10, 75},
+ dictWord{12, 10, 407},
+ dictWord{12, 10, 608},
+ dictWord{13, 10, 500},
+ dictWord{142, 10, 251},
+ dictWord{135, 11, 1676},
+ dictWord{135, 11, 2037},
+ dictWord{135, 0, 1692},
+ dictWord{5, 0, 501},
+ dictWord{7, 0, 1704},
+ dictWord{9, 0, 553},
+ dictWord{11, 0, 520},
+ dictWord{12, 0, 557},
+ dictWord{141, 0, 249},
+ dictWord{6, 0, 1527},
+ dictWord{14, 0, 324},
+ dictWord{15, 0, 55},
+ dictWord{15, 0, 80},
+ dictWord{14, 11, 324},
+ dictWord{15, 11, 55},
+ dictWord{143, 11, 80},
+ dictWord{135, 10, 1776},
+ dictWord{8, 0, 988},
+ dictWord{137, 11, 297},
+ dictWord{132, 10, 419},
+ dictWord{142, 0, 223},
+ dictWord{
+ 139,
+ 11,
+ 234,
+ },
+ dictWord{7, 0, 1123},
+ dictWord{12, 0, 508},
+ dictWord{14, 0, 102},
+ dictWord{14, 0, 226},
+ dictWord{144, 0, 57},
+ dictWord{4, 10, 138},
+ dictWord{
+ 7,
+ 10,
+ 1012,
+ },
+ dictWord{7, 10, 1280},
+ dictWord{137, 10, 76},
+ dictWord{7, 0, 1764},
+ dictWord{5, 10, 29},
+ dictWord{140, 10, 638},
+ dictWord{134, 0, 2015},
+ dictWord{134, 0, 1599},
+ dictWord{138, 11, 56},
+ dictWord{6, 11, 306},
+ dictWord{7, 11, 1140},
+ dictWord{7, 11, 1340},
+ dictWord{8, 11, 133},
+ dictWord{
+ 138,
+ 11,
+ 449,
+ },
+ dictWord{139, 11, 1011},
+ dictWord{6, 10, 1710},
+ dictWord{135, 10, 2038},
+ dictWord{7, 11, 1763},
+ dictWord{140, 11, 310},
+ dictWord{6, 0, 129},
+ dictWord{4, 10, 17},
+ dictWord{5, 10, 23},
+ dictWord{7, 10, 995},
+ dictWord{11, 10, 383},
+ dictWord{11, 10, 437},
+ dictWord{12, 10, 460},
+ dictWord{140, 10, 532},
+ dictWord{5, 11, 329},
+ dictWord{136, 11, 260},
+ dictWord{133, 10, 862},
+ dictWord{132, 0, 534},
+ dictWord{6, 0, 811},
+ dictWord{135, 0, 626},
+ dictWord{
+ 132,
+ 11,
+ 657,
+ },
+ dictWord{4, 0, 25},
+ dictWord{5, 0, 60},
+ dictWord{6, 0, 504},
+ dictWord{7, 0, 614},
+ dictWord{7, 0, 1155},
+ dictWord{12, 0, 0},
+ dictWord{152, 11, 7},
+ dictWord{
+ 7,
+ 0,
+ 1248,
+ },
+ dictWord{11, 0, 621},
+ dictWord{139, 0, 702},
+ dictWord{137, 0, 321},
+ dictWord{8, 10, 70},
+ dictWord{12, 10, 171},
+ dictWord{141, 10, 272},
+ dictWord{
+ 10,
+ 10,
+ 233,
+ },
+ dictWord{139, 10, 76},
+ dictWord{4, 0, 379},
+ dictWord{7, 0, 1397},
+ dictWord{134, 10, 442},
+ dictWord{5, 11, 66},
+ dictWord{7, 11, 1896},
+ dictWord{
+ 136,
+ 11,
+ 288,
+ },
+ dictWord{134, 11, 1643},
+ dictWord{134, 10, 1709},
+ dictWord{4, 11, 21},
+ dictWord{5, 11, 91},
+ dictWord{5, 11, 570},
+ dictWord{5, 11, 648},
+ dictWord{5, 11, 750},
+ dictWord{5, 11, 781},
+ dictWord{6, 11, 54},
+ dictWord{6, 11, 112},
+ dictWord{6, 11, 402},
+ dictWord{6, 11, 1732},
+ dictWord{7, 11, 315},
+ dictWord{
+ 7,
+ 11,
+ 749,
+ },
+ dictWord{7, 11, 1347},
+ dictWord{7, 11, 1900},
+ dictWord{9, 11, 78},
+ dictWord{9, 11, 508},
+ dictWord{10, 11, 611},
+ dictWord{11, 11, 510},
+ dictWord{
+ 11,
+ 11,
+ 728,
+ },
+ dictWord{13, 11, 36},
+ dictWord{14, 11, 39},
+ dictWord{16, 11, 83},
+ dictWord{17, 11, 124},
+ dictWord{148, 11, 30},
+ dictWord{4, 0, 118},
+ dictWord{
+ 6,
+ 0,
+ 274,
+ },
+ dictWord{6, 0, 361},
+ dictWord{7, 0, 75},
+ dictWord{141, 0, 441},
+ dictWord{10, 11, 322},
+ dictWord{10, 11, 719},
+ dictWord{139, 11, 407},
+ dictWord{
+ 147,
+ 10,
+ 119,
+ },
+ dictWord{12, 11, 549},
+ dictWord{14, 11, 67},
+ dictWord{147, 11, 60},
+ dictWord{11, 10, 69},
+ dictWord{12, 10, 105},
+ dictWord{12, 10, 117},
+ dictWord{13, 10, 213},
+ dictWord{14, 10, 13},
+ dictWord{14, 10, 62},
+ dictWord{14, 10, 177},
+ dictWord{14, 10, 421},
+ dictWord{15, 10, 19},
+ dictWord{146, 10, 141},
+ dictWord{9, 0, 841},
+ dictWord{137, 10, 309},
+ dictWord{7, 10, 608},
+ dictWord{7, 10, 976},
+ dictWord{8, 11, 125},
+ dictWord{8, 11, 369},
+ dictWord{8, 11, 524},
+ dictWord{9, 10, 146},
+ dictWord{10, 10, 206},
+ dictWord{10, 11, 486},
+ dictWord{10, 10, 596},
+ dictWord{11, 11, 13},
+ dictWord{11, 11, 381},
+ dictWord{11, 11, 736},
+ dictWord{11, 11, 766},
+ dictWord{11, 11, 845},
+ dictWord{13, 11, 114},
+ dictWord{13, 10, 218},
+ dictWord{13, 11, 292},
+ dictWord{14, 11, 47},
+ dictWord{
+ 142,
+ 10,
+ 153,
+ },
+ dictWord{12, 0, 693},
+ dictWord{135, 11, 759},
+ dictWord{5, 0, 314},
+ dictWord{6, 0, 221},
+ dictWord{7, 0, 419},
+ dictWord{10, 0, 650},
+ dictWord{11, 0, 396},
+ dictWord{12, 0, 156},
+ dictWord{13, 0, 369},
+ dictWord{14, 0, 333},
+ dictWord{145, 0, 47},
+ dictWord{6, 11, 1684},
+ dictWord{6, 11, 1731},
+ dictWord{7, 11, 356},
+ dictWord{7, 11, 1932},
+ dictWord{8, 11, 54},
+ dictWord{8, 11, 221},
+ dictWord{9, 11, 225},
+ dictWord{9, 11, 356},
+ dictWord{10, 11, 77},
+ dictWord{10, 11, 446},
+ dictWord{10, 11, 731},
+ dictWord{12, 11, 404},
+ dictWord{141, 11, 491},
+ dictWord{132, 11, 375},
+ dictWord{4, 10, 518},
+ dictWord{135, 10, 1136},
+ dictWord{
+ 4,
+ 0,
+ 913,
+ },
+ dictWord{4, 11, 411},
+ dictWord{11, 11, 643},
+ dictWord{140, 11, 115},
+ dictWord{4, 11, 80},
+ dictWord{133, 11, 44},
+ dictWord{8, 10, 689},
+ dictWord{
+ 137,
+ 10,
+ 863,
+ },
+ dictWord{138, 0, 880},
+ dictWord{4, 10, 18},
+ dictWord{7, 10, 145},
+ dictWord{7, 10, 444},
+ dictWord{7, 10, 1278},
+ dictWord{8, 10, 49},
+ dictWord{
+ 8,
+ 10,
+ 400,
+ },
+ dictWord{9, 10, 71},
+ dictWord{9, 10, 250},
+ dictWord{10, 10, 459},
+ dictWord{12, 10, 160},
+ dictWord{144, 10, 24},
+ dictWord{136, 0, 475},
+ dictWord{
+ 5,
+ 0,
+ 1016,
+ },
+ dictWord{5, 11, 299},
+ dictWord{135, 11, 1083},
+ dictWord{7, 0, 602},
+ dictWord{8, 0, 179},
+ dictWord{10, 0, 781},
+ dictWord{140, 0, 126},
+ dictWord{
+ 6,
+ 0,
+ 329,
+ },
+ dictWord{138, 0, 111},
+ dictWord{135, 0, 1864},
+ dictWord{4, 11, 219},
+ dictWord{7, 11, 1761},
+ dictWord{137, 11, 86},
+ dictWord{6, 0, 1888},
+ dictWord{
+ 6,
+ 0,
+ 1892,
+ },
+ dictWord{6, 0, 1901},
+ dictWord{6, 0, 1904},
+ dictWord{9, 0, 953},
+ dictWord{9, 0, 985},
+ dictWord{9, 0, 991},
+ dictWord{9, 0, 1001},
+ dictWord{12, 0, 818},
+ dictWord{12, 0, 846},
+ dictWord{12, 0, 847},
+ dictWord{12, 0, 861},
+ dictWord{12, 0, 862},
+ dictWord{12, 0, 873},
+ dictWord{12, 0, 875},
+ dictWord{12, 0, 877},
+ dictWord{12, 0, 879},
+ dictWord{12, 0, 881},
+ dictWord{12, 0, 884},
+ dictWord{12, 0, 903},
+ dictWord{12, 0, 915},
+ dictWord{12, 0, 926},
+ dictWord{12, 0, 939},
+ dictWord{
+ 15,
+ 0,
+ 182,
+ },
+ dictWord{15, 0, 219},
+ dictWord{15, 0, 255},
+ dictWord{18, 0, 191},
+ dictWord{18, 0, 209},
+ dictWord{18, 0, 211},
+ dictWord{149, 0, 41},
+ dictWord{
+ 5,
+ 11,
+ 328,
+ },
+ dictWord{135, 11, 918},
+ dictWord{137, 0, 780},
+ dictWord{12, 0, 82},
+ dictWord{143, 0, 36},
+ dictWord{133, 10, 1010},
+ dictWord{5, 0, 821},
+ dictWord{
+ 134,
+ 0,
+ 1687,
+ },
+ dictWord{133, 11, 514},
+ dictWord{132, 0, 956},
+ dictWord{134, 0, 1180},
+ dictWord{10, 0, 112},
+ dictWord{5, 10, 87},
+ dictWord{7, 10, 313},
+ dictWord{
+ 7,
+ 10,
+ 1103,
+ },
+ dictWord{10, 10, 582},
+ dictWord{11, 10, 389},
+ dictWord{11, 10, 813},
+ dictWord{12, 10, 385},
+ dictWord{13, 10, 286},
+ dictWord{14, 10, 124},
+ dictWord{146, 10, 108},
+ dictWord{5, 0, 71},
+ dictWord{7, 0, 1407},
+ dictWord{9, 0, 704},
+ dictWord{10, 0, 261},
+ dictWord{10, 0, 619},
+ dictWord{11, 0, 547},
+ dictWord{11, 0, 619},
+ dictWord{143, 0, 157},
+ dictWord{4, 0, 531},
+ dictWord{5, 0, 455},
+ dictWord{5, 11, 301},
+ dictWord{6, 11, 571},
+ dictWord{14, 11, 49},
+ dictWord{
+ 146,
+ 11,
+ 102,
+ },
+ dictWord{132, 10, 267},
+ dictWord{6, 0, 385},
+ dictWord{7, 0, 2008},
+ dictWord{9, 0, 337},
+ dictWord{138, 0, 517},
+ dictWord{133, 11, 726},
+ dictWord{133, 11, 364},
+ dictWord{4, 11, 76},
+ dictWord{7, 11, 1550},
+ dictWord{9, 11, 306},
+ dictWord{9, 11, 430},
+ dictWord{9, 11, 663},
+ dictWord{10, 11, 683},
+ dictWord{11, 11, 427},
+ dictWord{11, 11, 753},
+ dictWord{12, 11, 334},
+ dictWord{12, 11, 442},
+ dictWord{14, 11, 258},
+ dictWord{14, 11, 366},
+ dictWord{
+ 143,
+ 11,
+ 131,
+ },
+ dictWord{6, 0, 1865},
+ dictWord{6, 0, 1879},
+ dictWord{6, 0, 1881},
+ dictWord{6, 0, 1894},
+ dictWord{6, 0, 1908},
+ dictWord{9, 0, 915},
+ dictWord{9, 0, 926},
+ dictWord{9, 0, 940},
+ dictWord{9, 0, 943},
+ dictWord{9, 0, 966},
+ dictWord{9, 0, 980},
+ dictWord{9, 0, 989},
+ dictWord{9, 0, 1005},
+ dictWord{9, 0, 1010},
+ dictWord{
+ 12,
+ 0,
+ 813,
+ },
+ dictWord{12, 0, 817},
+ dictWord{12, 0, 840},
+ dictWord{12, 0, 843},
+ dictWord{12, 0, 855},
+ dictWord{12, 0, 864},
+ dictWord{12, 0, 871},
+ dictWord{12, 0, 872},
+ dictWord{12, 0, 899},
+ dictWord{12, 0, 905},
+ dictWord{12, 0, 924},
+ dictWord{15, 0, 171},
+ dictWord{15, 0, 181},
+ dictWord{15, 0, 224},
+ dictWord{15, 0, 235},
+ dictWord{15, 0, 251},
+ dictWord{146, 0, 184},
+ dictWord{137, 11, 52},
+ dictWord{5, 0, 16},
+ dictWord{6, 0, 86},
+ dictWord{6, 0, 603},
+ dictWord{7, 0, 292},
+ dictWord{7, 0, 561},
+ dictWord{8, 0, 257},
+ dictWord{8, 0, 382},
+ dictWord{9, 0, 721},
+ dictWord{9, 0, 778},
+ dictWord{11, 0, 581},
+ dictWord{140, 0, 466},
+ dictWord{4, 0, 486},
+ dictWord{
+ 5,
+ 0,
+ 491,
+ },
+ dictWord{135, 10, 1121},
+ dictWord{4, 0, 72},
+ dictWord{6, 0, 265},
+ dictWord{135, 0, 1300},
+ dictWord{135, 11, 1183},
+ dictWord{10, 10, 249},
+ dictWord{139, 10, 209},
+ dictWord{132, 10, 561},
+ dictWord{137, 11, 519},
+ dictWord{4, 11, 656},
+ dictWord{4, 10, 760},
+ dictWord{135, 11, 779},
+ dictWord{
+ 9,
+ 10,
+ 154,
+ },
+ dictWord{140, 10, 485},
+ dictWord{135, 11, 1793},
+ dictWord{135, 11, 144},
+ dictWord{136, 10, 255},
+ dictWord{133, 0, 621},
+ dictWord{4, 10, 368},
+ dictWord{135, 10, 641},
+ dictWord{135, 11, 1373},
+ dictWord{7, 11, 554},
+ dictWord{7, 11, 605},
+ dictWord{141, 11, 10},
+ dictWord{137, 0, 234},
+ dictWord{
+ 5,
+ 0,
+ 815,
+ },
+ dictWord{6, 0, 1688},
+ dictWord{134, 0, 1755},
+ dictWord{5, 11, 838},
+ dictWord{5, 11, 841},
+ dictWord{134, 11, 1649},
+ dictWord{7, 0, 1987},
+ dictWord{
+ 7,
+ 0,
+ 2040,
+ },
+ dictWord{136, 0, 743},
+ dictWord{133, 11, 1012},
+ dictWord{6, 0, 197},
+ dictWord{136, 0, 205},
+ dictWord{6, 0, 314},
+ dictWord{134, 11, 314},
+ dictWord{144, 11, 53},
+ dictWord{6, 11, 251},
+ dictWord{7, 11, 365},
+ dictWord{7, 11, 1357},
+ dictWord{7, 11, 1497},
+ dictWord{8, 11, 154},
+ dictWord{141, 11, 281},
+ dictWord{133, 11, 340},
+ dictWord{6, 0, 452},
+ dictWord{7, 0, 312},
+ dictWord{138, 0, 219},
+ dictWord{138, 0, 589},
+ dictWord{4, 0, 333},
+ dictWord{9, 0, 176},
+ dictWord{12, 0, 353},
+ dictWord{141, 0, 187},
+ dictWord{9, 10, 92},
+ dictWord{147, 10, 91},
+ dictWord{134, 0, 1110},
+ dictWord{11, 0, 47},
+ dictWord{139, 11, 495},
+ dictWord{6, 10, 525},
+ dictWord{8, 10, 806},
+ dictWord{9, 10, 876},
+ dictWord{140, 10, 284},
+ dictWord{8, 11, 261},
+ dictWord{9, 11, 144},
+ dictWord{9, 11, 466},
+ dictWord{10, 11, 370},
+ dictWord{12, 11, 470},
+ dictWord{13, 11, 144},
+ dictWord{142, 11, 348},
+ dictWord{137, 11, 897},
+ dictWord{8, 0, 863},
+ dictWord{8, 0, 864},
+ dictWord{8, 0, 868},
+ dictWord{8, 0, 884},
+ dictWord{10, 0, 866},
+ dictWord{10, 0, 868},
+ dictWord{10, 0, 873},
+ dictWord{10, 0, 911},
+ dictWord{10, 0, 912},
+ dictWord{
+ 10,
+ 0,
+ 944,
+ },
+ dictWord{12, 0, 727},
+ dictWord{6, 11, 248},
+ dictWord{9, 11, 546},
+ dictWord{10, 11, 535},
+ dictWord{11, 11, 681},
+ dictWord{141, 11, 135},
+ dictWord{
+ 6,
+ 0,
+ 300,
+ },
+ dictWord{135, 0, 1515},
+ dictWord{134, 0, 1237},
+ dictWord{139, 10, 958},
+ dictWord{133, 10, 594},
+ dictWord{140, 11, 250},
+ dictWord{
+ 134,
+ 0,
+ 1685,
+ },
+ dictWord{134, 11, 567},
+ dictWord{7, 0, 135},
+ dictWord{8, 0, 7},
+ dictWord{8, 0, 62},
+ dictWord{9, 0, 243},
+ dictWord{10, 0, 658},
+ dictWord{10, 0, 697},
+ dictWord{11, 0, 456},
+ dictWord{139, 0, 756},
+ dictWord{9, 0, 395},
+ dictWord{138, 0, 79},
+ dictWord{6, 10, 1641},
+ dictWord{136, 10, 820},
+ dictWord{4, 10, 302},
+ dictWord{135, 10, 1766},
+ dictWord{134, 11, 174},
+ dictWord{135, 10, 1313},
+ dictWord{135, 0, 631},
+ dictWord{134, 10, 1674},
+ dictWord{134, 11, 395},
+ dictWord{138, 0, 835},
+ dictWord{7, 0, 406},
+ dictWord{7, 0, 459},
+ dictWord{8, 0, 606},
+ dictWord{139, 0, 726},
+ dictWord{134, 11, 617},
+ dictWord{134, 0, 979},
+ dictWord{
+ 6,
+ 10,
+ 389,
+ },
+ dictWord{7, 10, 149},
+ dictWord{9, 10, 142},
+ dictWord{138, 10, 94},
+ dictWord{5, 11, 878},
+ dictWord{133, 11, 972},
+ dictWord{6, 10, 8},
+ dictWord{
+ 7,
+ 10,
+ 1881,
+ },
+ dictWord{8, 10, 91},
+ dictWord{136, 11, 511},
+ dictWord{133, 0, 612},
+ dictWord{132, 11, 351},
+ dictWord{4, 0, 372},
+ dictWord{7, 0, 482},
+ dictWord{
+ 8,
+ 0,
+ 158,
+ },
+ dictWord{9, 0, 602},
+ dictWord{9, 0, 615},
+ dictWord{10, 0, 245},
+ dictWord{10, 0, 678},
+ dictWord{10, 0, 744},
+ dictWord{11, 0, 248},
+ dictWord{
+ 139,
+ 0,
+ 806,
+ },
+ dictWord{5, 0, 854},
+ dictWord{135, 0, 1991},
+ dictWord{132, 11, 286},
+ dictWord{135, 11, 344},
+ dictWord{7, 11, 438},
+ dictWord{7, 11, 627},
+ dictWord{
+ 7,
+ 11,
+ 1516,
+ },
+ dictWord{8, 11, 40},
+ dictWord{9, 11, 56},
+ dictWord{9, 11, 294},
+ dictWord{10, 11, 30},
+ dictWord{10, 11, 259},
+ dictWord{11, 11, 969},
+ dictWord{
+ 146,
+ 11,
+ 148,
+ },
+ dictWord{135, 0, 1492},
+ dictWord{5, 11, 259},
+ dictWord{7, 11, 414},
+ dictWord{7, 11, 854},
+ dictWord{142, 11, 107},
+ dictWord{135, 10, 1746},
+ dictWord{6, 0, 833},
+ dictWord{134, 0, 998},
+ dictWord{135, 10, 24},
+ dictWord{6, 0, 750},
+ dictWord{135, 0, 1739},
+ dictWord{4, 10, 503},
+ dictWord{
+ 135,
+ 10,
+ 1661,
+ },
+ dictWord{5, 10, 130},
+ dictWord{7, 10, 1314},
+ dictWord{9, 10, 610},
+ dictWord{10, 10, 718},
+ dictWord{11, 10, 601},
+ dictWord{11, 10, 819},
+ dictWord{
+ 11,
+ 10,
+ 946,
+ },
+ dictWord{140, 10, 536},
+ dictWord{10, 10, 149},
+ dictWord{11, 10, 280},
+ dictWord{142, 10, 336},
+ dictWord{132, 11, 738},
+ dictWord{
+ 135,
+ 10,
+ 1946,
+ },
+ dictWord{5, 0, 195},
+ dictWord{135, 0, 1685},
+ dictWord{7, 0, 1997},
+ dictWord{8, 0, 730},
+ dictWord{139, 0, 1006},
+ dictWord{151, 11, 17},
+ dictWord{
+ 133,
+ 11,
+ 866,
+ },
+ dictWord{14, 0, 463},
+ dictWord{14, 0, 470},
+ dictWord{150, 0, 61},
+ dictWord{5, 0, 751},
+ dictWord{8, 0, 266},
+ dictWord{11, 0, 578},
+ dictWord{
+ 4,
+ 10,
+ 392,
+ },
+ dictWord{135, 10, 1597},
+ dictWord{5, 10, 433},
+ dictWord{9, 10, 633},
+ dictWord{139, 10, 629},
+ dictWord{135, 0, 821},
+ dictWord{6, 0, 715},
+ dictWord{
+ 134,
+ 0,
+ 1325,
+ },
+ dictWord{133, 11, 116},
+ dictWord{6, 0, 868},
+ dictWord{132, 11, 457},
+ dictWord{134, 0, 959},
+ dictWord{6, 10, 234},
+ dictWord{138, 11, 199},
+ dictWord{7, 0, 1053},
+ dictWord{7, 10, 1950},
+ dictWord{8, 10, 680},
+ dictWord{11, 10, 817},
+ dictWord{147, 10, 88},
+ dictWord{7, 10, 1222},
+ dictWord{
+ 138,
+ 10,
+ 386,
+ },
+ dictWord{5, 0, 950},
+ dictWord{5, 0, 994},
+ dictWord{6, 0, 351},
+ dictWord{134, 0, 1124},
+ dictWord{134, 0, 1081},
+ dictWord{7, 0, 1595},
+ dictWord{6, 10, 5},
+ dictWord{11, 10, 249},
+ dictWord{12, 10, 313},
+ dictWord{16, 10, 66},
+ dictWord{145, 10, 26},
+ dictWord{148, 0, 59},
+ dictWord{5, 11, 527},
+ dictWord{6, 11, 189},
+ dictWord{135, 11, 859},
+ dictWord{5, 10, 963},
+ dictWord{6, 10, 1773},
+ dictWord{11, 11, 104},
+ dictWord{11, 11, 554},
+ dictWord{15, 11, 60},
+ dictWord{
+ 143,
+ 11,
+ 125,
+ },
+ dictWord{135, 0, 47},
+ dictWord{137, 0, 684},
+ dictWord{134, 11, 116},
+ dictWord{134, 0, 1606},
+ dictWord{134, 0, 777},
+ dictWord{7, 0, 1020},
+ dictWord{
+ 8,
+ 10,
+ 509,
+ },
+ dictWord{136, 10, 792},
+ dictWord{135, 0, 1094},
+ dictWord{132, 0, 350},
+ dictWord{133, 11, 487},
+ dictWord{4, 11, 86},
+ dictWord{5, 11, 667},
+ dictWord{5, 11, 753},
+ dictWord{6, 11, 316},
+ dictWord{6, 11, 455},
+ dictWord{135, 11, 946},
+ dictWord{7, 0, 1812},
+ dictWord{13, 0, 259},
+ dictWord{13, 0, 356},
+ dictWord{14, 0, 242},
+ dictWord{147, 0, 114},
+ dictWord{132, 10, 931},
+ dictWord{133, 0, 967},
+ dictWord{4, 0, 473},
+ dictWord{7, 0, 623},
+ dictWord{8, 0, 808},
+ dictWord{
+ 9,
+ 0,
+ 871,
+ },
+ dictWord{9, 0, 893},
+ dictWord{11, 0, 38},
+ dictWord{11, 0, 431},
+ dictWord{12, 0, 112},
+ dictWord{12, 0, 217},
+ dictWord{12, 0, 243},
+ dictWord{12, 0, 562},
+ dictWord{12, 0, 663},
+ dictWord{12, 0, 683},
+ dictWord{13, 0, 141},
+ dictWord{13, 0, 197},
+ dictWord{13, 0, 227},
+ dictWord{13, 0, 406},
+ dictWord{13, 0, 487},
+ dictWord{14, 0, 156},
+ dictWord{14, 0, 203},
+ dictWord{14, 0, 224},
+ dictWord{14, 0, 256},
+ dictWord{18, 0, 58},
+ dictWord{150, 0, 0},
+ dictWord{138, 0, 286},
+ dictWord{
+ 7,
+ 10,
+ 943,
+ },
+ dictWord{139, 10, 614},
+ dictWord{135, 10, 1837},
+ dictWord{150, 11, 45},
+ dictWord{132, 0, 798},
+ dictWord{4, 0, 222},
+ dictWord{7, 0, 286},
+ dictWord{136, 0, 629},
+ dictWord{4, 11, 79},
+ dictWord{7, 11, 1773},
+ dictWord{10, 11, 450},
+ dictWord{11, 11, 589},
+ dictWord{13, 11, 332},
+ dictWord{13, 11, 493},
+ dictWord{14, 11, 183},
+ dictWord{14, 11, 334},
+ dictWord{14, 11, 362},
+ dictWord{14, 11, 368},
+ dictWord{14, 11, 376},
+ dictWord{14, 11, 379},
+ dictWord{
+ 19,
+ 11,
+ 90,
+ },
+ dictWord{19, 11, 103},
+ dictWord{19, 11, 127},
+ dictWord{148, 11, 90},
+ dictWord{5, 0, 337},
+ dictWord{11, 0, 513},
+ dictWord{11, 0, 889},
+ dictWord{
+ 11,
+ 0,
+ 961,
+ },
+ dictWord{12, 0, 461},
+ dictWord{13, 0, 79},
+ dictWord{15, 0, 121},
+ dictWord{4, 10, 90},
+ dictWord{5, 10, 545},
+ dictWord{7, 10, 754},
+ dictWord{9, 10, 186},
+ dictWord{10, 10, 72},
+ dictWord{10, 10, 782},
+ dictWord{11, 10, 577},
+ dictWord{11, 10, 610},
+ dictWord{12, 10, 354},
+ dictWord{12, 10, 362},
+ dictWord{
+ 140,
+ 10,
+ 595,
+ },
+ dictWord{141, 0, 306},
+ dictWord{136, 0, 146},
+ dictWord{7, 0, 1646},
+ dictWord{9, 10, 329},
+ dictWord{11, 10, 254},
+ dictWord{141, 11, 124},
+ dictWord{
+ 4,
+ 0,
+ 465,
+ },
+ dictWord{135, 0, 1663},
+ dictWord{132, 0, 525},
+ dictWord{133, 11, 663},
+ dictWord{10, 0, 299},
+ dictWord{18, 0, 74},
+ dictWord{9, 10, 187},
+ dictWord{
+ 11,
+ 10,
+ 1016,
+ },
+ dictWord{145, 10, 44},
+ dictWord{7, 0, 165},
+ dictWord{7, 0, 919},
+ dictWord{4, 10, 506},
+ dictWord{136, 10, 517},
+ dictWord{5, 10, 295},
+ dictWord{
+ 135,
+ 10,
+ 1680,
+ },
+ dictWord{133, 11, 846},
+ dictWord{134, 0, 1064},
+ dictWord{5, 11, 378},
+ dictWord{7, 11, 1402},
+ dictWord{7, 11, 1414},
+ dictWord{8, 11, 465},
+ dictWord{9, 11, 286},
+ dictWord{10, 11, 185},
+ dictWord{10, 11, 562},
+ dictWord{10, 11, 635},
+ dictWord{11, 11, 31},
+ dictWord{11, 11, 393},
+ dictWord{
+ 12,
+ 11,
+ 456,
+ },
+ dictWord{13, 11, 312},
+ dictWord{18, 11, 65},
+ dictWord{18, 11, 96},
+ dictWord{147, 11, 89},
+ dictWord{132, 0, 596},
+ dictWord{7, 10, 987},
+ dictWord{
+ 9,
+ 10,
+ 688,
+ },
+ dictWord{10, 10, 522},
+ dictWord{11, 10, 788},
+ dictWord{140, 10, 566},
+ dictWord{6, 0, 82},
+ dictWord{7, 0, 138},
+ dictWord{7, 0, 517},
+ dictWord{7, 0, 1741},
+ dictWord{11, 0, 238},
+ dictWord{4, 11, 648},
+ dictWord{134, 10, 1775},
+ dictWord{7, 0, 1233},
+ dictWord{7, 10, 700},
+ dictWord{7, 10, 940},
+ dictWord{8, 10, 514},
+ dictWord{9, 10, 116},
+ dictWord{9, 10, 535},
+ dictWord{10, 10, 118},
+ dictWord{11, 10, 107},
+ dictWord{11, 10, 148},
+ dictWord{11, 10, 922},
+ dictWord{
+ 12,
+ 10,
+ 254,
+ },
+ dictWord{12, 10, 421},
+ dictWord{142, 10, 238},
+ dictWord{4, 0, 962},
+ dictWord{6, 0, 1824},
+ dictWord{8, 0, 894},
+ dictWord{12, 0, 708},
+ dictWord{
+ 12,
+ 0,
+ 725,
+ },
+ dictWord{14, 0, 451},
+ dictWord{20, 0, 94},
+ dictWord{22, 0, 59},
+ dictWord{150, 0, 62},
+ dictWord{5, 11, 945},
+ dictWord{6, 11, 1656},
+ dictWord{6, 11, 1787},
+ dictWord{7, 11, 167},
+ dictWord{8, 11, 824},
+ dictWord{9, 11, 391},
+ dictWord{10, 11, 375},
+ dictWord{139, 11, 185},
+ dictWord{5, 0, 495},
+ dictWord{7, 0, 834},
+ dictWord{9, 0, 733},
+ dictWord{139, 0, 378},
+ dictWord{4, 10, 743},
+ dictWord{135, 11, 1273},
+ dictWord{6, 0, 1204},
+ dictWord{7, 11, 1645},
+ dictWord{8, 11, 352},
+ dictWord{137, 11, 249},
+ dictWord{139, 10, 292},
+ dictWord{133, 0, 559},
+ dictWord{132, 11, 152},
+ dictWord{9, 0, 499},
+ dictWord{10, 0, 341},
+ dictWord{
+ 15,
+ 0,
+ 144,
+ },
+ dictWord{19, 0, 49},
+ dictWord{7, 10, 1283},
+ dictWord{9, 10, 227},
+ dictWord{11, 10, 325},
+ dictWord{11, 10, 408},
+ dictWord{14, 10, 180},
+ dictWord{
+ 146,
+ 10,
+ 47,
+ },
+ dictWord{6, 0, 21},
+ dictWord{6, 0, 1737},
+ dictWord{7, 0, 1444},
+ dictWord{136, 0, 224},
+ dictWord{133, 11, 1006},
+ dictWord{7, 0, 1446},
+ dictWord{
+ 9,
+ 0,
+ 97,
+ },
+ dictWord{17, 0, 15},
+ dictWord{5, 10, 81},
+ dictWord{7, 10, 146},
+ dictWord{7, 10, 1342},
+ dictWord{8, 10, 53},
+ dictWord{8, 10, 561},
+ dictWord{8, 10, 694},
+ dictWord{8, 10, 754},
+ dictWord{9, 10, 115},
+ dictWord{9, 10, 894},
+ dictWord{10, 10, 462},
+ dictWord{10, 10, 813},
+ dictWord{11, 10, 230},
+ dictWord{11, 10, 657},
+ dictWord{11, 10, 699},
+ dictWord{11, 10, 748},
+ dictWord{12, 10, 119},
+ dictWord{12, 10, 200},
+ dictWord{12, 10, 283},
+ dictWord{142, 10, 273},
+ dictWord{
+ 5,
+ 10,
+ 408,
+ },
+ dictWord{137, 10, 747},
+ dictWord{135, 11, 431},
+ dictWord{135, 11, 832},
+ dictWord{6, 0, 729},
+ dictWord{134, 0, 953},
+ dictWord{4, 0, 727},
+ dictWord{
+ 8,
+ 0,
+ 565,
+ },
+ dictWord{5, 11, 351},
+ dictWord{7, 11, 264},
+ dictWord{136, 11, 565},
+ dictWord{134, 0, 1948},
+ dictWord{5, 0, 519},
+ dictWord{5, 11, 40},
+ dictWord{
+ 7,
+ 11,
+ 598,
+ },
+ dictWord{7, 11, 1638},
+ dictWord{8, 11, 78},
+ dictWord{9, 11, 166},
+ dictWord{9, 11, 640},
+ dictWord{9, 11, 685},
+ dictWord{9, 11, 773},
+ dictWord{
+ 11,
+ 11,
+ 215,
+ },
+ dictWord{13, 11, 65},
+ dictWord{14, 11, 172},
+ dictWord{14, 11, 317},
+ dictWord{145, 11, 6},
+ dictWord{8, 11, 60},
+ dictWord{9, 11, 343},
+ dictWord{
+ 139,
+ 11,
+ 769,
+ },
+ dictWord{137, 11, 455},
+ dictWord{134, 0, 1193},
+ dictWord{140, 0, 790},
+ dictWord{7, 11, 1951},
+ dictWord{8, 11, 765},
+ dictWord{8, 11, 772},
+ dictWord{140, 11, 671},
+ dictWord{7, 11, 108},
+ dictWord{8, 11, 219},
+ dictWord{8, 11, 388},
+ dictWord{9, 11, 639},
+ dictWord{9, 11, 775},
+ dictWord{11, 11, 275},
+ dictWord{140, 11, 464},
+ dictWord{132, 11, 468},
+ dictWord{7, 10, 30},
+ dictWord{8, 10, 86},
+ dictWord{8, 10, 315},
+ dictWord{8, 10, 700},
+ dictWord{9, 10, 576},
+ dictWord{
+ 9,
+ 10,
+ 858,
+ },
+ dictWord{11, 10, 310},
+ dictWord{11, 10, 888},
+ dictWord{11, 10, 904},
+ dictWord{12, 10, 361},
+ dictWord{141, 10, 248},
+ dictWord{5, 11, 15},
+ dictWord{6, 11, 56},
+ dictWord{7, 11, 1758},
+ dictWord{8, 11, 500},
+ dictWord{9, 11, 730},
+ dictWord{11, 11, 331},
+ dictWord{13, 11, 150},
+ dictWord{142, 11, 282},
+ dictWord{4, 0, 402},
+ dictWord{7, 0, 2},
+ dictWord{8, 0, 323},
+ dictWord{136, 0, 479},
+ dictWord{138, 10, 839},
+ dictWord{11, 0, 580},
+ dictWord{142, 0, 201},
+ dictWord{
+ 5,
+ 0,
+ 59,
+ },
+ dictWord{135, 0, 672},
+ dictWord{137, 10, 617},
+ dictWord{146, 0, 34},
+ dictWord{134, 11, 1886},
+ dictWord{4, 0, 961},
+ dictWord{136, 0, 896},
+ dictWord{
+ 6,
+ 0,
+ 1285,
+ },
+ dictWord{5, 11, 205},
+ dictWord{6, 11, 438},
+ dictWord{137, 11, 711},
+ dictWord{134, 10, 428},
+ dictWord{7, 10, 524},
+ dictWord{8, 10, 169},
+ dictWord{8, 10, 234},
+ dictWord{9, 10, 480},
+ dictWord{138, 10, 646},
+ dictWord{148, 0, 46},
+ dictWord{141, 0, 479},
+ dictWord{133, 11, 534},
+ dictWord{6, 0, 2019},
+ dictWord{134, 10, 1648},
+ dictWord{4, 0, 85},
+ dictWord{7, 0, 549},
+ dictWord{7, 10, 1205},
+ dictWord{138, 10, 637},
+ dictWord{4, 0, 663},
+ dictWord{5, 0, 94},
+ dictWord{
+ 7,
+ 11,
+ 235,
+ },
+ dictWord{7, 11, 1475},
+ dictWord{15, 11, 68},
+ dictWord{146, 11, 120},
+ dictWord{6, 11, 443},
+ dictWord{9, 11, 237},
+ dictWord{9, 11, 571},
+ dictWord{
+ 9,
+ 11,
+ 695,
+ },
+ dictWord{10, 11, 139},
+ dictWord{11, 11, 715},
+ dictWord{12, 11, 417},
+ dictWord{141, 11, 421},
+ dictWord{132, 0, 783},
+ dictWord{4, 0, 682},
+ dictWord{8, 0, 65},
+ dictWord{9, 10, 39},
+ dictWord{10, 10, 166},
+ dictWord{11, 10, 918},
+ dictWord{12, 10, 635},
+ dictWord{20, 10, 10},
+ dictWord{22, 10, 27},
+ dictWord{
+ 22,
+ 10,
+ 43,
+ },
+ dictWord{150, 10, 52},
+ dictWord{6, 0, 11},
+ dictWord{135, 0, 187},
+ dictWord{132, 0, 522},
+ dictWord{4, 0, 52},
+ dictWord{135, 0, 661},
+ dictWord{
+ 4,
+ 0,
+ 383,
+ },
+ dictWord{133, 0, 520},
+ dictWord{135, 11, 546},
+ dictWord{11, 0, 343},
+ dictWord{142, 0, 127},
+ dictWord{4, 11, 578},
+ dictWord{7, 10, 157},
+ dictWord{
+ 7,
+ 11,
+ 624,
+ },
+ dictWord{7, 11, 916},
+ dictWord{8, 10, 279},
+ dictWord{10, 11, 256},
+ dictWord{11, 11, 87},
+ dictWord{139, 11, 703},
+ dictWord{134, 10, 604},
+ dictWord{
+ 4,
+ 0,
+ 281,
+ },
+ dictWord{5, 0, 38},
+ dictWord{7, 0, 194},
+ dictWord{7, 0, 668},
+ dictWord{7, 0, 1893},
+ dictWord{137, 0, 397},
+ dictWord{7, 10, 945},
+ dictWord{11, 10, 713},
+ dictWord{139, 10, 744},
+ dictWord{139, 10, 1022},
+ dictWord{9, 0, 635},
+ dictWord{139, 0, 559},
+ dictWord{5, 11, 923},
+ dictWord{7, 11, 490},
+ dictWord{
+ 12,
+ 11,
+ 553,
+ },
+ dictWord{13, 11, 100},
+ dictWord{14, 11, 118},
+ dictWord{143, 11, 75},
+ dictWord{132, 0, 975},
+ dictWord{132, 10, 567},
+ dictWord{137, 10, 859},
+ dictWord{7, 10, 1846},
+ dictWord{7, 11, 1846},
+ dictWord{8, 10, 628},
+ dictWord{136, 11, 628},
+ dictWord{148, 0, 116},
+ dictWord{138, 11, 750},
+ dictWord{14, 0, 51},
+ dictWord{14, 11, 51},
+ dictWord{15, 11, 7},
+ dictWord{148, 11, 20},
+ dictWord{132, 0, 858},
+ dictWord{134, 0, 1075},
+ dictWord{4, 11, 924},
+ dictWord{
+ 133,
+ 10,
+ 762,
+ },
+ dictWord{136, 0, 535},
+ dictWord{133, 0, 448},
+ dictWord{10, 10, 784},
+ dictWord{141, 10, 191},
+ dictWord{133, 10, 298},
+ dictWord{7, 0, 610},
+ dictWord{135, 0, 1501},
+ dictWord{7, 10, 633},
+ dictWord{7, 10, 905},
+ dictWord{7, 10, 909},
+ dictWord{7, 10, 1538},
+ dictWord{9, 10, 767},
+ dictWord{140, 10, 636},
+ dictWord{4, 11, 265},
+ dictWord{7, 11, 807},
+ dictWord{135, 11, 950},
+ dictWord{5, 11, 93},
+ dictWord{12, 11, 267},
+ dictWord{144, 11, 26},
+ dictWord{136, 0, 191},
+ dictWord{139, 10, 301},
+ dictWord{135, 10, 1970},
+ dictWord{135, 0, 267},
+ dictWord{4, 0, 319},
+ dictWord{5, 0, 699},
+ dictWord{138, 0, 673},
+ dictWord{
+ 6,
+ 0,
+ 336,
+ },
+ dictWord{7, 0, 92},
+ dictWord{7, 0, 182},
+ dictWord{8, 0, 453},
+ dictWord{8, 0, 552},
+ dictWord{9, 0, 204},
+ dictWord{9, 0, 285},
+ dictWord{10, 0, 99},
+ dictWord{
+ 11,
+ 0,
+ 568,
+ },
+ dictWord{11, 0, 950},
+ dictWord{12, 0, 94},
+ dictWord{16, 0, 20},
+ dictWord{16, 0, 70},
+ dictWord{19, 0, 55},
+ dictWord{12, 10, 644},
+ dictWord{144, 10, 90},
+ dictWord{6, 0, 551},
+ dictWord{7, 0, 1308},
+ dictWord{7, 10, 845},
+ dictWord{7, 11, 994},
+ dictWord{8, 10, 160},
+ dictWord{137, 10, 318},
+ dictWord{19, 11, 1},
+ dictWord{
+ 19,
+ 11,
+ 26,
+ },
+ dictWord{150, 11, 9},
+ dictWord{7, 0, 1406},
+ dictWord{9, 0, 218},
+ dictWord{141, 0, 222},
+ dictWord{5, 0, 256},
+ dictWord{138, 0, 69},
+ dictWord{
+ 5,
+ 11,
+ 233,
+ },
+ dictWord{5, 11, 320},
+ dictWord{6, 11, 140},
+ dictWord{7, 11, 330},
+ dictWord{136, 11, 295},
+ dictWord{6, 0, 1980},
+ dictWord{136, 0, 952},
+ dictWord{
+ 4,
+ 0,
+ 833,
+ },
+ dictWord{137, 11, 678},
+ dictWord{133, 11, 978},
+ dictWord{4, 11, 905},
+ dictWord{6, 11, 1701},
+ dictWord{137, 11, 843},
+ dictWord{138, 10, 735},
+ dictWord{136, 10, 76},
+ dictWord{17, 0, 39},
+ dictWord{148, 0, 36},
+ dictWord{18, 0, 81},
+ dictWord{146, 11, 81},
+ dictWord{14, 0, 352},
+ dictWord{17, 0, 53},
+ dictWord{
+ 18,
+ 0,
+ 146,
+ },
+ dictWord{18, 0, 152},
+ dictWord{19, 0, 11},
+ dictWord{150, 0, 54},
+ dictWord{135, 0, 634},
+ dictWord{138, 10, 841},
+ dictWord{132, 0, 618},
+ dictWord{
+ 4,
+ 0,
+ 339,
+ },
+ dictWord{7, 0, 259},
+ dictWord{17, 0, 73},
+ dictWord{4, 11, 275},
+ dictWord{140, 11, 376},
+ dictWord{132, 11, 509},
+ dictWord{7, 11, 273},
+ dictWord{
+ 139,
+ 11,
+ 377,
+ },
+ dictWord{4, 0, 759},
+ dictWord{13, 0, 169},
+ dictWord{137, 10, 804},
+ dictWord{6, 10, 96},
+ dictWord{135, 10, 1426},
+ dictWord{4, 10, 651},
+ dictWord{133, 10, 289},
+ dictWord{7, 0, 1075},
+ dictWord{8, 10, 35},
+ dictWord{9, 10, 511},
+ dictWord{10, 10, 767},
+ dictWord{147, 10, 118},
+ dictWord{6, 0, 649},
+ dictWord{6, 0, 670},
+ dictWord{136, 0, 482},
+ dictWord{5, 0, 336},
+ dictWord{6, 0, 341},
+ dictWord{6, 0, 478},
+ dictWord{6, 0, 1763},
+ dictWord{136, 0, 386},
+ dictWord{
+ 5,
+ 11,
+ 802,
+ },
+ dictWord{7, 11, 2021},
+ dictWord{8, 11, 805},
+ dictWord{14, 11, 94},
+ dictWord{15, 11, 65},
+ dictWord{16, 11, 4},
+ dictWord{16, 11, 77},
+ dictWord{16, 11, 80},
+ dictWord{145, 11, 5},
+ dictWord{6, 0, 1035},
+ dictWord{5, 11, 167},
+ dictWord{5, 11, 899},
+ dictWord{6, 11, 410},
+ dictWord{137, 11, 777},
+ dictWord{
+ 134,
+ 11,
+ 1705,
+ },
+ dictWord{5, 0, 924},
+ dictWord{133, 0, 969},
+ dictWord{132, 10, 704},
+ dictWord{135, 0, 73},
+ dictWord{135, 11, 10},
+ dictWord{135, 10, 1078},
+ dictWord{
+ 5,
+ 11,
+ 11,
+ },
+ dictWord{6, 11, 117},
+ dictWord{6, 11, 485},
+ dictWord{7, 11, 1133},
+ dictWord{9, 11, 582},
+ dictWord{9, 11, 594},
+ dictWord{11, 11, 21},
+ dictWord{
+ 11,
+ 11,
+ 818,
+ },
+ dictWord{12, 11, 535},
+ dictWord{141, 11, 86},
+ dictWord{135, 0, 1971},
+ dictWord{4, 11, 264},
+ dictWord{7, 11, 1067},
+ dictWord{8, 11, 204},
+ dictWord{8, 11, 385},
+ dictWord{139, 11, 953},
+ dictWord{6, 0, 1458},
+ dictWord{135, 0, 1344},
+ dictWord{5, 0, 396},
+ dictWord{134, 0, 501},
+ dictWord{4, 10, 720},
+ dictWord{133, 10, 306},
+ dictWord{4, 0, 929},
+ dictWord{5, 0, 799},
+ dictWord{8, 0, 46},
+ dictWord{8, 0, 740},
+ dictWord{133, 10, 431},
+ dictWord{7, 11, 646},
+ dictWord{
+ 7,
+ 11,
+ 1730,
+ },
+ dictWord{11, 11, 446},
+ dictWord{141, 11, 178},
+ dictWord{7, 0, 276},
+ dictWord{5, 10, 464},
+ dictWord{6, 10, 236},
+ dictWord{7, 10, 696},
+ dictWord{
+ 7,
+ 10,
+ 914,
+ },
+ dictWord{7, 10, 1108},
+ dictWord{7, 10, 1448},
+ dictWord{9, 10, 15},
+ dictWord{9, 10, 564},
+ dictWord{10, 10, 14},
+ dictWord{12, 10, 565},
+ dictWord{
+ 13,
+ 10,
+ 449,
+ },
+ dictWord{14, 10, 53},
+ dictWord{15, 10, 13},
+ dictWord{16, 10, 64},
+ dictWord{145, 10, 41},
+ dictWord{4, 0, 892},
+ dictWord{133, 0, 770},
+ dictWord{
+ 6,
+ 10,
+ 1767,
+ },
+ dictWord{12, 10, 194},
+ dictWord{145, 10, 107},
+ dictWord{135, 0, 158},
+ dictWord{5, 10, 840},
+ dictWord{138, 11, 608},
+ dictWord{134, 0, 1432},
+ dictWord{138, 11, 250},
+ dictWord{8, 11, 794},
+ dictWord{9, 11, 400},
+ dictWord{10, 11, 298},
+ dictWord{142, 11, 228},
+ dictWord{151, 0, 25},
+ dictWord{
+ 7,
+ 11,
+ 1131,
+ },
+ dictWord{135, 11, 1468},
+ dictWord{135, 0, 2001},
+ dictWord{9, 10, 642},
+ dictWord{11, 10, 236},
+ dictWord{142, 10, 193},
+ dictWord{4, 10, 68},
+ dictWord{5, 10, 634},
+ dictWord{6, 10, 386},
+ dictWord{7, 10, 794},
+ dictWord{8, 10, 273},
+ dictWord{9, 10, 563},
+ dictWord{10, 10, 105},
+ dictWord{10, 10, 171},
+ dictWord{11, 10, 94},
+ dictWord{139, 10, 354},
+ dictWord{136, 11, 724},
+ dictWord{132, 0, 478},
+ dictWord{11, 11, 512},
+ dictWord{13, 11, 205},
+ dictWord{
+ 19,
+ 11,
+ 30,
+ },
+ dictWord{22, 11, 36},
+ dictWord{151, 11, 19},
+ dictWord{7, 0, 1461},
+ dictWord{140, 0, 91},
+ dictWord{6, 11, 190},
+ dictWord{7, 11, 768},
+ dictWord{
+ 135,
+ 11,
+ 1170,
+ },
+ dictWord{4, 0, 602},
+ dictWord{8, 0, 211},
+ dictWord{4, 10, 95},
+ dictWord{7, 10, 416},
+ dictWord{139, 10, 830},
+ dictWord{7, 10, 731},
+ dictWord{13, 10, 20},
+ dictWord{143, 10, 11},
+ dictWord{6, 0, 1068},
+ dictWord{135, 0, 1872},
+ dictWord{4, 0, 13},
+ dictWord{5, 0, 567},
+ dictWord{7, 0, 1498},
+ dictWord{9, 0, 124},
+ dictWord{11, 0, 521},
+ dictWord{12, 0, 405},
+ dictWord{135, 11, 1023},
+ dictWord{135, 0, 1006},
+ dictWord{132, 0, 735},
+ dictWord{138, 0, 812},
+ dictWord{4, 0, 170},
+ dictWord{135, 0, 323},
+ dictWord{6, 11, 137},
+ dictWord{9, 11, 75},
+ dictWord{9, 11, 253},
+ dictWord{10, 11, 194},
+ dictWord{138, 11, 444},
+ dictWord{5, 0, 304},
+ dictWord{7, 0, 1403},
+ dictWord{5, 10, 864},
+ dictWord{10, 10, 648},
+ dictWord{11, 10, 671},
+ dictWord{143, 10, 46},
+ dictWord{135, 11, 1180},
+ dictWord{
+ 133,
+ 10,
+ 928,
+ },
+ dictWord{4, 0, 148},
+ dictWord{133, 0, 742},
+ dictWord{11, 10, 986},
+ dictWord{140, 10, 682},
+ dictWord{133, 0, 523},
+ dictWord{135, 11, 1743},
+ dictWord{7, 0, 730},
+ dictWord{18, 0, 144},
+ dictWord{19, 0, 61},
+ dictWord{8, 10, 44},
+ dictWord{9, 10, 884},
+ dictWord{10, 10, 580},
+ dictWord{11, 10, 399},
+ dictWord{
+ 11,
+ 10,
+ 894,
+ },
+ dictWord{143, 10, 122},
+ dictWord{5, 11, 760},
+ dictWord{7, 11, 542},
+ dictWord{8, 11, 135},
+ dictWord{136, 11, 496},
+ dictWord{136, 0, 981},
+ dictWord{133, 0, 111},
+ dictWord{10, 0, 132},
+ dictWord{11, 0, 191},
+ dictWord{11, 0, 358},
+ dictWord{139, 0, 460},
+ dictWord{7, 11, 319},
+ dictWord{7, 11, 355},
+ dictWord{
+ 7,
+ 11,
+ 763,
+ },
+ dictWord{10, 11, 389},
+ dictWord{145, 11, 43},
+ dictWord{134, 0, 890},
+ dictWord{134, 0, 1420},
+ dictWord{136, 11, 557},
+ dictWord{
+ 133,
+ 10,
+ 518,
+ },
+ dictWord{133, 0, 444},
+ dictWord{135, 0, 1787},
+ dictWord{135, 10, 1852},
+ dictWord{8, 0, 123},
+ dictWord{15, 0, 6},
+ dictWord{144, 0, 7},
+ dictWord{
+ 6,
+ 0,
+ 2041,
+ },
+ dictWord{10, 11, 38},
+ dictWord{139, 11, 784},
+ dictWord{136, 0, 932},
+ dictWord{5, 0, 937},
+ dictWord{135, 0, 100},
+ dictWord{6, 0, 995},
+ dictWord{
+ 4,
+ 11,
+ 58,
+ },
+ dictWord{5, 11, 286},
+ dictWord{6, 11, 319},
+ dictWord{7, 11, 402},
+ dictWord{7, 11, 1254},
+ dictWord{7, 11, 1903},
+ dictWord{8, 11, 356},
+ dictWord{
+ 140,
+ 11,
+ 408,
+ },
+ dictWord{4, 11, 389},
+ dictWord{9, 11, 181},
+ dictWord{9, 11, 255},
+ dictWord{10, 11, 8},
+ dictWord{10, 11, 29},
+ dictWord{10, 11, 816},
+ dictWord{
+ 11,
+ 11,
+ 311,
+ },
+ dictWord{11, 11, 561},
+ dictWord{12, 11, 67},
+ dictWord{141, 11, 181},
+ dictWord{138, 0, 255},
+ dictWord{5, 0, 138},
+ dictWord{4, 10, 934},
+ dictWord{
+ 136,
+ 10,
+ 610,
+ },
+ dictWord{4, 0, 965},
+ dictWord{10, 0, 863},
+ dictWord{138, 0, 898},
+ dictWord{10, 10, 804},
+ dictWord{138, 10, 832},
+ dictWord{12, 0, 631},
+ dictWord{
+ 8,
+ 10,
+ 96,
+ },
+ dictWord{9, 10, 36},
+ dictWord{10, 10, 607},
+ dictWord{11, 10, 423},
+ dictWord{11, 10, 442},
+ dictWord{12, 10, 309},
+ dictWord{14, 10, 199},
+ dictWord{
+ 15,
+ 10,
+ 90,
+ },
+ dictWord{145, 10, 110},
+ dictWord{134, 0, 1394},
+ dictWord{4, 0, 652},
+ dictWord{8, 0, 320},
+ dictWord{22, 0, 6},
+ dictWord{22, 0, 16},
+ dictWord{
+ 9,
+ 10,
+ 13,
+ },
+ dictWord{9, 10, 398},
+ dictWord{9, 10, 727},
+ dictWord{10, 10, 75},
+ dictWord{10, 10, 184},
+ dictWord{10, 10, 230},
+ dictWord{10, 10, 564},
+ dictWord{
+ 10,
+ 10,
+ 569,
+ },
+ dictWord{11, 10, 973},
+ dictWord{12, 10, 70},
+ dictWord{12, 10, 189},
+ dictWord{13, 10, 57},
+ dictWord{141, 10, 257},
+ dictWord{6, 0, 897},
+ dictWord{
+ 134,
+ 0,
+ 1333,
+ },
+ dictWord{4, 0, 692},
+ dictWord{133, 0, 321},
+ dictWord{133, 11, 373},
+ dictWord{135, 0, 922},
+ dictWord{5, 0, 619},
+ dictWord{133, 0, 698},
+ dictWord{
+ 137,
+ 10,
+ 631,
+ },
+ dictWord{5, 10, 345},
+ dictWord{135, 10, 1016},
+ dictWord{9, 0, 957},
+ dictWord{9, 0, 1018},
+ dictWord{12, 0, 828},
+ dictWord{12, 0, 844},
+ dictWord{
+ 12,
+ 0,
+ 897,
+ },
+ dictWord{12, 0, 901},
+ dictWord{12, 0, 943},
+ dictWord{15, 0, 180},
+ dictWord{18, 0, 197},
+ dictWord{18, 0, 200},
+ dictWord{18, 0, 213},
+ dictWord{
+ 18,
+ 0,
+ 214,
+ },
+ dictWord{146, 0, 226},
+ dictWord{5, 0, 917},
+ dictWord{134, 0, 1659},
+ dictWord{135, 0, 1100},
+ dictWord{134, 0, 1173},
+ dictWord{134, 0, 1930},
+ dictWord{5, 0, 251},
+ dictWord{5, 0, 956},
+ dictWord{8, 0, 268},
+ dictWord{9, 0, 214},
+ dictWord{146, 0, 142},
+ dictWord{133, 10, 673},
+ dictWord{137, 10, 850},
+ dictWord{
+ 4,
+ 10,
+ 287,
+ },
+ dictWord{133, 10, 1018},
+ dictWord{132, 11, 672},
+ dictWord{5, 0, 346},
+ dictWord{5, 0, 711},
+ dictWord{8, 0, 390},
+ dictWord{11, 11, 752},
+ dictWord{139, 11, 885},
+ dictWord{5, 10, 34},
+ dictWord{10, 10, 724},
+ dictWord{12, 10, 444},
+ dictWord{13, 10, 354},
+ dictWord{18, 10, 32},
+ dictWord{23, 10, 24},
+ dictWord{23, 10, 31},
+ dictWord{152, 10, 5},
+ dictWord{4, 11, 710},
+ dictWord{134, 11, 606},
+ dictWord{134, 0, 744},
+ dictWord{134, 10, 382},
+ dictWord{
+ 133,
+ 11,
+ 145,
+ },
+ dictWord{4, 10, 329},
+ dictWord{7, 11, 884},
+ dictWord{140, 11, 124},
+ dictWord{4, 11, 467},
+ dictWord{5, 11, 405},
+ dictWord{134, 11, 544},
+ dictWord{
+ 9,
+ 10,
+ 846,
+ },
+ dictWord{138, 10, 827},
+ dictWord{133, 0, 624},
+ dictWord{9, 11, 372},
+ dictWord{15, 11, 2},
+ dictWord{19, 11, 10},
+ dictWord{147, 11, 18},
+ dictWord{
+ 4,
+ 11,
+ 387,
+ },
+ dictWord{135, 11, 1288},
+ dictWord{5, 0, 783},
+ dictWord{7, 0, 1998},
+ dictWord{135, 0, 2047},
+ dictWord{132, 10, 906},
+ dictWord{136, 10, 366},
+ dictWord{135, 11, 550},
+ dictWord{4, 10, 123},
+ dictWord{4, 10, 649},
+ dictWord{5, 10, 605},
+ dictWord{7, 10, 1509},
+ dictWord{136, 10, 36},
+ dictWord{
+ 134,
+ 0,
+ 1125,
+ },
+ dictWord{132, 0, 594},
+ dictWord{133, 10, 767},
+ dictWord{135, 11, 1227},
+ dictWord{136, 11, 467},
+ dictWord{4, 11, 576},
+ dictWord{
+ 135,
+ 11,
+ 1263,
+ },
+ dictWord{4, 0, 268},
+ dictWord{7, 0, 1534},
+ dictWord{135, 11, 1534},
+ dictWord{4, 10, 273},
+ dictWord{5, 10, 658},
+ dictWord{5, 11, 919},
+ dictWord{
+ 5,
+ 10,
+ 995,
+ },
+ dictWord{134, 11, 1673},
+ dictWord{133, 0, 563},
+ dictWord{134, 10, 72},
+ dictWord{135, 10, 1345},
+ dictWord{4, 11, 82},
+ dictWord{5, 11, 333},
+ dictWord{
+ 5,
+ 11,
+ 904,
+ },
+ dictWord{6, 11, 207},
+ dictWord{7, 11, 325},
+ dictWord{7, 11, 1726},
+ dictWord{8, 11, 101},
+ dictWord{10, 11, 778},
+ dictWord{139, 11, 220},
+ dictWord{5, 0, 37},
+ dictWord{6, 0, 39},
+ dictWord{6, 0, 451},
+ dictWord{7, 0, 218},
+ dictWord{7, 0, 667},
+ dictWord{7, 0, 1166},
+ dictWord{7, 0, 1687},
+ dictWord{8, 0, 662},
+ dictWord{16, 0, 2},
+ dictWord{133, 10, 589},
+ dictWord{134, 0, 1332},
+ dictWord{133, 11, 903},
+ dictWord{134, 0, 508},
+ dictWord{5, 10, 117},
+ dictWord{6, 10, 514},
+ dictWord{6, 10, 541},
+ dictWord{7, 10, 1164},
+ dictWord{7, 10, 1436},
+ dictWord{8, 10, 220},
+ dictWord{8, 10, 648},
+ dictWord{10, 10, 688},
+ dictWord{11, 10, 560},
+ dictWord{140, 11, 147},
+ dictWord{6, 11, 555},
+ dictWord{135, 11, 485},
+ dictWord{133, 10, 686},
+ dictWord{7, 0, 453},
+ dictWord{7, 0, 635},
+ dictWord{7, 0, 796},
+ dictWord{8, 0, 331},
+ dictWord{9, 0, 330},
+ dictWord{9, 0, 865},
+ dictWord{10, 0, 119},
+ dictWord{10, 0, 235},
+ dictWord{11, 0, 111},
+ dictWord{11, 0, 129},
+ dictWord{
+ 11,
+ 0,
+ 240,
+ },
+ dictWord{12, 0, 31},
+ dictWord{12, 0, 66},
+ dictWord{12, 0, 222},
+ dictWord{12, 0, 269},
+ dictWord{12, 0, 599},
+ dictWord{12, 0, 684},
+ dictWord{12, 0, 689},
+ dictWord{12, 0, 691},
+ dictWord{142, 0, 345},
+ dictWord{135, 0, 1834},
+ dictWord{4, 11, 705},
+ dictWord{7, 11, 615},
+ dictWord{138, 11, 251},
+ dictWord{
+ 136,
+ 11,
+ 345,
+ },
+ dictWord{137, 0, 527},
+ dictWord{6, 0, 98},
+ dictWord{7, 0, 702},
+ dictWord{135, 0, 991},
+ dictWord{11, 0, 576},
+ dictWord{14, 0, 74},
+ dictWord{7, 10, 196},
+ dictWord{10, 10, 765},
+ dictWord{11, 10, 347},
+ dictWord{11, 10, 552},
+ dictWord{11, 10, 790},
+ dictWord{12, 10, 263},
+ dictWord{13, 10, 246},
+ dictWord{
+ 13,
+ 10,
+ 270,
+ },
+ dictWord{13, 10, 395},
+ dictWord{14, 10, 176},
+ dictWord{14, 10, 190},
+ dictWord{14, 10, 398},
+ dictWord{14, 10, 412},
+ dictWord{15, 10, 32},
+ dictWord{
+ 15,
+ 10,
+ 63,
+ },
+ dictWord{16, 10, 88},
+ dictWord{147, 10, 105},
+ dictWord{134, 11, 90},
+ dictWord{13, 0, 84},
+ dictWord{141, 0, 122},
+ dictWord{6, 0, 37},
+ dictWord{
+ 7,
+ 0,
+ 299,
+ },
+ dictWord{7, 0, 1666},
+ dictWord{8, 0, 195},
+ dictWord{8, 0, 316},
+ dictWord{9, 0, 178},
+ dictWord{9, 0, 276},
+ dictWord{9, 0, 339},
+ dictWord{9, 0, 536},
+ dictWord{
+ 10,
+ 0,
+ 102,
+ },
+ dictWord{10, 0, 362},
+ dictWord{10, 0, 785},
+ dictWord{11, 0, 55},
+ dictWord{11, 0, 149},
+ dictWord{11, 0, 773},
+ dictWord{13, 0, 416},
+ dictWord{
+ 13,
+ 0,
+ 419,
+ },
+ dictWord{14, 0, 38},
+ dictWord{14, 0, 41},
+ dictWord{142, 0, 210},
+ dictWord{5, 10, 381},
+ dictWord{135, 10, 1792},
+ dictWord{7, 11, 813},
+ dictWord{
+ 12,
+ 11,
+ 497,
+ },
+ dictWord{141, 11, 56},
+ dictWord{7, 10, 616},
+ dictWord{138, 10, 413},
+ dictWord{133, 0, 645},
+ dictWord{6, 11, 125},
+ dictWord{135, 11, 1277},
+ dictWord{132, 0, 290},
+ dictWord{6, 0, 70},
+ dictWord{7, 0, 1292},
+ dictWord{10, 0, 762},
+ dictWord{139, 0, 288},
+ dictWord{6, 10, 120},
+ dictWord{7, 10, 1188},
+ dictWord{
+ 7,
+ 10,
+ 1710,
+ },
+ dictWord{8, 10, 286},
+ dictWord{9, 10, 667},
+ dictWord{11, 10, 592},
+ dictWord{139, 10, 730},
+ dictWord{135, 11, 1784},
+ dictWord{7, 0, 1315},
+ dictWord{135, 11, 1315},
+ dictWord{134, 0, 1955},
+ dictWord{135, 10, 1146},
+ dictWord{7, 0, 131},
+ dictWord{7, 0, 422},
+ dictWord{8, 0, 210},
+ dictWord{
+ 140,
+ 0,
+ 573,
+ },
+ dictWord{4, 10, 352},
+ dictWord{135, 10, 687},
+ dictWord{139, 0, 797},
+ dictWord{143, 0, 38},
+ dictWord{14, 0, 179},
+ dictWord{15, 0, 151},
+ dictWord{
+ 150,
+ 0,
+ 11,
+ },
+ dictWord{7, 0, 488},
+ dictWord{4, 10, 192},
+ dictWord{5, 10, 49},
+ dictWord{6, 10, 200},
+ dictWord{6, 10, 293},
+ dictWord{134, 10, 1696},
+ dictWord{
+ 132,
+ 0,
+ 936,
+ },
+ dictWord{135, 11, 703},
+ dictWord{6, 11, 160},
+ dictWord{7, 11, 1106},
+ dictWord{9, 11, 770},
+ dictWord{10, 11, 618},
+ dictWord{11, 11, 112},
+ dictWord{
+ 140,
+ 11,
+ 413,
+ },
+ dictWord{5, 0, 453},
+ dictWord{134, 0, 441},
+ dictWord{135, 0, 595},
+ dictWord{132, 10, 650},
+ dictWord{132, 10, 147},
+ dictWord{6, 0, 991},
+ dictWord{6, 0, 1182},
+ dictWord{12, 11, 271},
+ dictWord{145, 11, 109},
+ dictWord{133, 10, 934},
+ dictWord{140, 11, 221},
+ dictWord{132, 0, 653},
+ dictWord{
+ 7,
+ 0,
+ 505,
+ },
+ dictWord{135, 0, 523},
+ dictWord{134, 0, 903},
+ dictWord{135, 11, 479},
+ dictWord{7, 11, 304},
+ dictWord{9, 11, 646},
+ dictWord{9, 11, 862},
+ dictWord{
+ 10,
+ 11,
+ 262,
+ },
+ dictWord{11, 11, 696},
+ dictWord{12, 11, 208},
+ dictWord{15, 11, 79},
+ dictWord{147, 11, 108},
+ dictWord{146, 0, 80},
+ dictWord{135, 11, 981},
+ dictWord{142, 0, 432},
+ dictWord{132, 0, 314},
+ dictWord{137, 11, 152},
+ dictWord{7, 0, 1368},
+ dictWord{8, 0, 232},
+ dictWord{8, 0, 361},
+ dictWord{10, 0, 682},
+ dictWord{138, 0, 742},
+ dictWord{135, 11, 1586},
+ dictWord{9, 0, 534},
+ dictWord{4, 11, 434},
+ dictWord{11, 11, 663},
+ dictWord{12, 11, 210},
+ dictWord{13, 11, 166},
+ dictWord{13, 11, 310},
+ dictWord{14, 11, 373},
+ dictWord{147, 11, 43},
+ dictWord{7, 11, 1091},
+ dictWord{135, 11, 1765},
+ dictWord{6, 11, 550},
+ dictWord{
+ 135,
+ 11,
+ 652,
+ },
+ dictWord{137, 0, 27},
+ dictWord{142, 0, 12},
+ dictWord{4, 10, 637},
+ dictWord{5, 11, 553},
+ dictWord{7, 11, 766},
+ dictWord{138, 11, 824},
+ dictWord{
+ 7,
+ 11,
+ 737,
+ },
+ dictWord{8, 11, 298},
+ dictWord{136, 11, 452},
+ dictWord{7, 0, 736},
+ dictWord{139, 0, 264},
+ dictWord{134, 0, 1657},
+ dictWord{133, 11, 292},
+ dictWord{138, 11, 135},
+ dictWord{6, 0, 844},
+ dictWord{134, 0, 1117},
+ dictWord{135, 0, 127},
+ dictWord{9, 10, 867},
+ dictWord{138, 10, 837},
+ dictWord{
+ 6,
+ 0,
+ 1184,
+ },
+ dictWord{134, 0, 1208},
+ dictWord{134, 0, 1294},
+ dictWord{136, 0, 364},
+ dictWord{6, 0, 1415},
+ dictWord{7, 0, 1334},
+ dictWord{11, 0, 125},
+ dictWord{
+ 6,
+ 10,
+ 170,
+ },
+ dictWord{7, 11, 393},
+ dictWord{8, 10, 395},
+ dictWord{8, 10, 487},
+ dictWord{10, 11, 603},
+ dictWord{11, 11, 206},
+ dictWord{141, 10, 147},
+ dictWord{137, 11, 748},
+ dictWord{4, 11, 912},
+ dictWord{137, 11, 232},
+ dictWord{4, 10, 535},
+ dictWord{136, 10, 618},
+ dictWord{137, 0, 792},
+ dictWord{
+ 7,
+ 11,
+ 1973,
+ },
+ dictWord{136, 11, 716},
+ dictWord{135, 11, 98},
+ dictWord{5, 0, 909},
+ dictWord{9, 0, 849},
+ dictWord{138, 0, 805},
+ dictWord{4, 0, 630},
+ dictWord{
+ 132,
+ 0,
+ 699,
+ },
+ dictWord{5, 11, 733},
+ dictWord{14, 11, 103},
+ dictWord{150, 10, 23},
+ dictWord{12, 11, 158},
+ dictWord{18, 11, 8},
+ dictWord{19, 11, 62},
+ dictWord{
+ 20,
+ 11,
+ 6,
+ },
+ dictWord{22, 11, 4},
+ dictWord{23, 11, 2},
+ dictWord{151, 11, 9},
+ dictWord{132, 0, 968},
+ dictWord{132, 10, 778},
+ dictWord{132, 10, 46},
+ dictWord{5, 10, 811},
+ dictWord{6, 10, 1679},
+ dictWord{6, 10, 1714},
+ dictWord{135, 10, 2032},
+ dictWord{6, 0, 1446},
+ dictWord{7, 10, 1458},
+ dictWord{9, 10, 407},
+ dictWord{
+ 139,
+ 10,
+ 15,
+ },
+ dictWord{7, 0, 206},
+ dictWord{7, 0, 397},
+ dictWord{7, 0, 621},
+ dictWord{7, 0, 640},
+ dictWord{8, 0, 124},
+ dictWord{8, 0, 619},
+ dictWord{9, 0, 305},
+ dictWord{
+ 9,
+ 0,
+ 643,
+ },
+ dictWord{10, 0, 264},
+ dictWord{10, 0, 628},
+ dictWord{11, 0, 40},
+ dictWord{12, 0, 349},
+ dictWord{13, 0, 134},
+ dictWord{13, 0, 295},
+ dictWord{
+ 14,
+ 0,
+ 155,
+ },
+ dictWord{15, 0, 120},
+ dictWord{18, 0, 105},
+ dictWord{6, 10, 34},
+ dictWord{7, 10, 1089},
+ dictWord{8, 10, 708},
+ dictWord{8, 10, 721},
+ dictWord{9, 10, 363},
+ dictWord{148, 10, 98},
+ dictWord{4, 0, 262},
+ dictWord{5, 0, 641},
+ dictWord{135, 0, 342},
+ dictWord{137, 11, 72},
+ dictWord{4, 0, 99},
+ dictWord{6, 0, 250},
+ dictWord{
+ 6,
+ 0,
+ 346,
+ },
+ dictWord{8, 0, 127},
+ dictWord{138, 0, 81},
+ dictWord{132, 0, 915},
+ dictWord{5, 0, 75},
+ dictWord{9, 0, 517},
+ dictWord{10, 0, 470},
+ dictWord{12, 0, 155},
+ dictWord{141, 0, 224},
+ dictWord{132, 10, 462},
+ dictWord{11, 11, 600},
+ dictWord{11, 11, 670},
+ dictWord{141, 11, 245},
+ dictWord{142, 0, 83},
+ dictWord{
+ 5,
+ 10,
+ 73,
+ },
+ dictWord{6, 10, 23},
+ dictWord{134, 10, 338},
+ dictWord{6, 0, 1031},
+ dictWord{139, 11, 923},
+ dictWord{7, 11, 164},
+ dictWord{7, 11, 1571},
+ dictWord{
+ 9,
+ 11,
+ 107,
+ },
+ dictWord{140, 11, 225},
+ dictWord{134, 0, 1470},
+ dictWord{133, 0, 954},
+ dictWord{6, 0, 304},
+ dictWord{8, 0, 418},
+ dictWord{10, 0, 345},
+ dictWord{
+ 11,
+ 0,
+ 341,
+ },
+ dictWord{139, 0, 675},
+ dictWord{9, 0, 410},
+ dictWord{139, 0, 425},
+ dictWord{4, 11, 27},
+ dictWord{5, 11, 484},
+ dictWord{5, 11, 510},
+ dictWord{6, 11, 434},
+ dictWord{7, 11, 1000},
+ dictWord{7, 11, 1098},
+ dictWord{8, 11, 2},
+ dictWord{136, 11, 200},
+ dictWord{134, 0, 734},
+ dictWord{140, 11, 257},
+ dictWord{
+ 7,
+ 10,
+ 725,
+ },
+ dictWord{8, 10, 498},
+ dictWord{139, 10, 268},
+ dictWord{134, 0, 1822},
+ dictWord{135, 0, 1798},
+ dictWord{135, 10, 773},
+ dictWord{132, 11, 460},
+ dictWord{4, 11, 932},
+ dictWord{133, 11, 891},
+ dictWord{134, 0, 14},
+ dictWord{132, 10, 583},
+ dictWord{7, 10, 1462},
+ dictWord{8, 11, 625},
+ dictWord{
+ 139,
+ 10,
+ 659,
+ },
+ dictWord{5, 0, 113},
+ dictWord{6, 0, 243},
+ dictWord{6, 0, 1708},
+ dictWord{7, 0, 1865},
+ dictWord{11, 0, 161},
+ dictWord{16, 0, 37},
+ dictWord{17, 0, 99},
+ dictWord{133, 10, 220},
+ dictWord{134, 11, 76},
+ dictWord{5, 11, 461},
+ dictWord{135, 11, 1925},
+ dictWord{140, 0, 69},
+ dictWord{8, 11, 92},
+ dictWord{
+ 137,
+ 11,
+ 221,
+ },
+ dictWord{139, 10, 803},
+ dictWord{132, 10, 544},
+ dictWord{4, 0, 274},
+ dictWord{134, 0, 922},
+ dictWord{132, 0, 541},
+ dictWord{5, 0, 627},
+ dictWord{
+ 6,
+ 10,
+ 437,
+ },
+ dictWord{6, 10, 564},
+ dictWord{11, 10, 181},
+ dictWord{141, 10, 183},
+ dictWord{135, 10, 1192},
+ dictWord{7, 0, 166},
+ dictWord{132, 11, 763},
+ dictWord{133, 11, 253},
+ dictWord{134, 0, 849},
+ dictWord{9, 11, 73},
+ dictWord{10, 11, 110},
+ dictWord{14, 11, 185},
+ dictWord{145, 11, 119},
+ dictWord{5, 11, 212},
+ dictWord{12, 11, 35},
+ dictWord{141, 11, 382},
+ dictWord{133, 0, 717},
+ dictWord{137, 0, 304},
+ dictWord{136, 0, 600},
+ dictWord{133, 0, 654},
+ dictWord{
+ 6,
+ 0,
+ 273,
+ },
+ dictWord{10, 0, 188},
+ dictWord{13, 0, 377},
+ dictWord{146, 0, 77},
+ dictWord{4, 10, 790},
+ dictWord{5, 10, 273},
+ dictWord{134, 10, 394},
+ dictWord{
+ 132,
+ 0,
+ 543,
+ },
+ dictWord{135, 0, 410},
+ dictWord{11, 0, 98},
+ dictWord{11, 0, 524},
+ dictWord{141, 0, 87},
+ dictWord{132, 0, 941},
+ dictWord{135, 11, 1175},
+ dictWord{
+ 4,
+ 0,
+ 250,
+ },
+ dictWord{7, 0, 1612},
+ dictWord{11, 0, 186},
+ dictWord{12, 0, 133},
+ dictWord{6, 10, 127},
+ dictWord{7, 10, 1511},
+ dictWord{8, 10, 613},
+ dictWord{
+ 12,
+ 10,
+ 495,
+ },
+ dictWord{12, 10, 586},
+ dictWord{12, 10, 660},
+ dictWord{12, 10, 668},
+ dictWord{14, 10, 385},
+ dictWord{15, 10, 118},
+ dictWord{17, 10, 20},
+ dictWord{
+ 146,
+ 10,
+ 98,
+ },
+ dictWord{6, 0, 1785},
+ dictWord{133, 11, 816},
+ dictWord{134, 0, 1339},
+ dictWord{7, 0, 961},
+ dictWord{7, 0, 1085},
+ dictWord{7, 0, 1727},
+ dictWord{
+ 8,
+ 0,
+ 462,
+ },
+ dictWord{6, 10, 230},
+ dictWord{135, 11, 1727},
+ dictWord{9, 0, 636},
+ dictWord{135, 10, 1954},
+ dictWord{132, 0, 780},
+ dictWord{5, 11, 869},
+ dictWord{5, 11, 968},
+ dictWord{6, 11, 1626},
+ dictWord{8, 11, 734},
+ dictWord{136, 11, 784},
+ dictWord{4, 11, 542},
+ dictWord{6, 11, 1716},
+ dictWord{6, 11, 1727},
+ dictWord{7, 11, 1082},
+ dictWord{7, 11, 1545},
+ dictWord{8, 11, 56},
+ dictWord{8, 11, 118},
+ dictWord{8, 11, 412},
+ dictWord{8, 11, 564},
+ dictWord{9, 11, 888},
+ dictWord{9, 11, 908},
+ dictWord{10, 11, 50},
+ dictWord{10, 11, 423},
+ dictWord{11, 11, 685},
+ dictWord{11, 11, 697},
+ dictWord{11, 11, 933},
+ dictWord{12, 11, 299},
+ dictWord{13, 11, 126},
+ dictWord{13, 11, 136},
+ dictWord{13, 11, 170},
+ dictWord{141, 11, 190},
+ dictWord{134, 11, 226},
+ dictWord{4, 11, 232},
+ dictWord{
+ 9,
+ 11,
+ 202,
+ },
+ dictWord{10, 11, 474},
+ dictWord{140, 11, 433},
+ dictWord{137, 11, 500},
+ dictWord{5, 0, 529},
+ dictWord{136, 10, 68},
+ dictWord{132, 10, 654},
+ dictWord{
+ 4,
+ 10,
+ 156,
+ },
+ dictWord{7, 10, 998},
+ dictWord{7, 10, 1045},
+ dictWord{7, 10, 1860},
+ dictWord{9, 10, 48},
+ dictWord{9, 10, 692},
+ dictWord{11, 10, 419},
+ dictWord{139, 10, 602},
+ dictWord{7, 0, 1276},
+ dictWord{8, 0, 474},
+ dictWord{9, 0, 652},
+ dictWord{6, 11, 108},
+ dictWord{7, 11, 1003},
+ dictWord{7, 11, 1181},
+ dictWord{136, 11, 343},
+ dictWord{7, 11, 1264},
+ dictWord{7, 11, 1678},
+ dictWord{11, 11, 945},
+ dictWord{12, 11, 341},
+ dictWord{12, 11, 471},
+ dictWord{
+ 140,
+ 11,
+ 569,
+ },
+ dictWord{134, 11, 1712},
+ dictWord{5, 0, 948},
+ dictWord{12, 0, 468},
+ dictWord{19, 0, 96},
+ dictWord{148, 0, 24},
+ dictWord{4, 11, 133},
+ dictWord{
+ 7,
+ 11,
+ 711,
+ },
+ dictWord{7, 11, 1298},
+ dictWord{7, 11, 1585},
+ dictWord{135, 11, 1929},
+ dictWord{6, 0, 753},
+ dictWord{140, 0, 657},
+ dictWord{139, 0, 941},
+ dictWord{
+ 6,
+ 11,
+ 99,
+ },
+ dictWord{7, 11, 1808},
+ dictWord{145, 11, 57},
+ dictWord{6, 11, 574},
+ dictWord{7, 11, 428},
+ dictWord{7, 11, 1250},
+ dictWord{10, 11, 669},
+ dictWord{
+ 11,
+ 11,
+ 485,
+ },
+ dictWord{11, 11, 840},
+ dictWord{12, 11, 300},
+ dictWord{142, 11, 250},
+ dictWord{4, 0, 532},
+ dictWord{5, 0, 706},
+ dictWord{135, 0, 662},
+ dictWord{
+ 5,
+ 0,
+ 837,
+ },
+ dictWord{6, 0, 1651},
+ dictWord{139, 0, 985},
+ dictWord{7, 0, 1861},
+ dictWord{9, 10, 197},
+ dictWord{10, 10, 300},
+ dictWord{12, 10, 473},
+ dictWord{
+ 13,
+ 10,
+ 90,
+ },
+ dictWord{141, 10, 405},
+ dictWord{137, 11, 252},
+ dictWord{6, 11, 323},
+ dictWord{135, 11, 1564},
+ dictWord{4, 0, 330},
+ dictWord{4, 0, 863},
+ dictWord{7, 0, 933},
+ dictWord{7, 0, 2012},
+ dictWord{8, 0, 292},
+ dictWord{7, 11, 461},
+ dictWord{8, 11, 775},
+ dictWord{138, 11, 435},
+ dictWord{132, 10, 606},
+ dictWord{
+ 4,
+ 11,
+ 655,
+ },
+ dictWord{7, 11, 850},
+ dictWord{17, 11, 75},
+ dictWord{146, 11, 137},
+ dictWord{135, 0, 767},
+ dictWord{7, 10, 1978},
+ dictWord{136, 10, 676},
+ dictWord{132, 0, 641},
+ dictWord{135, 11, 1559},
+ dictWord{134, 0, 1233},
+ dictWord{137, 0, 242},
+ dictWord{17, 0, 114},
+ dictWord{4, 10, 361},
+ dictWord{
+ 133,
+ 10,
+ 315,
+ },
+ dictWord{137, 0, 883},
+ dictWord{132, 10, 461},
+ dictWord{138, 0, 274},
+ dictWord{134, 0, 2008},
+ dictWord{134, 0, 1794},
+ dictWord{4, 0, 703},
+ dictWord{135, 0, 207},
+ dictWord{12, 0, 285},
+ dictWord{132, 10, 472},
+ dictWord{132, 0, 571},
+ dictWord{5, 0, 873},
+ dictWord{5, 0, 960},
+ dictWord{8, 0, 823},
+ dictWord{9, 0, 881},
+ dictWord{136, 11, 577},
+ dictWord{7, 0, 617},
+ dictWord{10, 0, 498},
+ dictWord{11, 0, 501},
+ dictWord{12, 0, 16},
+ dictWord{140, 0, 150},
+ dictWord{
+ 138,
+ 10,
+ 747,
+ },
+ dictWord{132, 0, 431},
+ dictWord{133, 10, 155},
+ dictWord{11, 0, 283},
+ dictWord{11, 0, 567},
+ dictWord{7, 10, 163},
+ dictWord{8, 10, 319},
+ dictWord{
+ 9,
+ 10,
+ 402,
+ },
+ dictWord{10, 10, 24},
+ dictWord{10, 10, 681},
+ dictWord{11, 10, 200},
+ dictWord{12, 10, 253},
+ dictWord{12, 10, 410},
+ dictWord{142, 10, 219},
+ dictWord{4, 11, 413},
+ dictWord{5, 11, 677},
+ dictWord{8, 11, 432},
+ dictWord{140, 11, 280},
+ dictWord{9, 0, 401},
+ dictWord{5, 10, 475},
+ dictWord{7, 10, 1780},
+ dictWord{11, 10, 297},
+ dictWord{11, 10, 558},
+ dictWord{14, 10, 322},
+ dictWord{147, 10, 76},
+ dictWord{6, 0, 781},
+ dictWord{9, 0, 134},
+ dictWord{10, 0, 2},
+ dictWord{
+ 10,
+ 0,
+ 27,
+ },
+ dictWord{10, 0, 333},
+ dictWord{11, 0, 722},
+ dictWord{143, 0, 1},
+ dictWord{5, 0, 33},
+ dictWord{6, 0, 470},
+ dictWord{139, 0, 424},
+ dictWord{
+ 135,
+ 0,
+ 2006,
+ },
+ dictWord{12, 0, 783},
+ dictWord{135, 10, 1956},
+ dictWord{136, 0, 274},
+ dictWord{135, 0, 1882},
+ dictWord{132, 0, 794},
+ dictWord{135, 0, 1848},
+ dictWord{5, 10, 944},
+ dictWord{134, 10, 1769},
+ dictWord{6, 0, 47},
+ dictWord{7, 0, 90},
+ dictWord{7, 0, 664},
+ dictWord{7, 0, 830},
+ dictWord{7, 0, 1380},
+ dictWord{
+ 7,
+ 0,
+ 2025,
+ },
+ dictWord{8, 0, 448},
+ dictWord{136, 0, 828},
+ dictWord{132, 10, 144},
+ dictWord{134, 0, 1199},
+ dictWord{4, 11, 395},
+ dictWord{139, 11, 762},
+ dictWord{135, 11, 1504},
+ dictWord{9, 0, 417},
+ dictWord{137, 0, 493},
+ dictWord{9, 11, 174},
+ dictWord{10, 11, 164},
+ dictWord{11, 11, 440},
+ dictWord{11, 11, 841},
+ dictWord{143, 11, 98},
+ dictWord{134, 11, 426},
+ dictWord{139, 11, 1002},
+ dictWord{134, 0, 295},
+ dictWord{134, 0, 816},
+ dictWord{6, 10, 247},
+ dictWord{
+ 137,
+ 10,
+ 555,
+ },
+ dictWord{133, 0, 1019},
+ dictWord{4, 0, 620},
+ dictWord{5, 11, 476},
+ dictWord{10, 10, 280},
+ dictWord{138, 10, 797},
+ dictWord{139, 0, 464},
+ dictWord{5, 11, 76},
+ dictWord{6, 11, 458},
+ dictWord{6, 11, 497},
+ dictWord{7, 11, 764},
+ dictWord{7, 11, 868},
+ dictWord{9, 11, 658},
+ dictWord{10, 11, 594},
+ dictWord{
+ 11,
+ 11,
+ 173,
+ },
+ dictWord{11, 11, 566},
+ dictWord{12, 11, 20},
+ dictWord{12, 11, 338},
+ dictWord{141, 11, 200},
+ dictWord{134, 0, 208},
+ dictWord{4, 11, 526},
+ dictWord{7, 11, 1029},
+ dictWord{135, 11, 1054},
+ dictWord{132, 11, 636},
+ dictWord{6, 11, 233},
+ dictWord{7, 11, 660},
+ dictWord{7, 11, 1124},
+ dictWord{
+ 17,
+ 11,
+ 31,
+ },
+ dictWord{19, 11, 22},
+ dictWord{151, 11, 14},
+ dictWord{10, 0, 442},
+ dictWord{133, 10, 428},
+ dictWord{10, 0, 930},
+ dictWord{140, 0, 778},
+ dictWord{
+ 6,
+ 0,
+ 68,
+ },
+ dictWord{7, 0, 448},
+ dictWord{7, 0, 1629},
+ dictWord{7, 0, 1769},
+ dictWord{7, 0, 1813},
+ dictWord{8, 0, 442},
+ dictWord{8, 0, 516},
+ dictWord{9, 0, 710},
+ dictWord{
+ 10,
+ 0,
+ 282,
+ },
+ dictWord{10, 0, 722},
+ dictWord{7, 10, 1717},
+ dictWord{138, 10, 546},
+ dictWord{134, 0, 1128},
+ dictWord{11, 0, 844},
+ dictWord{12, 0, 104},
+ dictWord{140, 0, 625},
+ dictWord{4, 11, 432},
+ dictWord{135, 11, 824},
+ dictWord{138, 10, 189},
+ dictWord{133, 0, 787},
+ dictWord{133, 10, 99},
+ dictWord{
+ 4,
+ 11,
+ 279,
+ },
+ dictWord{7, 11, 301},
+ dictWord{137, 11, 362},
+ dictWord{8, 0, 491},
+ dictWord{4, 10, 397},
+ dictWord{136, 10, 555},
+ dictWord{4, 11, 178},
+ dictWord{
+ 133,
+ 11,
+ 399,
+ },
+ dictWord{134, 0, 711},
+ dictWord{144, 0, 9},
+ dictWord{4, 0, 403},
+ dictWord{5, 0, 441},
+ dictWord{7, 0, 450},
+ dictWord{10, 0, 840},
+ dictWord{11, 0, 101},
+ dictWord{12, 0, 193},
+ dictWord{141, 0, 430},
+ dictWord{135, 11, 1246},
+ dictWord{12, 10, 398},
+ dictWord{20, 10, 39},
+ dictWord{21, 10, 11},
+ dictWord{
+ 150,
+ 10,
+ 41,
+ },
+ dictWord{4, 10, 485},
+ dictWord{7, 10, 353},
+ dictWord{135, 10, 1523},
+ dictWord{6, 10, 366},
+ dictWord{7, 10, 1384},
+ dictWord{7, 10, 1601},
+ dictWord{
+ 135,
+ 11,
+ 1912,
+ },
+ dictWord{7, 0, 396},
+ dictWord{10, 0, 160},
+ dictWord{135, 11, 396},
+ dictWord{137, 10, 282},
+ dictWord{134, 11, 1692},
+ dictWord{4, 10, 157},
+ dictWord{5, 10, 471},
+ dictWord{6, 11, 202},
+ dictWord{10, 11, 448},
+ dictWord{11, 11, 208},
+ dictWord{12, 11, 360},
+ dictWord{17, 11, 117},
+ dictWord{
+ 17,
+ 11,
+ 118,
+ },
+ dictWord{18, 11, 27},
+ dictWord{148, 11, 67},
+ dictWord{133, 0, 679},
+ dictWord{137, 0, 326},
+ dictWord{136, 10, 116},
+ dictWord{7, 11, 872},
+ dictWord{
+ 10,
+ 11,
+ 516,
+ },
+ dictWord{139, 11, 167},
+ dictWord{132, 11, 224},
+ dictWord{5, 11, 546},
+ dictWord{7, 11, 35},
+ dictWord{8, 11, 11},
+ dictWord{8, 11, 12},
+ dictWord{
+ 9,
+ 11,
+ 315,
+ },
+ dictWord{9, 11, 533},
+ dictWord{10, 11, 802},
+ dictWord{11, 11, 166},
+ dictWord{12, 11, 525},
+ dictWord{142, 11, 243},
+ dictWord{7, 0, 1128},
+ dictWord{135, 11, 1920},
+ dictWord{5, 11, 241},
+ dictWord{8, 11, 242},
+ dictWord{9, 11, 451},
+ dictWord{10, 11, 667},
+ dictWord{11, 11, 598},
+ dictWord{
+ 140,
+ 11,
+ 429,
+ },
+ dictWord{6, 0, 737},
+ dictWord{5, 10, 160},
+ dictWord{7, 10, 363},
+ dictWord{7, 10, 589},
+ dictWord{10, 10, 170},
+ dictWord{141, 10, 55},
+ dictWord{
+ 135,
+ 0,
+ 1796,
+ },
+ dictWord{142, 11, 254},
+ dictWord{4, 0, 574},
+ dictWord{7, 0, 350},
+ dictWord{7, 0, 1024},
+ dictWord{8, 0, 338},
+ dictWord{9, 0, 677},
+ dictWord{138, 0, 808},
+ dictWord{134, 0, 1096},
+ dictWord{137, 11, 516},
+ dictWord{7, 0, 405},
+ dictWord{10, 0, 491},
+ dictWord{4, 10, 108},
+ dictWord{4, 11, 366},
+ dictWord{
+ 139,
+ 10,
+ 498,
+ },
+ dictWord{11, 11, 337},
+ dictWord{142, 11, 303},
+ dictWord{134, 11, 1736},
+ dictWord{7, 0, 1081},
+ dictWord{140, 11, 364},
+ dictWord{7, 10, 1005},
+ dictWord{140, 10, 609},
+ dictWord{7, 0, 1676},
+ dictWord{4, 10, 895},
+ dictWord{133, 10, 772},
+ dictWord{135, 0, 2037},
+ dictWord{6, 0, 1207},
+ dictWord{
+ 11,
+ 11,
+ 916,
+ },
+ dictWord{142, 11, 419},
+ dictWord{14, 11, 140},
+ dictWord{148, 11, 41},
+ dictWord{6, 11, 331},
+ dictWord{136, 11, 623},
+ dictWord{9, 0, 944},
+ dictWord{
+ 9,
+ 0,
+ 969,
+ },
+ dictWord{9, 0, 1022},
+ dictWord{12, 0, 913},
+ dictWord{12, 0, 936},
+ dictWord{15, 0, 177},
+ dictWord{15, 0, 193},
+ dictWord{4, 10, 926},
+ dictWord{
+ 133,
+ 10,
+ 983,
+ },
+ dictWord{5, 0, 354},
+ dictWord{135, 11, 506},
+ dictWord{8, 0, 598},
+ dictWord{9, 0, 664},
+ dictWord{138, 0, 441},
+ dictWord{4, 11, 640},
+ dictWord{
+ 133,
+ 11,
+ 513,
+ },
+ dictWord{137, 0, 297},
+ dictWord{132, 10, 538},
+ dictWord{6, 10, 294},
+ dictWord{7, 10, 1267},
+ dictWord{136, 10, 624},
+ dictWord{7, 0, 1772},
+ dictWord{
+ 7,
+ 11,
+ 1888,
+ },
+ dictWord{8, 11, 289},
+ dictWord{11, 11, 45},
+ dictWord{12, 11, 278},
+ dictWord{140, 11, 537},
+ dictWord{135, 10, 1325},
+ dictWord{138, 0, 751},
+ dictWord{141, 0, 37},
+ dictWord{134, 0, 1828},
+ dictWord{132, 10, 757},
+ dictWord{132, 11, 394},
+ dictWord{6, 0, 257},
+ dictWord{135, 0, 1522},
+ dictWord{
+ 4,
+ 0,
+ 582,
+ },
+ dictWord{9, 0, 191},
+ dictWord{135, 11, 1931},
+ dictWord{7, 11, 574},
+ dictWord{7, 11, 1719},
+ dictWord{137, 11, 145},
+ dictWord{132, 11, 658},
+ dictWord{10, 0, 790},
+ dictWord{132, 11, 369},
+ dictWord{9, 11, 781},
+ dictWord{10, 11, 144},
+ dictWord{11, 11, 385},
+ dictWord{13, 11, 161},
+ dictWord{13, 11, 228},
+ dictWord{13, 11, 268},
+ dictWord{148, 11, 107},
+ dictWord{8, 0, 469},
+ dictWord{10, 0, 47},
+ dictWord{136, 11, 374},
+ dictWord{6, 0, 306},
+ dictWord{7, 0, 1140},
+ dictWord{7, 0, 1340},
+ dictWord{8, 0, 133},
+ dictWord{138, 0, 449},
+ dictWord{139, 0, 1011},
+ dictWord{7, 10, 1875},
+ dictWord{139, 10, 124},
+ dictWord{
+ 4,
+ 11,
+ 344,
+ },
+ dictWord{6, 11, 498},
+ dictWord{139, 11, 323},
+ dictWord{137, 0, 299},
+ dictWord{132, 0, 837},
+ dictWord{133, 11, 906},
+ dictWord{5, 0, 329},
+ dictWord{
+ 8,
+ 0,
+ 260,
+ },
+ dictWord{138, 0, 10},
+ dictWord{134, 0, 1320},
+ dictWord{4, 0, 657},
+ dictWord{146, 0, 158},
+ dictWord{135, 0, 1191},
+ dictWord{152, 0, 7},
+ dictWord{
+ 6,
+ 0,
+ 1939,
+ },
+ dictWord{8, 0, 974},
+ dictWord{138, 0, 996},
+ dictWord{135, 0, 1665},
+ dictWord{11, 11, 126},
+ dictWord{139, 11, 287},
+ dictWord{143, 0, 8},
+ dictWord{
+ 14,
+ 11,
+ 149,
+ },
+ dictWord{14, 11, 399},
+ dictWord{143, 11, 57},
+ dictWord{5, 0, 66},
+ dictWord{7, 0, 1896},
+ dictWord{136, 0, 288},
+ dictWord{7, 0, 175},
+ dictWord{
+ 10,
+ 0,
+ 494,
+ },
+ dictWord{5, 10, 150},
+ dictWord{8, 10, 603},
+ dictWord{9, 10, 593},
+ dictWord{9, 10, 634},
+ dictWord{10, 10, 173},
+ dictWord{11, 10, 462},
+ dictWord{
+ 11,
+ 10,
+ 515,
+ },
+ dictWord{13, 10, 216},
+ dictWord{13, 10, 288},
+ dictWord{142, 10, 400},
+ dictWord{134, 0, 1643},
+ dictWord{136, 11, 21},
+ dictWord{4, 0, 21},
+ dictWord{
+ 5,
+ 0,
+ 91,
+ },
+ dictWord{5, 0, 648},
+ dictWord{5, 0, 750},
+ dictWord{5, 0, 781},
+ dictWord{6, 0, 54},
+ dictWord{6, 0, 112},
+ dictWord{6, 0, 402},
+ dictWord{6, 0, 1732},
+ dictWord{
+ 7,
+ 0,
+ 315,
+ },
+ dictWord{7, 0, 749},
+ dictWord{7, 0, 1427},
+ dictWord{7, 0, 1900},
+ dictWord{9, 0, 78},
+ dictWord{9, 0, 508},
+ dictWord{10, 0, 611},
+ dictWord{10, 0, 811},
+ dictWord{11, 0, 510},
+ dictWord{11, 0, 728},
+ dictWord{13, 0, 36},
+ dictWord{14, 0, 39},
+ dictWord{16, 0, 83},
+ dictWord{17, 0, 124},
+ dictWord{148, 0, 30},
+ dictWord{
+ 4,
+ 0,
+ 668,
+ },
+ dictWord{136, 0, 570},
+ dictWord{10, 0, 322},
+ dictWord{10, 0, 719},
+ dictWord{139, 0, 407},
+ dictWord{135, 11, 1381},
+ dictWord{136, 11, 193},
+ dictWord{12, 10, 108},
+ dictWord{141, 10, 291},
+ dictWord{132, 11, 616},
+ dictWord{136, 11, 692},
+ dictWord{8, 0, 125},
+ dictWord{8, 0, 369},
+ dictWord{8, 0, 524},
+ dictWord{10, 0, 486},
+ dictWord{11, 0, 13},
+ dictWord{11, 0, 381},
+ dictWord{11, 0, 736},
+ dictWord{11, 0, 766},
+ dictWord{11, 0, 845},
+ dictWord{13, 0, 114},
+ dictWord{
+ 13,
+ 0,
+ 292,
+ },
+ dictWord{142, 0, 47},
+ dictWord{134, 0, 1247},
+ dictWord{6, 0, 1684},
+ dictWord{6, 0, 1731},
+ dictWord{7, 0, 356},
+ dictWord{8, 0, 54},
+ dictWord{8, 0, 221},
+ dictWord{9, 0, 225},
+ dictWord{9, 0, 356},
+ dictWord{10, 0, 77},
+ dictWord{10, 0, 446},
+ dictWord{10, 0, 731},
+ dictWord{12, 0, 404},
+ dictWord{141, 0, 491},
+ dictWord{135, 10, 1777},
+ dictWord{4, 11, 305},
+ dictWord{4, 10, 493},
+ dictWord{144, 10, 55},
+ dictWord{4, 0, 951},
+ dictWord{6, 0, 1809},
+ dictWord{6, 0, 1849},
+ dictWord{8, 0, 846},
+ dictWord{8, 0, 866},
+ dictWord{8, 0, 899},
+ dictWord{10, 0, 896},
+ dictWord{12, 0, 694},
+ dictWord{142, 0, 468},
+ dictWord{5, 11, 214},
+ dictWord{
+ 7,
+ 11,
+ 603,
+ },
+ dictWord{8, 11, 611},
+ dictWord{9, 11, 686},
+ dictWord{10, 11, 88},
+ dictWord{11, 11, 459},
+ dictWord{11, 11, 496},
+ dictWord{12, 11, 463},
+ dictWord{
+ 12,
+ 11,
+ 590,
+ },
+ dictWord{13, 11, 0},
+ dictWord{142, 11, 214},
+ dictWord{132, 0, 411},
+ dictWord{4, 0, 80},
+ dictWord{133, 0, 44},
+ dictWord{140, 11, 74},
+ dictWord{
+ 143,
+ 0,
+ 31,
+ },
+ dictWord{7, 0, 669},
+ dictWord{6, 10, 568},
+ dictWord{7, 10, 1804},
+ dictWord{8, 10, 362},
+ dictWord{8, 10, 410},
+ dictWord{8, 10, 830},
+ dictWord{9, 10, 514},
+ dictWord{11, 10, 649},
+ dictWord{142, 10, 157},
+ dictWord{7, 0, 673},
+ dictWord{134, 11, 1703},
+ dictWord{132, 10, 625},
+ dictWord{134, 0, 1303},
+ dictWord{
+ 5,
+ 0,
+ 299,
+ },
+ dictWord{135, 0, 1083},
+ dictWord{138, 0, 704},
+ dictWord{6, 0, 275},
+ dictWord{7, 0, 408},
+ dictWord{6, 10, 158},
+ dictWord{7, 10, 129},
+ dictWord{
+ 7,
+ 10,
+ 181,
+ },
+ dictWord{8, 10, 276},
+ dictWord{8, 10, 377},
+ dictWord{10, 10, 523},
+ dictWord{11, 10, 816},
+ dictWord{12, 10, 455},
+ dictWord{13, 10, 303},
+ dictWord{
+ 142,
+ 10,
+ 135,
+ },
+ dictWord{4, 0, 219},
+ dictWord{7, 0, 367},
+ dictWord{7, 0, 1713},
+ dictWord{7, 0, 1761},
+ dictWord{9, 0, 86},
+ dictWord{9, 0, 537},
+ dictWord{10, 0, 165},
+ dictWord{12, 0, 219},
+ dictWord{140, 0, 561},
+ dictWord{8, 0, 216},
+ dictWord{4, 10, 1},
+ dictWord{4, 11, 737},
+ dictWord{6, 11, 317},
+ dictWord{7, 10, 1143},
+ dictWord{
+ 7,
+ 10,
+ 1463,
+ },
+ dictWord{9, 10, 207},
+ dictWord{9, 10, 390},
+ dictWord{9, 10, 467},
+ dictWord{10, 11, 98},
+ dictWord{11, 11, 294},
+ dictWord{11, 10, 836},
+ dictWord{
+ 12,
+ 11,
+ 60,
+ },
+ dictWord{12, 11, 437},
+ dictWord{13, 11, 64},
+ dictWord{13, 11, 380},
+ dictWord{142, 11, 430},
+ dictWord{6, 11, 1758},
+ dictWord{8, 11, 520},
+ dictWord{9, 11, 345},
+ dictWord{9, 11, 403},
+ dictWord{142, 11, 350},
+ dictWord{5, 11, 47},
+ dictWord{10, 11, 242},
+ dictWord{138, 11, 579},
+ dictWord{5, 11, 139},
+ dictWord{7, 11, 1168},
+ dictWord{138, 11, 539},
+ dictWord{135, 0, 1319},
+ dictWord{4, 10, 295},
+ dictWord{4, 10, 723},
+ dictWord{5, 10, 895},
+ dictWord{
+ 7,
+ 10,
+ 1031,
+ },
+ dictWord{8, 10, 199},
+ dictWord{8, 10, 340},
+ dictWord{9, 10, 153},
+ dictWord{9, 10, 215},
+ dictWord{10, 10, 21},
+ dictWord{10, 10, 59},
+ dictWord{
+ 10,
+ 10,
+ 80,
+ },
+ dictWord{10, 10, 224},
+ dictWord{10, 10, 838},
+ dictWord{11, 10, 229},
+ dictWord{11, 10, 652},
+ dictWord{12, 10, 192},
+ dictWord{13, 10, 146},
+ dictWord{
+ 142,
+ 10,
+ 91,
+ },
+ dictWord{140, 0, 428},
+ dictWord{137, 10, 51},
+ dictWord{133, 0, 514},
+ dictWord{5, 10, 309},
+ dictWord{140, 10, 211},
+ dictWord{6, 0, 1010},
+ dictWord{5, 10, 125},
+ dictWord{8, 10, 77},
+ dictWord{138, 10, 15},
+ dictWord{4, 0, 55},
+ dictWord{5, 0, 301},
+ dictWord{6, 0, 571},
+ dictWord{142, 0, 49},
+ dictWord{
+ 146,
+ 0,
+ 102,
+ },
+ dictWord{136, 11, 370},
+ dictWord{4, 11, 107},
+ dictWord{7, 11, 613},
+ dictWord{8, 11, 358},
+ dictWord{8, 11, 439},
+ dictWord{8, 11, 504},
+ dictWord{
+ 9,
+ 11,
+ 501,
+ },
+ dictWord{10, 11, 383},
+ dictWord{139, 11, 477},
+ dictWord{132, 11, 229},
+ dictWord{133, 0, 364},
+ dictWord{133, 10, 439},
+ dictWord{4, 11, 903},
+ dictWord{135, 11, 1816},
+ dictWord{11, 0, 379},
+ dictWord{140, 10, 76},
+ dictWord{4, 0, 76},
+ dictWord{4, 0, 971},
+ dictWord{7, 0, 1550},
+ dictWord{9, 0, 306},
+ dictWord{
+ 9,
+ 0,
+ 430,
+ },
+ dictWord{9, 0, 663},
+ dictWord{10, 0, 683},
+ dictWord{10, 0, 921},
+ dictWord{11, 0, 427},
+ dictWord{11, 0, 753},
+ dictWord{12, 0, 334},
+ dictWord{12, 0, 442},
+ dictWord{14, 0, 258},
+ dictWord{14, 0, 366},
+ dictWord{143, 0, 131},
+ dictWord{137, 0, 52},
+ dictWord{4, 11, 47},
+ dictWord{6, 11, 373},
+ dictWord{7, 11, 452},
+ dictWord{7, 11, 543},
+ dictWord{7, 11, 1714},
+ dictWord{7, 11, 1856},
+ dictWord{9, 11, 6},
+ dictWord{11, 11, 257},
+ dictWord{139, 11, 391},
+ dictWord{4, 10, 8},
+ dictWord{
+ 7,
+ 10,
+ 1152,
+ },
+ dictWord{7, 10, 1153},
+ dictWord{7, 10, 1715},
+ dictWord{9, 10, 374},
+ dictWord{10, 10, 478},
+ dictWord{139, 10, 648},
+ dictWord{4, 11, 785},
+ dictWord{133, 11, 368},
+ dictWord{135, 10, 1099},
+ dictWord{135, 11, 860},
+ dictWord{5, 11, 980},
+ dictWord{134, 11, 1754},
+ dictWord{134, 0, 1258},
+ dictWord{
+ 6,
+ 0,
+ 1058,
+ },
+ dictWord{6, 0, 1359},
+ dictWord{7, 11, 536},
+ dictWord{7, 11, 1331},
+ dictWord{136, 11, 143},
+ dictWord{4, 0, 656},
+ dictWord{135, 0, 779},
+ dictWord{136, 10, 87},
+ dictWord{5, 11, 19},
+ dictWord{6, 11, 533},
+ dictWord{146, 11, 126},
+ dictWord{7, 0, 144},
+ dictWord{138, 10, 438},
+ dictWord{5, 11, 395},
+ dictWord{5, 11, 951},
+ dictWord{134, 11, 1776},
+ dictWord{135, 0, 1373},
+ dictWord{7, 0, 554},
+ dictWord{7, 0, 605},
+ dictWord{141, 0, 10},
+ dictWord{4, 10, 69},
+ dictWord{
+ 5,
+ 10,
+ 122,
+ },
+ dictWord{9, 10, 656},
+ dictWord{138, 10, 464},
+ dictWord{5, 10, 849},
+ dictWord{134, 10, 1633},
+ dictWord{5, 0, 838},
+ dictWord{5, 0, 841},
+ dictWord{134, 0, 1649},
+ dictWord{133, 0, 1012},
+ dictWord{139, 10, 499},
+ dictWord{7, 10, 476},
+ dictWord{7, 10, 1592},
+ dictWord{138, 10, 87},
+ dictWord{
+ 6,
+ 0,
+ 251,
+ },
+ dictWord{7, 0, 365},
+ dictWord{7, 0, 1357},
+ dictWord{7, 0, 1497},
+ dictWord{8, 0, 154},
+ dictWord{141, 0, 281},
+ dictWord{132, 11, 441},
+ dictWord{
+ 132,
+ 11,
+ 695,
+ },
+ dictWord{7, 11, 497},
+ dictWord{9, 11, 387},
+ dictWord{147, 11, 81},
+ dictWord{133, 0, 340},
+ dictWord{14, 10, 283},
+ dictWord{142, 11, 283},
+ dictWord{
+ 134,
+ 0,
+ 810,
+ },
+ dictWord{135, 11, 1894},
+ dictWord{139, 0, 495},
+ dictWord{5, 11, 284},
+ dictWord{6, 11, 49},
+ dictWord{6, 11, 350},
+ dictWord{7, 11, 1},
+ dictWord{
+ 7,
+ 11,
+ 377,
+ },
+ dictWord{7, 11, 1693},
+ dictWord{8, 11, 18},
+ dictWord{8, 11, 678},
+ dictWord{9, 11, 161},
+ dictWord{9, 11, 585},
+ dictWord{9, 11, 671},
+ dictWord{
+ 9,
+ 11,
+ 839,
+ },
+ dictWord{11, 11, 912},
+ dictWord{141, 11, 427},
+ dictWord{5, 10, 859},
+ dictWord{7, 10, 1160},
+ dictWord{8, 10, 107},
+ dictWord{9, 10, 291},
+ dictWord{
+ 9,
+ 10,
+ 439,
+ },
+ dictWord{10, 10, 663},
+ dictWord{11, 10, 609},
+ dictWord{140, 10, 197},
+ dictWord{8, 0, 261},
+ dictWord{9, 0, 144},
+ dictWord{9, 0, 466},
+ dictWord{
+ 10,
+ 0,
+ 370,
+ },
+ dictWord{12, 0, 470},
+ dictWord{13, 0, 144},
+ dictWord{142, 0, 348},
+ dictWord{137, 0, 897},
+ dictWord{6, 0, 248},
+ dictWord{9, 0, 546},
+ dictWord{10, 0, 535},
+ dictWord{11, 0, 681},
+ dictWord{141, 0, 135},
+ dictWord{4, 0, 358},
+ dictWord{135, 0, 1496},
+ dictWord{134, 0, 567},
+ dictWord{136, 0, 445},
+ dictWord{
+ 4,
+ 10,
+ 117,
+ },
+ dictWord{6, 10, 372},
+ dictWord{7, 10, 1905},
+ dictWord{142, 10, 323},
+ dictWord{4, 10, 722},
+ dictWord{139, 10, 471},
+ dictWord{6, 0, 697},
+ dictWord{
+ 134,
+ 0,
+ 996,
+ },
+ dictWord{7, 11, 2007},
+ dictWord{9, 11, 101},
+ dictWord{9, 11, 450},
+ dictWord{10, 11, 66},
+ dictWord{10, 11, 842},
+ dictWord{11, 11, 536},
+ dictWord{
+ 140,
+ 11,
+ 587,
+ },
+ dictWord{132, 0, 577},
+ dictWord{134, 0, 1336},
+ dictWord{9, 10, 5},
+ dictWord{12, 10, 216},
+ dictWord{12, 10, 294},
+ dictWord{12, 10, 298},
+ dictWord{12, 10, 400},
+ dictWord{12, 10, 518},
+ dictWord{13, 10, 229},
+ dictWord{143, 10, 139},
+ dictWord{6, 0, 174},
+ dictWord{138, 0, 917},
+ dictWord{
+ 134,
+ 10,
+ 1774,
+ },
+ dictWord{5, 10, 12},
+ dictWord{7, 10, 375},
+ dictWord{9, 10, 88},
+ dictWord{9, 10, 438},
+ dictWord{11, 11, 62},
+ dictWord{139, 10, 270},
+ dictWord{
+ 134,
+ 11,
+ 1766,
+ },
+ dictWord{6, 11, 0},
+ dictWord{7, 11, 84},
+ dictWord{7, 10, 816},
+ dictWord{7, 10, 1241},
+ dictWord{9, 10, 283},
+ dictWord{9, 10, 520},
+ dictWord{10, 10, 213},
+ dictWord{10, 10, 307},
+ dictWord{10, 10, 463},
+ dictWord{10, 10, 671},
+ dictWord{10, 10, 746},
+ dictWord{11, 10, 401},
+ dictWord{11, 10, 794},
+ dictWord{
+ 11,
+ 11,
+ 895,
+ },
+ dictWord{12, 10, 517},
+ dictWord{17, 11, 11},
+ dictWord{18, 10, 107},
+ dictWord{147, 10, 115},
+ dictWord{5, 0, 878},
+ dictWord{133, 0, 972},
+ dictWord{
+ 6,
+ 11,
+ 1665,
+ },
+ dictWord{7, 11, 256},
+ dictWord{7, 11, 1388},
+ dictWord{138, 11, 499},
+ dictWord{4, 10, 258},
+ dictWord{136, 10, 639},
+ dictWord{4, 11, 22},
+ dictWord{5, 11, 10},
+ dictWord{6, 10, 22},
+ dictWord{7, 11, 848},
+ dictWord{7, 10, 903},
+ dictWord{7, 10, 1963},
+ dictWord{8, 11, 97},
+ dictWord{138, 10, 577},
+ dictWord{
+ 5,
+ 10,
+ 681,
+ },
+ dictWord{136, 10, 782},
+ dictWord{133, 11, 481},
+ dictWord{132, 0, 351},
+ dictWord{4, 10, 664},
+ dictWord{5, 10, 804},
+ dictWord{139, 10, 1013},
+ dictWord{6, 11, 134},
+ dictWord{7, 11, 437},
+ dictWord{7, 11, 959},
+ dictWord{9, 11, 37},
+ dictWord{14, 11, 285},
+ dictWord{14, 11, 371},
+ dictWord{144, 11, 60},
+ dictWord{7, 11, 486},
+ dictWord{8, 11, 155},
+ dictWord{11, 11, 93},
+ dictWord{140, 11, 164},
+ dictWord{132, 0, 286},
+ dictWord{7, 0, 438},
+ dictWord{7, 0, 627},
+ dictWord{7, 0, 1516},
+ dictWord{8, 0, 40},
+ dictWord{9, 0, 56},
+ dictWord{9, 0, 294},
+ dictWord{10, 0, 30},
+ dictWord{11, 0, 969},
+ dictWord{11, 0, 995},
+ dictWord{146, 0, 148},
+ dictWord{5, 11, 591},
+ dictWord{135, 11, 337},
+ dictWord{134, 0, 1950},
+ dictWord{133, 10, 32},
+ dictWord{138, 11, 500},
+ dictWord{5, 11, 380},
+ dictWord{
+ 5,
+ 11,
+ 650,
+ },
+ dictWord{136, 11, 310},
+ dictWord{4, 11, 364},
+ dictWord{7, 11, 1156},
+ dictWord{7, 11, 1187},
+ dictWord{137, 11, 409},
+ dictWord{4, 0, 738},
+ dictWord{134, 11, 482},
+ dictWord{4, 11, 781},
+ dictWord{6, 11, 487},
+ dictWord{7, 11, 926},
+ dictWord{8, 11, 263},
+ dictWord{139, 11, 500},
+ dictWord{135, 11, 418},
+ dictWord{6, 0, 2047},
+ dictWord{10, 0, 969},
+ dictWord{4, 10, 289},
+ dictWord{7, 10, 629},
+ dictWord{7, 10, 1698},
+ dictWord{7, 10, 1711},
+ dictWord{
+ 140,
+ 10,
+ 215,
+ },
+ dictWord{6, 10, 450},
+ dictWord{136, 10, 109},
+ dictWord{134, 0, 818},
+ dictWord{136, 10, 705},
+ dictWord{133, 0, 866},
+ dictWord{4, 11, 94},
+ dictWord{
+ 135,
+ 11,
+ 1265,
+ },
+ dictWord{132, 11, 417},
+ dictWord{134, 0, 1467},
+ dictWord{135, 10, 1238},
+ dictWord{4, 0, 972},
+ dictWord{6, 0, 1851},
+ dictWord{
+ 134,
+ 0,
+ 1857,
+ },
+ dictWord{134, 0, 355},
+ dictWord{133, 0, 116},
+ dictWord{132, 0, 457},
+ dictWord{135, 11, 1411},
+ dictWord{4, 11, 408},
+ dictWord{4, 11, 741},
+ dictWord{135, 11, 500},
+ dictWord{134, 10, 26},
+ dictWord{142, 11, 137},
+ dictWord{5, 0, 527},
+ dictWord{6, 0, 189},
+ dictWord{7, 0, 859},
+ dictWord{136, 0, 267},
+ dictWord{11, 0, 104},
+ dictWord{11, 0, 554},
+ dictWord{15, 0, 60},
+ dictWord{143, 0, 125},
+ dictWord{134, 0, 1613},
+ dictWord{4, 10, 414},
+ dictWord{5, 10, 467},
+ dictWord{
+ 9,
+ 10,
+ 654,
+ },
+ dictWord{10, 10, 451},
+ dictWord{12, 10, 59},
+ dictWord{141, 10, 375},
+ dictWord{135, 10, 17},
+ dictWord{134, 0, 116},
+ dictWord{135, 11, 541},
+ dictWord{135, 10, 955},
+ dictWord{6, 11, 73},
+ dictWord{135, 11, 177},
+ dictWord{133, 11, 576},
+ dictWord{134, 0, 886},
+ dictWord{133, 0, 487},
+ dictWord{
+ 4,
+ 0,
+ 86,
+ },
+ dictWord{5, 0, 667},
+ dictWord{5, 0, 753},
+ dictWord{6, 0, 316},
+ dictWord{6, 0, 455},
+ dictWord{135, 0, 946},
+ dictWord{142, 11, 231},
+ dictWord{150, 0, 45},
+ dictWord{134, 0, 863},
+ dictWord{134, 0, 1953},
+ dictWord{6, 10, 280},
+ dictWord{10, 10, 502},
+ dictWord{11, 10, 344},
+ dictWord{140, 10, 38},
+ dictWord{4, 0, 79},
+ dictWord{7, 0, 1773},
+ dictWord{10, 0, 450},
+ dictWord{11, 0, 589},
+ dictWord{13, 0, 332},
+ dictWord{13, 0, 493},
+ dictWord{14, 0, 183},
+ dictWord{14, 0, 334},
+ dictWord{14, 0, 362},
+ dictWord{14, 0, 368},
+ dictWord{14, 0, 376},
+ dictWord{14, 0, 379},
+ dictWord{19, 0, 90},
+ dictWord{19, 0, 103},
+ dictWord{19, 0, 127},
+ dictWord{
+ 148,
+ 0,
+ 90,
+ },
+ dictWord{5, 10, 45},
+ dictWord{7, 10, 1161},
+ dictWord{11, 10, 448},
+ dictWord{11, 10, 880},
+ dictWord{13, 10, 139},
+ dictWord{13, 10, 407},
+ dictWord{
+ 15,
+ 10,
+ 16,
+ },
+ dictWord{17, 10, 95},
+ dictWord{18, 10, 66},
+ dictWord{18, 10, 88},
+ dictWord{18, 10, 123},
+ dictWord{149, 10, 7},
+ dictWord{136, 10, 777},
+ dictWord{
+ 4,
+ 10,
+ 410,
+ },
+ dictWord{135, 10, 521},
+ dictWord{135, 10, 1778},
+ dictWord{135, 11, 538},
+ dictWord{142, 0, 381},
+ dictWord{133, 11, 413},
+ dictWord{
+ 134,
+ 0,
+ 1142,
+ },
+ dictWord{6, 0, 1189},
+ dictWord{136, 11, 495},
+ dictWord{5, 0, 663},
+ dictWord{6, 0, 1962},
+ dictWord{134, 0, 2003},
+ dictWord{7, 11, 54},
+ dictWord{
+ 8,
+ 11,
+ 312,
+ },
+ dictWord{10, 11, 191},
+ dictWord{10, 11, 614},
+ dictWord{140, 11, 567},
+ dictWord{132, 10, 436},
+ dictWord{133, 0, 846},
+ dictWord{10, 0, 528},
+ dictWord{11, 0, 504},
+ dictWord{7, 10, 1587},
+ dictWord{135, 10, 1707},
+ dictWord{5, 0, 378},
+ dictWord{8, 0, 465},
+ dictWord{9, 0, 286},
+ dictWord{10, 0, 185},
+ dictWord{
+ 10,
+ 0,
+ 562,
+ },
+ dictWord{10, 0, 635},
+ dictWord{11, 0, 31},
+ dictWord{11, 0, 393},
+ dictWord{13, 0, 312},
+ dictWord{18, 0, 65},
+ dictWord{18, 0, 96},
+ dictWord{147, 0, 89},
+ dictWord{7, 0, 899},
+ dictWord{14, 0, 325},
+ dictWord{6, 11, 468},
+ dictWord{7, 11, 567},
+ dictWord{7, 11, 1478},
+ dictWord{8, 11, 530},
+ dictWord{142, 11, 290},
+ dictWord{7, 0, 1880},
+ dictWord{9, 0, 680},
+ dictWord{139, 0, 798},
+ dictWord{134, 0, 1770},
+ dictWord{132, 0, 648},
+ dictWord{150, 11, 35},
+ dictWord{5, 0, 945},
+ dictWord{6, 0, 1656},
+ dictWord{6, 0, 1787},
+ dictWord{7, 0, 167},
+ dictWord{8, 0, 824},
+ dictWord{9, 0, 391},
+ dictWord{10, 0, 375},
+ dictWord{139, 0, 185},
+ dictWord{
+ 6,
+ 11,
+ 484,
+ },
+ dictWord{135, 11, 822},
+ dictWord{134, 0, 2046},
+ dictWord{7, 0, 1645},
+ dictWord{8, 0, 352},
+ dictWord{137, 0, 249},
+ dictWord{132, 0, 152},
+ dictWord{6, 0, 611},
+ dictWord{135, 0, 1733},
+ dictWord{6, 11, 1724},
+ dictWord{135, 11, 2022},
+ dictWord{133, 0, 1006},
+ dictWord{141, 11, 96},
+ dictWord{
+ 5,
+ 0,
+ 420,
+ },
+ dictWord{135, 0, 1449},
+ dictWord{146, 11, 149},
+ dictWord{135, 0, 832},
+ dictWord{135, 10, 663},
+ dictWord{133, 0, 351},
+ dictWord{5, 0, 40},
+ dictWord{
+ 7,
+ 0,
+ 598,
+ },
+ dictWord{7, 0, 1638},
+ dictWord{8, 0, 78},
+ dictWord{9, 0, 166},
+ dictWord{9, 0, 640},
+ dictWord{9, 0, 685},
+ dictWord{9, 0, 773},
+ dictWord{11, 0, 215},
+ dictWord{13, 0, 65},
+ dictWord{14, 0, 172},
+ dictWord{14, 0, 317},
+ dictWord{145, 0, 6},
+ dictWord{8, 0, 60},
+ dictWord{9, 0, 343},
+ dictWord{139, 0, 769},
+ dictWord{
+ 134,
+ 0,
+ 1354,
+ },
+ dictWord{132, 0, 724},
+ dictWord{137, 0, 745},
+ dictWord{132, 11, 474},
+ dictWord{7, 0, 1951},
+ dictWord{8, 0, 765},
+ dictWord{8, 0, 772},
+ dictWord{
+ 140,
+ 0,
+ 671,
+ },
+ dictWord{7, 0, 108},
+ dictWord{8, 0, 219},
+ dictWord{8, 0, 388},
+ dictWord{9, 0, 775},
+ dictWord{11, 0, 275},
+ dictWord{140, 0, 464},
+ dictWord{137, 0, 639},
+ dictWord{135, 10, 503},
+ dictWord{133, 11, 366},
+ dictWord{5, 0, 15},
+ dictWord{6, 0, 56},
+ dictWord{7, 0, 1758},
+ dictWord{8, 0, 500},
+ dictWord{9, 0, 730},
+ dictWord{
+ 11,
+ 0,
+ 331,
+ },
+ dictWord{13, 0, 150},
+ dictWord{14, 0, 282},
+ dictWord{5, 11, 305},
+ dictWord{9, 11, 560},
+ dictWord{141, 11, 208},
+ dictWord{4, 10, 113},
+ dictWord{
+ 5,
+ 10,
+ 163,
+ },
+ dictWord{5, 10, 735},
+ dictWord{7, 10, 1009},
+ dictWord{9, 10, 9},
+ dictWord{9, 10, 771},
+ dictWord{12, 10, 90},
+ dictWord{13, 10, 138},
+ dictWord{
+ 13,
+ 10,
+ 410,
+ },
+ dictWord{143, 10, 128},
+ dictWord{4, 10, 324},
+ dictWord{138, 10, 104},
+ dictWord{135, 11, 466},
+ dictWord{142, 11, 27},
+ dictWord{134, 0, 1886},
+ dictWord{5, 0, 205},
+ dictWord{6, 0, 438},
+ dictWord{9, 0, 711},
+ dictWord{4, 11, 480},
+ dictWord{6, 11, 167},
+ dictWord{6, 11, 302},
+ dictWord{6, 11, 1642},
+ dictWord{
+ 7,
+ 11,
+ 130,
+ },
+ dictWord{7, 11, 656},
+ dictWord{7, 11, 837},
+ dictWord{7, 11, 1547},
+ dictWord{7, 11, 1657},
+ dictWord{8, 11, 429},
+ dictWord{9, 11, 228},
+ dictWord{
+ 10,
+ 11,
+ 643,
+ },
+ dictWord{13, 11, 289},
+ dictWord{13, 11, 343},
+ dictWord{147, 11, 101},
+ dictWord{134, 0, 865},
+ dictWord{6, 0, 2025},
+ dictWord{136, 0, 965},
+ dictWord{
+ 7,
+ 11,
+ 278,
+ },
+ dictWord{10, 11, 739},
+ dictWord{11, 11, 708},
+ dictWord{141, 11, 348},
+ dictWord{133, 0, 534},
+ dictWord{135, 11, 1922},
+ dictWord{
+ 137,
+ 0,
+ 691,
+ },
+ dictWord{4, 10, 935},
+ dictWord{133, 10, 823},
+ dictWord{6, 0, 443},
+ dictWord{9, 0, 237},
+ dictWord{9, 0, 571},
+ dictWord{9, 0, 695},
+ dictWord{10, 0, 139},
+ dictWord{11, 0, 715},
+ dictWord{12, 0, 417},
+ dictWord{141, 0, 421},
+ dictWord{5, 10, 269},
+ dictWord{7, 10, 434},
+ dictWord{7, 10, 891},
+ dictWord{8, 10, 339},
+ dictWord{
+ 9,
+ 10,
+ 702,
+ },
+ dictWord{11, 10, 594},
+ dictWord{11, 10, 718},
+ dictWord{145, 10, 100},
+ dictWord{6, 0, 1555},
+ dictWord{7, 0, 878},
+ dictWord{9, 10, 485},
+ dictWord{141, 10, 264},
+ dictWord{134, 10, 1713},
+ dictWord{7, 10, 1810},
+ dictWord{11, 10, 866},
+ dictWord{12, 10, 103},
+ dictWord{141, 10, 495},
+ dictWord{
+ 135,
+ 10,
+ 900,
+ },
+ dictWord{6, 0, 1410},
+ dictWord{9, 11, 316},
+ dictWord{139, 11, 256},
+ dictWord{4, 0, 995},
+ dictWord{135, 0, 1033},
+ dictWord{132, 0, 578},
+ dictWord{10, 0, 881},
+ dictWord{12, 0, 740},
+ dictWord{12, 0, 743},
+ dictWord{140, 0, 759},
+ dictWord{132, 0, 822},
+ dictWord{133, 0, 923},
+ dictWord{142, 10, 143},
+ dictWord{135, 11, 1696},
+ dictWord{6, 11, 363},
+ dictWord{7, 11, 1955},
+ dictWord{136, 11, 725},
+ dictWord{132, 0, 924},
+ dictWord{133, 0, 665},
+ dictWord{
+ 135,
+ 10,
+ 2029,
+ },
+ dictWord{135, 0, 1901},
+ dictWord{4, 0, 265},
+ dictWord{6, 0, 1092},
+ dictWord{6, 0, 1417},
+ dictWord{7, 0, 807},
+ dictWord{135, 0, 950},
+ dictWord{
+ 5,
+ 0,
+ 93,
+ },
+ dictWord{12, 0, 267},
+ dictWord{141, 0, 498},
+ dictWord{135, 0, 1451},
+ dictWord{5, 11, 813},
+ dictWord{135, 11, 2046},
+ dictWord{5, 10, 625},
+ dictWord{135, 10, 1617},
+ dictWord{135, 0, 747},
+ dictWord{6, 0, 788},
+ dictWord{137, 0, 828},
+ dictWord{7, 0, 184},
+ dictWord{11, 0, 307},
+ dictWord{11, 0, 400},
+ dictWord{15, 0, 130},
+ dictWord{5, 11, 712},
+ dictWord{7, 11, 1855},
+ dictWord{8, 10, 425},
+ dictWord{8, 10, 693},
+ dictWord{9, 10, 720},
+ dictWord{10, 10, 380},
+ dictWord{10, 10, 638},
+ dictWord{11, 11, 17},
+ dictWord{11, 10, 473},
+ dictWord{12, 10, 61},
+ dictWord{13, 11, 321},
+ dictWord{144, 11, 67},
+ dictWord{135, 0, 198},
+ dictWord{6, 11, 320},
+ dictWord{7, 11, 781},
+ dictWord{7, 11, 1921},
+ dictWord{9, 11, 55},
+ dictWord{10, 11, 186},
+ dictWord{10, 11, 273},
+ dictWord{10, 11, 664},
+ dictWord{10, 11, 801},
+ dictWord{11, 11, 996},
+ dictWord{11, 11, 997},
+ dictWord{13, 11, 157},
+ dictWord{142, 11, 170},
+ dictWord{136, 11, 271},
+ dictWord{
+ 135,
+ 0,
+ 994,
+ },
+ dictWord{7, 11, 103},
+ dictWord{7, 11, 863},
+ dictWord{11, 11, 184},
+ dictWord{14, 11, 299},
+ dictWord{145, 11, 62},
+ dictWord{11, 10, 551},
+ dictWord{142, 10, 159},
+ dictWord{5, 0, 233},
+ dictWord{5, 0, 320},
+ dictWord{6, 0, 140},
+ dictWord{8, 0, 295},
+ dictWord{8, 0, 615},
+ dictWord{136, 11, 615},
+ dictWord{
+ 133,
+ 0,
+ 978,
+ },
+ dictWord{4, 0, 905},
+ dictWord{6, 0, 1701},
+ dictWord{137, 0, 843},
+ dictWord{132, 10, 168},
+ dictWord{4, 0, 974},
+ dictWord{8, 0, 850},
+ dictWord{
+ 12,
+ 0,
+ 709,
+ },
+ dictWord{12, 0, 768},
+ dictWord{140, 0, 786},
+ dictWord{135, 10, 91},
+ dictWord{152, 0, 6},
+ dictWord{138, 10, 532},
+ dictWord{135, 10, 1884},
+ dictWord{132, 0, 509},
+ dictWord{6, 0, 1307},
+ dictWord{135, 0, 273},
+ dictWord{5, 11, 77},
+ dictWord{7, 11, 1455},
+ dictWord{10, 11, 843},
+ dictWord{19, 11, 73},
+ dictWord{150, 11, 5},
+ dictWord{132, 11, 458},
+ dictWord{135, 11, 1420},
+ dictWord{6, 11, 109},
+ dictWord{138, 11, 382},
+ dictWord{6, 0, 201},
+ dictWord{6, 11, 330},
+ dictWord{7, 10, 70},
+ dictWord{7, 11, 1084},
+ dictWord{10, 10, 240},
+ dictWord{11, 11, 142},
+ dictWord{147, 10, 93},
+ dictWord{7, 0, 1041},
+ dictWord{
+ 140,
+ 11,
+ 328,
+ },
+ dictWord{133, 11, 354},
+ dictWord{134, 0, 1040},
+ dictWord{133, 0, 693},
+ dictWord{134, 0, 774},
+ dictWord{139, 0, 234},
+ dictWord{132, 0, 336},
+ dictWord{7, 0, 1399},
+ dictWord{139, 10, 392},
+ dictWord{20, 0, 22},
+ dictWord{148, 11, 22},
+ dictWord{5, 0, 802},
+ dictWord{7, 0, 2021},
+ dictWord{136, 0, 805},
+ dictWord{
+ 5,
+ 0,
+ 167,
+ },
+ dictWord{5, 0, 899},
+ dictWord{6, 0, 410},
+ dictWord{137, 0, 777},
+ dictWord{137, 0, 789},
+ dictWord{134, 0, 1705},
+ dictWord{7, 10, 655},
+ dictWord{
+ 135,
+ 10,
+ 1844,
+ },
+ dictWord{4, 10, 145},
+ dictWord{6, 10, 176},
+ dictWord{7, 10, 395},
+ dictWord{137, 10, 562},
+ dictWord{132, 10, 501},
+ dictWord{135, 0, 10},
+ dictWord{5, 0, 11},
+ dictWord{6, 0, 117},
+ dictWord{6, 0, 485},
+ dictWord{7, 0, 1133},
+ dictWord{9, 0, 582},
+ dictWord{9, 0, 594},
+ dictWord{10, 0, 82},
+ dictWord{11, 0, 21},
+ dictWord{11, 0, 818},
+ dictWord{12, 0, 535},
+ dictWord{13, 0, 86},
+ dictWord{20, 0, 91},
+ dictWord{23, 0, 13},
+ dictWord{134, 10, 509},
+ dictWord{4, 0, 264},
+ dictWord{
+ 7,
+ 0,
+ 1067,
+ },
+ dictWord{8, 0, 204},
+ dictWord{8, 0, 385},
+ dictWord{139, 0, 953},
+ dictWord{139, 11, 737},
+ dictWord{138, 0, 56},
+ dictWord{134, 0, 1917},
+ dictWord{
+ 133,
+ 0,
+ 470,
+ },
+ dictWord{10, 11, 657},
+ dictWord{14, 11, 297},
+ dictWord{142, 11, 361},
+ dictWord{135, 11, 412},
+ dictWord{7, 0, 1198},
+ dictWord{7, 11, 1198},
+ dictWord{8, 11, 556},
+ dictWord{14, 11, 123},
+ dictWord{14, 11, 192},
+ dictWord{143, 11, 27},
+ dictWord{7, 11, 1985},
+ dictWord{14, 11, 146},
+ dictWord{15, 11, 42},
+ dictWord{16, 11, 23},
+ dictWord{17, 11, 86},
+ dictWord{146, 11, 17},
+ dictWord{11, 0, 1015},
+ dictWord{136, 11, 122},
+ dictWord{4, 10, 114},
+ dictWord{
+ 9,
+ 10,
+ 492,
+ },
+ dictWord{13, 10, 462},
+ dictWord{142, 10, 215},
+ dictWord{4, 10, 77},
+ dictWord{5, 10, 361},
+ dictWord{6, 10, 139},
+ dictWord{6, 10, 401},
+ dictWord{
+ 6,
+ 10,
+ 404,
+ },
+ dictWord{7, 10, 413},
+ dictWord{7, 10, 715},
+ dictWord{7, 10, 1716},
+ dictWord{11, 10, 279},
+ dictWord{12, 10, 179},
+ dictWord{12, 10, 258},
+ dictWord{
+ 13,
+ 10,
+ 244,
+ },
+ dictWord{142, 10, 358},
+ dictWord{134, 10, 1717},
+ dictWord{7, 10, 1061},
+ dictWord{8, 10, 82},
+ dictWord{11, 10, 250},
+ dictWord{12, 10, 420},
+ dictWord{141, 10, 184},
+ dictWord{133, 0, 715},
+ dictWord{135, 10, 724},
+ dictWord{9, 0, 919},
+ dictWord{9, 0, 922},
+ dictWord{9, 0, 927},
+ dictWord{9, 0, 933},
+ dictWord{9, 0, 962},
+ dictWord{9, 0, 1000},
+ dictWord{9, 0, 1002},
+ dictWord{9, 0, 1021},
+ dictWord{12, 0, 890},
+ dictWord{12, 0, 907},
+ dictWord{12, 0, 930},
+ dictWord{
+ 15,
+ 0,
+ 207,
+ },
+ dictWord{15, 0, 228},
+ dictWord{15, 0, 238},
+ dictWord{149, 0, 61},
+ dictWord{8, 0, 794},
+ dictWord{9, 0, 400},
+ dictWord{10, 0, 298},
+ dictWord{142, 0, 228},
+ dictWord{5, 11, 430},
+ dictWord{5, 11, 932},
+ dictWord{6, 11, 131},
+ dictWord{7, 11, 417},
+ dictWord{9, 11, 522},
+ dictWord{11, 11, 314},
+ dictWord{141, 11, 390},
+ dictWord{132, 0, 867},
+ dictWord{8, 0, 724},
+ dictWord{132, 11, 507},
+ dictWord{137, 11, 261},
+ dictWord{4, 11, 343},
+ dictWord{133, 11, 511},
+ dictWord{
+ 6,
+ 0,
+ 190,
+ },
+ dictWord{7, 0, 768},
+ dictWord{135, 0, 1170},
+ dictWord{6, 10, 513},
+ dictWord{135, 10, 1052},
+ dictWord{7, 11, 455},
+ dictWord{138, 11, 591},
+ dictWord{134, 0, 1066},
+ dictWord{137, 10, 899},
+ dictWord{14, 0, 67},
+ dictWord{147, 0, 60},
+ dictWord{4, 0, 948},
+ dictWord{18, 0, 174},
+ dictWord{146, 0, 176},
+ dictWord{135, 0, 1023},
+ dictWord{7, 10, 1417},
+ dictWord{12, 10, 382},
+ dictWord{17, 10, 48},
+ dictWord{152, 10, 12},
+ dictWord{134, 11, 575},
+ dictWord{
+ 132,
+ 0,
+ 764,
+ },
+ dictWord{6, 10, 545},
+ dictWord{7, 10, 565},
+ dictWord{7, 10, 1669},
+ dictWord{10, 10, 114},
+ dictWord{11, 10, 642},
+ dictWord{140, 10, 618},
+ dictWord{
+ 6,
+ 0,
+ 137,
+ },
+ dictWord{9, 0, 75},
+ dictWord{9, 0, 253},
+ dictWord{10, 0, 194},
+ dictWord{138, 0, 444},
+ dictWord{4, 0, 756},
+ dictWord{133, 10, 5},
+ dictWord{8, 0, 1008},
+ dictWord{135, 10, 192},
+ dictWord{132, 0, 842},
+ dictWord{11, 0, 643},
+ dictWord{12, 0, 115},
+ dictWord{136, 10, 763},
+ dictWord{139, 0, 67},
+ dictWord{
+ 133,
+ 10,
+ 759,
+ },
+ dictWord{4, 0, 821},
+ dictWord{5, 0, 760},
+ dictWord{7, 0, 542},
+ dictWord{8, 0, 135},
+ dictWord{8, 0, 496},
+ dictWord{135, 11, 580},
+ dictWord{7, 10, 370},
+ dictWord{7, 10, 1007},
+ dictWord{7, 10, 1177},
+ dictWord{135, 10, 1565},
+ dictWord{135, 10, 1237},
+ dictWord{140, 0, 736},
+ dictWord{7, 0, 319},
+ dictWord{
+ 7,
+ 0,
+ 355,
+ },
+ dictWord{7, 0, 763},
+ dictWord{10, 0, 389},
+ dictWord{145, 0, 43},
+ dictWord{8, 11, 333},
+ dictWord{138, 11, 182},
+ dictWord{4, 10, 87},
+ dictWord{5, 10, 250},
+ dictWord{141, 10, 298},
+ dictWord{138, 0, 786},
+ dictWord{134, 0, 2044},
+ dictWord{8, 11, 330},
+ dictWord{140, 11, 477},
+ dictWord{135, 11, 1338},
+ dictWord{132, 11, 125},
+ dictWord{134, 0, 1030},
+ dictWord{134, 0, 1083},
+ dictWord{132, 11, 721},
+ dictWord{135, 10, 814},
+ dictWord{7, 11, 776},
+ dictWord{
+ 8,
+ 11,
+ 145,
+ },
+ dictWord{147, 11, 56},
+ dictWord{134, 0, 1226},
+ dictWord{4, 10, 57},
+ dictWord{7, 10, 1195},
+ dictWord{7, 10, 1438},
+ dictWord{7, 10, 1548},
+ dictWord{
+ 7,
+ 10,
+ 1835,
+ },
+ dictWord{7, 10, 1904},
+ dictWord{9, 10, 757},
+ dictWord{10, 10, 604},
+ dictWord{139, 10, 519},
+ dictWord{7, 11, 792},
+ dictWord{8, 11, 147},
+ dictWord{10, 11, 821},
+ dictWord{139, 11, 1021},
+ dictWord{137, 11, 797},
+ dictWord{4, 0, 58},
+ dictWord{5, 0, 286},
+ dictWord{6, 0, 319},
+ dictWord{7, 0, 402},
+ dictWord{
+ 7,
+ 0,
+ 1254,
+ },
+ dictWord{7, 0, 1903},
+ dictWord{8, 0, 356},
+ dictWord{140, 0, 408},
+ dictWord{4, 0, 389},
+ dictWord{4, 0, 815},
+ dictWord{9, 0, 181},
+ dictWord{9, 0, 255},
+ dictWord{10, 0, 8},
+ dictWord{10, 0, 29},
+ dictWord{10, 0, 816},
+ dictWord{11, 0, 311},
+ dictWord{11, 0, 561},
+ dictWord{12, 0, 67},
+ dictWord{141, 0, 181},
+ dictWord{
+ 7,
+ 11,
+ 1472,
+ },
+ dictWord{135, 11, 1554},
+ dictWord{7, 11, 1071},
+ dictWord{7, 11, 1541},
+ dictWord{7, 11, 1767},
+ dictWord{7, 11, 1806},
+ dictWord{7, 11, 1999},
+ dictWord{9, 11, 248},
+ dictWord{10, 11, 400},
+ dictWord{11, 11, 162},
+ dictWord{11, 11, 178},
+ dictWord{11, 11, 242},
+ dictWord{12, 11, 605},
+ dictWord{
+ 15,
+ 11,
+ 26,
+ },
+ dictWord{144, 11, 44},
+ dictWord{5, 11, 168},
+ dictWord{5, 11, 930},
+ dictWord{8, 11, 74},
+ dictWord{9, 11, 623},
+ dictWord{12, 11, 500},
+ dictWord{
+ 12,
+ 11,
+ 579,
+ },
+ dictWord{13, 11, 41},
+ dictWord{143, 11, 93},
+ dictWord{6, 11, 220},
+ dictWord{7, 11, 1101},
+ dictWord{141, 11, 105},
+ dictWord{5, 0, 474},
+ dictWord{
+ 7,
+ 0,
+ 507,
+ },
+ dictWord{4, 10, 209},
+ dictWord{7, 11, 507},
+ dictWord{135, 10, 902},
+ dictWord{132, 0, 427},
+ dictWord{6, 0, 413},
+ dictWord{7, 10, 335},
+ dictWord{
+ 7,
+ 10,
+ 1437,
+ },
+ dictWord{7, 10, 1668},
+ dictWord{8, 10, 553},
+ dictWord{8, 10, 652},
+ dictWord{8, 10, 656},
+ dictWord{9, 10, 558},
+ dictWord{11, 10, 743},
+ dictWord{
+ 149,
+ 10,
+ 18,
+ },
+ dictWord{132, 0, 730},
+ dictWord{6, 11, 19},
+ dictWord{7, 11, 1413},
+ dictWord{139, 11, 428},
+ dictWord{133, 0, 373},
+ dictWord{132, 10, 559},
+ dictWord{7, 11, 96},
+ dictWord{8, 11, 401},
+ dictWord{137, 11, 896},
+ dictWord{7, 0, 799},
+ dictWord{7, 0, 1972},
+ dictWord{5, 10, 1017},
+ dictWord{138, 10, 511},
+ dictWord{135, 0, 1793},
+ dictWord{7, 11, 1961},
+ dictWord{7, 11, 1965},
+ dictWord{8, 11, 702},
+ dictWord{136, 11, 750},
+ dictWord{8, 11, 150},
+ dictWord{8, 11, 737},
+ dictWord{140, 11, 366},
+ dictWord{132, 0, 322},
+ dictWord{133, 10, 709},
+ dictWord{8, 11, 800},
+ dictWord{9, 11, 148},
+ dictWord{9, 11, 872},
+ dictWord{
+ 9,
+ 11,
+ 890,
+ },
+ dictWord{11, 11, 309},
+ dictWord{11, 11, 1001},
+ dictWord{13, 11, 267},
+ dictWord{141, 11, 323},
+ dictWord{134, 10, 1745},
+ dictWord{7, 0, 290},
+ dictWord{136, 10, 206},
+ dictWord{7, 0, 1651},
+ dictWord{145, 0, 89},
+ dictWord{139, 0, 2},
+ dictWord{132, 0, 672},
+ dictWord{6, 0, 1860},
+ dictWord{8, 0, 905},
+ dictWord{
+ 10,
+ 0,
+ 844,
+ },
+ dictWord{10, 0, 846},
+ dictWord{10, 0, 858},
+ dictWord{12, 0, 699},
+ dictWord{12, 0, 746},
+ dictWord{140, 0, 772},
+ dictWord{135, 11, 424},
+ dictWord{133, 11, 547},
+ dictWord{133, 0, 737},
+ dictWord{5, 11, 490},
+ dictWord{6, 11, 615},
+ dictWord{6, 11, 620},
+ dictWord{135, 11, 683},
+ dictWord{6, 0, 746},
+ dictWord{134, 0, 1612},
+ dictWord{132, 10, 776},
+ dictWord{9, 11, 385},
+ dictWord{149, 11, 17},
+ dictWord{133, 0, 145},
+ dictWord{135, 10, 1272},
+ dictWord{
+ 7,
+ 0,
+ 884,
+ },
+ dictWord{140, 0, 124},
+ dictWord{4, 0, 387},
+ dictWord{135, 0, 1288},
+ dictWord{5, 11, 133},
+ dictWord{136, 10, 406},
+ dictWord{136, 11, 187},
+ dictWord{
+ 6,
+ 0,
+ 679,
+ },
+ dictWord{8, 11, 8},
+ dictWord{138, 11, 0},
+ dictWord{135, 0, 550},
+ dictWord{135, 11, 798},
+ dictWord{136, 11, 685},
+ dictWord{7, 11, 1086},
+ dictWord{145, 11, 46},
+ dictWord{8, 10, 175},
+ dictWord{10, 10, 168},
+ dictWord{138, 10, 573},
+ dictWord{135, 0, 1305},
+ dictWord{4, 0, 576},
+ dictWord{
+ 135,
+ 0,
+ 1263,
+ },
+ dictWord{6, 0, 686},
+ dictWord{134, 0, 1563},
+ dictWord{134, 0, 607},
+ dictWord{5, 0, 919},
+ dictWord{134, 0, 1673},
+ dictWord{148, 0, 37},
+ dictWord{
+ 8,
+ 11,
+ 774,
+ },
+ dictWord{10, 11, 670},
+ dictWord{140, 11, 51},
+ dictWord{133, 10, 784},
+ dictWord{139, 10, 882},
+ dictWord{4, 0, 82},
+ dictWord{5, 0, 333},
+ dictWord{
+ 5,
+ 0,
+ 904,
+ },
+ dictWord{6, 0, 207},
+ dictWord{7, 0, 325},
+ dictWord{7, 0, 1726},
+ dictWord{8, 0, 101},
+ dictWord{10, 0, 778},
+ dictWord{139, 0, 220},
+ dictWord{135, 11, 371},
+ dictWord{132, 0, 958},
+ dictWord{133, 0, 903},
+ dictWord{4, 11, 127},
+ dictWord{5, 11, 350},
+ dictWord{6, 11, 356},
+ dictWord{8, 11, 426},
+ dictWord{9, 11, 572},
+ dictWord{10, 11, 247},
+ dictWord{139, 11, 312},
+ dictWord{140, 0, 147},
+ dictWord{6, 11, 59},
+ dictWord{7, 11, 885},
+ dictWord{9, 11, 603},
+ dictWord{
+ 141,
+ 11,
+ 397,
+ },
+ dictWord{10, 0, 367},
+ dictWord{9, 10, 14},
+ dictWord{9, 10, 441},
+ dictWord{139, 10, 9},
+ dictWord{11, 10, 966},
+ dictWord{12, 10, 287},
+ dictWord{
+ 13,
+ 10,
+ 342,
+ },
+ dictWord{13, 10, 402},
+ dictWord{15, 10, 110},
+ dictWord{143, 10, 163},
+ dictWord{134, 0, 690},
+ dictWord{132, 0, 705},
+ dictWord{9, 0, 651},
+ dictWord{
+ 11,
+ 0,
+ 971,
+ },
+ dictWord{13, 0, 273},
+ dictWord{7, 10, 1428},
+ dictWord{7, 10, 1640},
+ dictWord{7, 10, 1867},
+ dictWord{9, 10, 169},
+ dictWord{9, 10, 182},
+ dictWord{
+ 9,
+ 10,
+ 367,
+ },
+ dictWord{9, 10, 478},
+ dictWord{9, 10, 506},
+ dictWord{9, 10, 551},
+ dictWord{9, 10, 557},
+ dictWord{9, 10, 648},
+ dictWord{9, 10, 697},
+ dictWord{
+ 9,
+ 10,
+ 705,
+ },
+ dictWord{9, 10, 725},
+ dictWord{9, 10, 787},
+ dictWord{9, 10, 794},
+ dictWord{10, 10, 198},
+ dictWord{10, 10, 214},
+ dictWord{10, 10, 267},
+ dictWord{
+ 10,
+ 10,
+ 275,
+ },
+ dictWord{10, 10, 456},
+ dictWord{10, 10, 551},
+ dictWord{10, 10, 561},
+ dictWord{10, 10, 613},
+ dictWord{10, 10, 627},
+ dictWord{10, 10, 668},
+ dictWord{10, 10, 675},
+ dictWord{10, 10, 691},
+ dictWord{10, 10, 695},
+ dictWord{10, 10, 707},
+ dictWord{10, 10, 715},
+ dictWord{11, 10, 183},
+ dictWord{
+ 11,
+ 10,
+ 201,
+ },
+ dictWord{11, 10, 262},
+ dictWord{11, 10, 352},
+ dictWord{11, 10, 439},
+ dictWord{11, 10, 493},
+ dictWord{11, 10, 572},
+ dictWord{11, 10, 591},
+ dictWord{
+ 11,
+ 10,
+ 608,
+ },
+ dictWord{11, 10, 611},
+ dictWord{11, 10, 646},
+ dictWord{11, 10, 674},
+ dictWord{11, 10, 711},
+ dictWord{11, 10, 751},
+ dictWord{11, 10, 761},
+ dictWord{11, 10, 776},
+ dictWord{11, 10, 785},
+ dictWord{11, 10, 850},
+ dictWord{11, 10, 853},
+ dictWord{11, 10, 862},
+ dictWord{11, 10, 865},
+ dictWord{
+ 11,
+ 10,
+ 868,
+ },
+ dictWord{11, 10, 875},
+ dictWord{11, 10, 898},
+ dictWord{11, 10, 902},
+ dictWord{11, 10, 903},
+ dictWord{11, 10, 910},
+ dictWord{11, 10, 932},
+ dictWord{
+ 11,
+ 10,
+ 942,
+ },
+ dictWord{11, 10, 957},
+ dictWord{11, 10, 967},
+ dictWord{11, 10, 972},
+ dictWord{12, 10, 148},
+ dictWord{12, 10, 195},
+ dictWord{12, 10, 220},
+ dictWord{12, 10, 237},
+ dictWord{12, 10, 318},
+ dictWord{12, 10, 339},
+ dictWord{12, 10, 393},
+ dictWord{12, 10, 445},
+ dictWord{12, 10, 450},
+ dictWord{
+ 12,
+ 10,
+ 474,
+ },
+ dictWord{12, 10, 505},
+ dictWord{12, 10, 509},
+ dictWord{12, 10, 533},
+ dictWord{12, 10, 591},
+ dictWord{12, 10, 594},
+ dictWord{12, 10, 597},
+ dictWord{
+ 12,
+ 10,
+ 621,
+ },
+ dictWord{12, 10, 633},
+ dictWord{12, 10, 642},
+ dictWord{13, 10, 59},
+ dictWord{13, 10, 60},
+ dictWord{13, 10, 145},
+ dictWord{13, 10, 239},
+ dictWord{13, 10, 250},
+ dictWord{13, 10, 329},
+ dictWord{13, 10, 344},
+ dictWord{13, 10, 365},
+ dictWord{13, 10, 372},
+ dictWord{13, 10, 387},
+ dictWord{
+ 13,
+ 10,
+ 403,
+ },
+ dictWord{13, 10, 414},
+ dictWord{13, 10, 456},
+ dictWord{13, 10, 470},
+ dictWord{13, 10, 478},
+ dictWord{13, 10, 483},
+ dictWord{13, 10, 489},
+ dictWord{
+ 14,
+ 10,
+ 55,
+ },
+ dictWord{14, 10, 57},
+ dictWord{14, 10, 81},
+ dictWord{14, 10, 90},
+ dictWord{14, 10, 148},
+ dictWord{14, 10, 239},
+ dictWord{14, 10, 266},
+ dictWord{
+ 14,
+ 10,
+ 321,
+ },
+ dictWord{14, 10, 326},
+ dictWord{14, 10, 327},
+ dictWord{14, 10, 330},
+ dictWord{14, 10, 347},
+ dictWord{14, 10, 355},
+ dictWord{14, 10, 401},
+ dictWord{14, 10, 404},
+ dictWord{14, 10, 411},
+ dictWord{14, 10, 414},
+ dictWord{14, 10, 416},
+ dictWord{14, 10, 420},
+ dictWord{15, 10, 61},
+ dictWord{
+ 15,
+ 10,
+ 74,
+ },
+ dictWord{15, 10, 87},
+ dictWord{15, 10, 88},
+ dictWord{15, 10, 94},
+ dictWord{15, 10, 96},
+ dictWord{15, 10, 116},
+ dictWord{15, 10, 149},
+ dictWord{
+ 15,
+ 10,
+ 154,
+ },
+ dictWord{16, 10, 50},
+ dictWord{16, 10, 63},
+ dictWord{16, 10, 73},
+ dictWord{17, 10, 2},
+ dictWord{17, 10, 66},
+ dictWord{17, 10, 92},
+ dictWord{17, 10, 103},
+ dictWord{17, 10, 112},
+ dictWord{17, 10, 120},
+ dictWord{18, 10, 50},
+ dictWord{18, 10, 54},
+ dictWord{18, 10, 82},
+ dictWord{18, 10, 86},
+ dictWord{18, 10, 90},
+ dictWord{18, 10, 111},
+ dictWord{18, 10, 115},
+ dictWord{18, 10, 156},
+ dictWord{19, 10, 40},
+ dictWord{19, 10, 79},
+ dictWord{20, 10, 78},
+ dictWord{149, 10, 22},
+ dictWord{7, 0, 887},
+ dictWord{5, 10, 161},
+ dictWord{135, 10, 839},
+ dictWord{142, 11, 98},
+ dictWord{134, 0, 90},
+ dictWord{138, 11, 356},
+ dictWord{
+ 135,
+ 11,
+ 441,
+ },
+ dictWord{6, 11, 111},
+ dictWord{7, 11, 4},
+ dictWord{8, 11, 163},
+ dictWord{8, 11, 776},
+ dictWord{138, 11, 566},
+ dictWord{134, 0, 908},
+ dictWord{
+ 134,
+ 0,
+ 1261,
+ },
+ dictWord{7, 0, 813},
+ dictWord{12, 0, 497},
+ dictWord{141, 0, 56},
+ dictWord{134, 0, 1235},
+ dictWord{135, 0, 429},
+ dictWord{135, 11, 1994},
+ dictWord{138, 0, 904},
+ dictWord{6, 0, 125},
+ dictWord{7, 0, 1277},
+ dictWord{137, 0, 772},
+ dictWord{151, 0, 12},
+ dictWord{4, 0, 841},
+ dictWord{5, 0, 386},
+ dictWord{
+ 133,
+ 11,
+ 386,
+ },
+ dictWord{5, 11, 297},
+ dictWord{135, 11, 1038},
+ dictWord{6, 0, 860},
+ dictWord{6, 0, 1069},
+ dictWord{135, 11, 309},
+ dictWord{136, 0, 946},
+ dictWord{135, 10, 1814},
+ dictWord{141, 11, 418},
+ dictWord{136, 11, 363},
+ dictWord{10, 0, 768},
+ dictWord{139, 0, 787},
+ dictWord{22, 11, 30},
+ dictWord{
+ 150,
+ 11,
+ 33,
+ },
+ dictWord{6, 0, 160},
+ dictWord{7, 0, 1106},
+ dictWord{9, 0, 770},
+ dictWord{11, 0, 112},
+ dictWord{140, 0, 413},
+ dictWord{11, 11, 216},
+ dictWord{
+ 139,
+ 11,
+ 340,
+ },
+ dictWord{136, 10, 139},
+ dictWord{135, 11, 1390},
+ dictWord{135, 11, 808},
+ dictWord{132, 11, 280},
+ dictWord{12, 0, 271},
+ dictWord{17, 0, 109},
+ dictWord{7, 10, 643},
+ dictWord{136, 10, 236},
+ dictWord{140, 11, 54},
+ dictWord{4, 11, 421},
+ dictWord{133, 11, 548},
+ dictWord{11, 0, 719},
+ dictWord{12, 0, 36},
+ dictWord{141, 0, 337},
+ dictWord{7, 0, 581},
+ dictWord{9, 0, 644},
+ dictWord{137, 0, 699},
+ dictWord{11, 11, 511},
+ dictWord{13, 11, 394},
+ dictWord{14, 11, 298},
+ dictWord{14, 11, 318},
+ dictWord{146, 11, 103},
+ dictWord{7, 0, 304},
+ dictWord{9, 0, 646},
+ dictWord{9, 0, 862},
+ dictWord{11, 0, 696},
+ dictWord{12, 0, 208},
+ dictWord{15, 0, 79},
+ dictWord{147, 0, 108},
+ dictWord{4, 0, 631},
+ dictWord{7, 0, 1126},
+ dictWord{135, 0, 1536},
+ dictWord{135, 11, 1527},
+ dictWord{8, 0, 880},
+ dictWord{10, 0, 869},
+ dictWord{138, 0, 913},
+ dictWord{7, 0, 1513},
+ dictWord{5, 10, 54},
+ dictWord{6, 11, 254},
+ dictWord{9, 11, 109},
+ dictWord{138, 11, 103},
+ dictWord{135, 0, 981},
+ dictWord{133, 11, 729},
+ dictWord{132, 10, 744},
+ dictWord{132, 0, 434},
+ dictWord{134, 0, 550},
+ dictWord{7, 0, 930},
+ dictWord{10, 0, 476},
+ dictWord{13, 0, 452},
+ dictWord{19, 0, 104},
+ dictWord{6, 11, 1630},
+ dictWord{10, 10, 402},
+ dictWord{146, 10, 55},
+ dictWord{5, 0, 553},
+ dictWord{138, 0, 824},
+ dictWord{136, 0, 452},
+ dictWord{8, 0, 151},
+ dictWord{137, 10, 624},
+ dictWord{132, 10, 572},
+ dictWord{132, 0, 772},
+ dictWord{133, 11, 671},
+ dictWord{
+ 133,
+ 0,
+ 292,
+ },
+ dictWord{138, 0, 135},
+ dictWord{132, 11, 889},
+ dictWord{140, 11, 207},
+ dictWord{9, 0, 504},
+ dictWord{6, 10, 43},
+ dictWord{7, 10, 38},
+ dictWord{
+ 8,
+ 10,
+ 248,
+ },
+ dictWord{138, 10, 513},
+ dictWord{6, 0, 1089},
+ dictWord{135, 11, 1910},
+ dictWord{4, 11, 627},
+ dictWord{133, 11, 775},
+ dictWord{135, 0, 783},
+ dictWord{133, 10, 766},
+ dictWord{133, 10, 363},
+ dictWord{7, 0, 387},
+ dictWord{135, 11, 387},
+ dictWord{7, 0, 393},
+ dictWord{10, 0, 603},
+ dictWord{11, 0, 206},
+ dictWord{7, 11, 202},
+ dictWord{11, 11, 362},
+ dictWord{11, 11, 948},
+ dictWord{140, 11, 388},
+ dictWord{6, 11, 507},
+ dictWord{7, 11, 451},
+ dictWord{8, 11, 389},
+ dictWord{12, 11, 490},
+ dictWord{13, 11, 16},
+ dictWord{13, 11, 215},
+ dictWord{13, 11, 351},
+ dictWord{18, 11, 132},
+ dictWord{147, 11, 125},
+ dictWord{
+ 4,
+ 0,
+ 912,
+ },
+ dictWord{9, 0, 232},
+ dictWord{135, 11, 841},
+ dictWord{6, 10, 258},
+ dictWord{140, 10, 409},
+ dictWord{5, 10, 249},
+ dictWord{148, 10, 82},
+ dictWord{
+ 136,
+ 11,
+ 566,
+ },
+ dictWord{6, 0, 977},
+ dictWord{135, 11, 1214},
+ dictWord{7, 0, 1973},
+ dictWord{136, 0, 716},
+ dictWord{135, 0, 98},
+ dictWord{133, 0, 733},
+ dictWord{
+ 5,
+ 11,
+ 912,
+ },
+ dictWord{134, 11, 1695},
+ dictWord{5, 10, 393},
+ dictWord{6, 10, 378},
+ dictWord{7, 10, 1981},
+ dictWord{9, 10, 32},
+ dictWord{9, 10, 591},
+ dictWord{10, 10, 685},
+ dictWord{10, 10, 741},
+ dictWord{142, 10, 382},
+ dictWord{133, 10, 788},
+ dictWord{10, 0, 19},
+ dictWord{11, 0, 911},
+ dictWord{7, 10, 1968},
+ dictWord{141, 10, 509},
+ dictWord{5, 0, 668},
+ dictWord{5, 11, 236},
+ dictWord{6, 11, 572},
+ dictWord{8, 11, 492},
+ dictWord{11, 11, 618},
+ dictWord{144, 11, 56},
+ dictWord{135, 11, 1789},
+ dictWord{4, 0, 360},
+ dictWord{5, 0, 635},
+ dictWord{5, 0, 700},
+ dictWord{5, 10, 58},
+ dictWord{5, 10, 171},
+ dictWord{5, 10, 683},
+ dictWord{
+ 6,
+ 10,
+ 291,
+ },
+ dictWord{6, 10, 566},
+ dictWord{7, 10, 1650},
+ dictWord{11, 10, 523},
+ dictWord{12, 10, 273},
+ dictWord{12, 10, 303},
+ dictWord{15, 10, 39},
+ dictWord{143, 10, 111},
+ dictWord{133, 0, 901},
+ dictWord{134, 10, 589},
+ dictWord{5, 11, 190},
+ dictWord{136, 11, 318},
+ dictWord{140, 0, 656},
+ dictWord{
+ 7,
+ 0,
+ 726,
+ },
+ dictWord{152, 0, 9},
+ dictWord{4, 10, 917},
+ dictWord{133, 10, 1005},
+ dictWord{135, 10, 1598},
+ dictWord{134, 11, 491},
+ dictWord{4, 10, 919},
+ dictWord{133, 11, 434},
+ dictWord{137, 0, 72},
+ dictWord{6, 0, 1269},
+ dictWord{6, 0, 1566},
+ dictWord{134, 0, 1621},
+ dictWord{9, 0, 463},
+ dictWord{10, 0, 595},
+ dictWord{4, 10, 255},
+ dictWord{5, 10, 302},
+ dictWord{6, 10, 132},
+ dictWord{7, 10, 128},
+ dictWord{7, 10, 283},
+ dictWord{7, 10, 1299},
+ dictWord{10, 10, 52},
+ dictWord{
+ 10,
+ 10,
+ 514,
+ },
+ dictWord{11, 10, 925},
+ dictWord{13, 10, 92},
+ dictWord{142, 10, 309},
+ dictWord{135, 0, 1454},
+ dictWord{134, 0, 1287},
+ dictWord{11, 0, 600},
+ dictWord{13, 0, 245},
+ dictWord{137, 10, 173},
+ dictWord{136, 0, 989},
+ dictWord{7, 0, 164},
+ dictWord{7, 0, 1571},
+ dictWord{9, 0, 107},
+ dictWord{140, 0, 225},
+ dictWord{6, 0, 1061},
+ dictWord{141, 10, 442},
+ dictWord{4, 0, 27},
+ dictWord{5, 0, 484},
+ dictWord{5, 0, 510},
+ dictWord{6, 0, 434},
+ dictWord{7, 0, 1000},
+ dictWord{
+ 7,
+ 0,
+ 1098,
+ },
+ dictWord{136, 0, 2},
+ dictWord{7, 11, 85},
+ dictWord{7, 11, 247},
+ dictWord{8, 11, 585},
+ dictWord{10, 11, 163},
+ dictWord{138, 11, 316},
+ dictWord{
+ 11,
+ 11,
+ 103,
+ },
+ dictWord{142, 11, 0},
+ dictWord{134, 0, 1127},
+ dictWord{4, 0, 460},
+ dictWord{134, 0, 852},
+ dictWord{134, 10, 210},
+ dictWord{4, 0, 932},
+ dictWord{
+ 133,
+ 0,
+ 891,
+ },
+ dictWord{6, 0, 588},
+ dictWord{147, 11, 83},
+ dictWord{8, 0, 625},
+ dictWord{4, 10, 284},
+ dictWord{134, 10, 223},
+ dictWord{134, 0, 76},
+ dictWord{8, 0, 92},
+ dictWord{137, 0, 221},
+ dictWord{4, 11, 124},
+ dictWord{10, 11, 457},
+ dictWord{11, 11, 121},
+ dictWord{11, 11, 169},
+ dictWord{11, 11, 422},
+ dictWord{
+ 11,
+ 11,
+ 870,
+ },
+ dictWord{12, 11, 214},
+ dictWord{13, 11, 389},
+ dictWord{14, 11, 187},
+ dictWord{143, 11, 77},
+ dictWord{9, 11, 618},
+ dictWord{138, 11, 482},
+ dictWord{
+ 4,
+ 10,
+ 218,
+ },
+ dictWord{7, 10, 526},
+ dictWord{143, 10, 137},
+ dictWord{13, 0, 9},
+ dictWord{14, 0, 104},
+ dictWord{14, 0, 311},
+ dictWord{4, 10, 270},
+ dictWord{
+ 5,
+ 10,
+ 192,
+ },
+ dictWord{6, 10, 332},
+ dictWord{135, 10, 1322},
+ dictWord{140, 10, 661},
+ dictWord{135, 11, 1193},
+ dictWord{6, 11, 107},
+ dictWord{7, 11, 638},
+ dictWord{7, 11, 1632},
+ dictWord{137, 11, 396},
+ dictWord{132, 0, 763},
+ dictWord{4, 0, 622},
+ dictWord{5, 11, 370},
+ dictWord{134, 11, 1756},
+ dictWord{
+ 133,
+ 0,
+ 253,
+ },
+ dictWord{135, 0, 546},
+ dictWord{9, 0, 73},
+ dictWord{10, 0, 110},
+ dictWord{14, 0, 185},
+ dictWord{17, 0, 119},
+ dictWord{133, 11, 204},
+ dictWord{7, 0, 624},
+ dictWord{7, 0, 916},
+ dictWord{10, 0, 256},
+ dictWord{139, 0, 87},
+ dictWord{7, 10, 379},
+ dictWord{8, 10, 481},
+ dictWord{137, 10, 377},
+ dictWord{5, 0, 212},
+ dictWord{12, 0, 35},
+ dictWord{13, 0, 382},
+ dictWord{5, 11, 970},
+ dictWord{134, 11, 1706},
+ dictWord{9, 0, 746},
+ dictWord{5, 10, 1003},
+ dictWord{134, 10, 149},
+ dictWord{10, 0, 150},
+ dictWord{11, 0, 849},
+ dictWord{13, 0, 330},
+ dictWord{8, 10, 262},
+ dictWord{9, 10, 627},
+ dictWord{11, 10, 214},
+ dictWord{11, 10, 404},
+ dictWord{11, 10, 457},
+ dictWord{11, 10, 780},
+ dictWord{11, 10, 913},
+ dictWord{13, 10, 401},
+ dictWord{142, 10, 200},
+ dictWord{134, 0, 1466},
+ dictWord{
+ 135,
+ 11,
+ 3,
+ },
+ dictWord{6, 0, 1299},
+ dictWord{4, 11, 35},
+ dictWord{5, 11, 121},
+ dictWord{5, 11, 483},
+ dictWord{5, 11, 685},
+ dictWord{6, 11, 489},
+ dictWord{7, 11, 1204},
+ dictWord{136, 11, 394},
+ dictWord{135, 10, 742},
+ dictWord{4, 10, 142},
+ dictWord{136, 10, 304},
+ dictWord{4, 11, 921},
+ dictWord{133, 11, 1007},
+ dictWord{
+ 134,
+ 0,
+ 1518,
+ },
+ dictWord{6, 0, 1229},
+ dictWord{135, 0, 1175},
+ dictWord{133, 0, 816},
+ dictWord{12, 0, 159},
+ dictWord{4, 10, 471},
+ dictWord{4, 11, 712},
+ dictWord{
+ 5,
+ 10,
+ 51,
+ },
+ dictWord{6, 10, 602},
+ dictWord{7, 10, 925},
+ dictWord{8, 10, 484},
+ dictWord{138, 10, 195},
+ dictWord{134, 11, 1629},
+ dictWord{5, 0, 869},
+ dictWord{
+ 5,
+ 0,
+ 968,
+ },
+ dictWord{6, 0, 1626},
+ dictWord{8, 0, 734},
+ dictWord{136, 0, 784},
+ dictWord{4, 0, 542},
+ dictWord{6, 0, 1716},
+ dictWord{6, 0, 1727},
+ dictWord{
+ 7,
+ 0,
+ 1082,
+ },
+ dictWord{7, 0, 1545},
+ dictWord{8, 0, 56},
+ dictWord{8, 0, 118},
+ dictWord{8, 0, 412},
+ dictWord{8, 0, 564},
+ dictWord{9, 0, 888},
+ dictWord{9, 0, 908},
+ dictWord{
+ 10,
+ 0,
+ 50,
+ },
+ dictWord{10, 0, 423},
+ dictWord{11, 0, 685},
+ dictWord{11, 0, 697},
+ dictWord{11, 0, 933},
+ dictWord{12, 0, 299},
+ dictWord{13, 0, 126},
+ dictWord{
+ 13,
+ 0,
+ 136,
+ },
+ dictWord{13, 0, 170},
+ dictWord{13, 0, 190},
+ dictWord{136, 10, 688},
+ dictWord{132, 10, 697},
+ dictWord{4, 0, 232},
+ dictWord{9, 0, 202},
+ dictWord{
+ 10,
+ 0,
+ 474,
+ },
+ dictWord{140, 0, 433},
+ dictWord{136, 0, 212},
+ dictWord{6, 0, 108},
+ dictWord{7, 0, 1003},
+ dictWord{7, 0, 1181},
+ dictWord{8, 0, 111},
+ dictWord{
+ 136,
+ 0,
+ 343,
+ },
+ dictWord{5, 10, 221},
+ dictWord{135, 11, 1255},
+ dictWord{133, 11, 485},
+ dictWord{134, 0, 1712},
+ dictWord{142, 0, 216},
+ dictWord{5, 0, 643},
+ dictWord{
+ 6,
+ 0,
+ 516,
+ },
+ dictWord{4, 11, 285},
+ dictWord{5, 11, 317},
+ dictWord{6, 11, 301},
+ dictWord{7, 11, 7},
+ dictWord{8, 11, 153},
+ dictWord{10, 11, 766},
+ dictWord{
+ 11,
+ 11,
+ 468,
+ },
+ dictWord{12, 11, 467},
+ dictWord{141, 11, 143},
+ dictWord{4, 0, 133},
+ dictWord{7, 0, 711},
+ dictWord{7, 0, 1298},
+ dictWord{135, 0, 1585},
+ dictWord{
+ 134,
+ 0,
+ 650,
+ },
+ dictWord{135, 11, 512},
+ dictWord{6, 0, 99},
+ dictWord{7, 0, 1808},
+ dictWord{145, 0, 57},
+ dictWord{6, 0, 246},
+ dictWord{6, 0, 574},
+ dictWord{7, 0, 428},
+ dictWord{9, 0, 793},
+ dictWord{10, 0, 669},
+ dictWord{11, 0, 485},
+ dictWord{11, 0, 840},
+ dictWord{12, 0, 300},
+ dictWord{14, 0, 250},
+ dictWord{145, 0, 55},
+ dictWord{
+ 4,
+ 10,
+ 132,
+ },
+ dictWord{5, 10, 69},
+ dictWord{135, 10, 1242},
+ dictWord{136, 0, 1023},
+ dictWord{7, 0, 302},
+ dictWord{132, 10, 111},
+ dictWord{135, 0, 1871},
+ dictWord{132, 0, 728},
+ dictWord{9, 0, 252},
+ dictWord{132, 10, 767},
+ dictWord{6, 0, 461},
+ dictWord{7, 0, 1590},
+ dictWord{7, 10, 1416},
+ dictWord{7, 10, 2005},
+ dictWord{8, 10, 131},
+ dictWord{8, 10, 466},
+ dictWord{9, 10, 672},
+ dictWord{13, 10, 252},
+ dictWord{148, 10, 103},
+ dictWord{6, 0, 323},
+ dictWord{135, 0, 1564},
+ dictWord{7, 0, 461},
+ dictWord{136, 0, 775},
+ dictWord{6, 10, 44},
+ dictWord{136, 10, 368},
+ dictWord{139, 0, 172},
+ dictWord{132, 0, 464},
+ dictWord{4, 10, 570},
+ dictWord{133, 10, 120},
+ dictWord{137, 11, 269},
+ dictWord{6, 10, 227},
+ dictWord{135, 10, 1589},
+ dictWord{6, 11, 1719},
+ dictWord{6, 11, 1735},
+ dictWord{
+ 7,
+ 11,
+ 2016,
+ },
+ dictWord{7, 11, 2020},
+ dictWord{8, 11, 837},
+ dictWord{137, 11, 852},
+ dictWord{7, 0, 727},
+ dictWord{146, 0, 73},
+ dictWord{132, 0, 1023},
+ dictWord{135, 11, 852},
+ dictWord{135, 10, 1529},
+ dictWord{136, 0, 577},
+ dictWord{138, 11, 568},
+ dictWord{134, 0, 1037},
+ dictWord{8, 11, 67},
+ dictWord{
+ 138,
+ 11,
+ 419,
+ },
+ dictWord{4, 0, 413},
+ dictWord{5, 0, 677},
+ dictWord{8, 0, 432},
+ dictWord{140, 0, 280},
+ dictWord{10, 0, 600},
+ dictWord{6, 10, 1667},
+ dictWord{
+ 7,
+ 11,
+ 967,
+ },
+ dictWord{7, 10, 2036},
+ dictWord{141, 11, 11},
+ dictWord{6, 10, 511},
+ dictWord{140, 10, 132},
+ dictWord{6, 0, 799},
+ dictWord{5, 10, 568},
+ dictWord{
+ 6,
+ 10,
+ 138,
+ },
+ dictWord{135, 10, 1293},
+ dictWord{8, 0, 159},
+ dictWord{4, 10, 565},
+ dictWord{136, 10, 827},
+ dictWord{7, 0, 646},
+ dictWord{7, 0, 1730},
+ dictWord{
+ 11,
+ 0,
+ 446,
+ },
+ dictWord{141, 0, 178},
+ dictWord{4, 10, 922},
+ dictWord{133, 10, 1023},
+ dictWord{135, 11, 11},
+ dictWord{132, 0, 395},
+ dictWord{11, 0, 145},
+ dictWord{135, 10, 1002},
+ dictWord{9, 0, 174},
+ dictWord{10, 0, 164},
+ dictWord{11, 0, 440},
+ dictWord{11, 0, 514},
+ dictWord{11, 0, 841},
+ dictWord{15, 0, 98},
+ dictWord{149, 0, 20},
+ dictWord{134, 0, 426},
+ dictWord{10, 0, 608},
+ dictWord{139, 0, 1002},
+ dictWord{7, 11, 320},
+ dictWord{8, 11, 51},
+ dictWord{12, 11, 481},
+ dictWord{12, 11, 570},
+ dictWord{148, 11, 106},
+ dictWord{9, 0, 977},
+ dictWord{9, 0, 983},
+ dictWord{132, 11, 445},
+ dictWord{138, 0, 250},
+ dictWord{139, 0, 100},
+ dictWord{6, 0, 1982},
+ dictWord{136, 10, 402},
+ dictWord{133, 11, 239},
+ dictWord{4, 10, 716},
+ dictWord{141, 10, 31},
+ dictWord{5, 0, 476},
+ dictWord{7, 11, 83},
+ dictWord{7, 11, 1990},
+ dictWord{8, 11, 130},
+ dictWord{139, 11, 720},
+ dictWord{8, 10, 691},
+ dictWord{136, 10, 731},
+ dictWord{5, 11, 123},
+ dictWord{
+ 6,
+ 11,
+ 530,
+ },
+ dictWord{7, 11, 348},
+ dictWord{135, 11, 1419},
+ dictWord{5, 0, 76},
+ dictWord{6, 0, 458},
+ dictWord{6, 0, 497},
+ dictWord{7, 0, 868},
+ dictWord{9, 0, 658},
+ dictWord{10, 0, 594},
+ dictWord{11, 0, 173},
+ dictWord{11, 0, 566},
+ dictWord{12, 0, 20},
+ dictWord{12, 0, 338},
+ dictWord{141, 0, 200},
+ dictWord{9, 11, 139},
+ dictWord{
+ 10,
+ 11,
+ 399,
+ },
+ dictWord{11, 11, 469},
+ dictWord{12, 11, 634},
+ dictWord{141, 11, 223},
+ dictWord{9, 10, 840},
+ dictWord{138, 10, 803},
+ dictWord{133, 10, 847},
+ dictWord{11, 11, 223},
+ dictWord{140, 11, 168},
+ dictWord{132, 11, 210},
+ dictWord{8, 0, 447},
+ dictWord{9, 10, 53},
+ dictWord{9, 10, 268},
+ dictWord{9, 10, 901},
+ dictWord{10, 10, 518},
+ dictWord{10, 10, 829},
+ dictWord{11, 10, 188},
+ dictWord{13, 10, 74},
+ dictWord{14, 10, 46},
+ dictWord{15, 10, 17},
+ dictWord{15, 10, 33},
+ dictWord{17, 10, 40},
+ dictWord{18, 10, 36},
+ dictWord{19, 10, 20},
+ dictWord{22, 10, 1},
+ dictWord{152, 10, 2},
+ dictWord{4, 0, 526},
+ dictWord{7, 0, 1029},
+ dictWord{135, 0, 1054},
+ dictWord{19, 11, 59},
+ dictWord{150, 11, 2},
+ dictWord{4, 0, 636},
+ dictWord{6, 0, 1875},
+ dictWord{6, 0, 1920},
+ dictWord{9, 0, 999},
+ dictWord{
+ 12,
+ 0,
+ 807,
+ },
+ dictWord{12, 0, 825},
+ dictWord{15, 0, 179},
+ dictWord{15, 0, 190},
+ dictWord{18, 0, 182},
+ dictWord{136, 10, 532},
+ dictWord{6, 0, 1699},
+ dictWord{
+ 7,
+ 0,
+ 660,
+ },
+ dictWord{7, 0, 1124},
+ dictWord{17, 0, 31},
+ dictWord{19, 0, 22},
+ dictWord{151, 0, 14},
+ dictWord{135, 10, 681},
+ dictWord{132, 11, 430},
+ dictWord{
+ 140,
+ 10,
+ 677,
+ },
+ dictWord{4, 10, 684},
+ dictWord{136, 10, 384},
+ dictWord{132, 11, 756},
+ dictWord{133, 11, 213},
+ dictWord{7, 0, 188},
+ dictWord{7, 10, 110},
+ dictWord{
+ 8,
+ 10,
+ 290,
+ },
+ dictWord{8, 10, 591},
+ dictWord{9, 10, 382},
+ dictWord{9, 10, 649},
+ dictWord{11, 10, 71},
+ dictWord{11, 10, 155},
+ dictWord{11, 10, 313},
+ dictWord{
+ 12,
+ 10,
+ 5,
+ },
+ dictWord{13, 10, 325},
+ dictWord{142, 10, 287},
+ dictWord{7, 10, 360},
+ dictWord{7, 10, 425},
+ dictWord{9, 10, 66},
+ dictWord{9, 10, 278},
+ dictWord{
+ 138,
+ 10,
+ 644,
+ },
+ dictWord{142, 11, 164},
+ dictWord{4, 0, 279},
+ dictWord{7, 0, 301},
+ dictWord{137, 0, 362},
+ dictWord{134, 11, 586},
+ dictWord{135, 0, 1743},
+ dictWord{4, 0, 178},
+ dictWord{133, 0, 399},
+ dictWord{4, 10, 900},
+ dictWord{133, 10, 861},
+ dictWord{5, 10, 254},
+ dictWord{7, 10, 985},
+ dictWord{136, 10, 73},
+ dictWord{133, 11, 108},
+ dictWord{7, 10, 1959},
+ dictWord{136, 10, 683},
+ dictWord{133, 11, 219},
+ dictWord{4, 11, 193},
+ dictWord{5, 11, 916},
+ dictWord{
+ 7,
+ 11,
+ 364,
+ },
+ dictWord{10, 11, 398},
+ dictWord{10, 11, 726},
+ dictWord{11, 11, 317},
+ dictWord{11, 11, 626},
+ dictWord{12, 11, 142},
+ dictWord{12, 11, 288},
+ dictWord{
+ 12,
+ 11,
+ 678,
+ },
+ dictWord{13, 11, 313},
+ dictWord{15, 11, 113},
+ dictWord{18, 11, 114},
+ dictWord{21, 11, 30},
+ dictWord{150, 11, 53},
+ dictWord{6, 11, 241},
+ dictWord{7, 11, 907},
+ dictWord{8, 11, 832},
+ dictWord{9, 11, 342},
+ dictWord{10, 11, 729},
+ dictWord{11, 11, 284},
+ dictWord{11, 11, 445},
+ dictWord{11, 11, 651},
+ dictWord{11, 11, 863},
+ dictWord{13, 11, 398},
+ dictWord{146, 11, 99},
+ dictWord{132, 0, 872},
+ dictWord{134, 0, 831},
+ dictWord{134, 0, 1692},
+ dictWord{
+ 6,
+ 0,
+ 202,
+ },
+ dictWord{6, 0, 1006},
+ dictWord{9, 0, 832},
+ dictWord{10, 0, 636},
+ dictWord{11, 0, 208},
+ dictWord{12, 0, 360},
+ dictWord{17, 0, 118},
+ dictWord{18, 0, 27},
+ dictWord{20, 0, 67},
+ dictWord{137, 11, 734},
+ dictWord{132, 10, 725},
+ dictWord{7, 11, 993},
+ dictWord{138, 11, 666},
+ dictWord{134, 0, 1954},
+ dictWord{
+ 134,
+ 10,
+ 196,
+ },
+ dictWord{7, 0, 872},
+ dictWord{10, 0, 516},
+ dictWord{139, 0, 167},
+ dictWord{133, 10, 831},
+ dictWord{4, 11, 562},
+ dictWord{9, 11, 254},
+ dictWord{
+ 139,
+ 11,
+ 879,
+ },
+ dictWord{137, 0, 313},
+ dictWord{4, 0, 224},
+ dictWord{132, 11, 786},
+ dictWord{11, 0, 24},
+ dictWord{12, 0, 170},
+ dictWord{136, 10, 723},
+ dictWord{
+ 5,
+ 0,
+ 546,
+ },
+ dictWord{7, 0, 35},
+ dictWord{8, 0, 11},
+ dictWord{8, 0, 12},
+ dictWord{9, 0, 315},
+ dictWord{9, 0, 533},
+ dictWord{10, 0, 802},
+ dictWord{11, 0, 166},
+ dictWord{
+ 12,
+ 0,
+ 525,
+ },
+ dictWord{142, 0, 243},
+ dictWord{7, 0, 1937},
+ dictWord{13, 10, 80},
+ dictWord{13, 10, 437},
+ dictWord{145, 10, 74},
+ dictWord{5, 0, 241},
+ dictWord{
+ 8,
+ 0,
+ 242,
+ },
+ dictWord{9, 0, 451},
+ dictWord{10, 0, 667},
+ dictWord{11, 0, 598},
+ dictWord{140, 0, 429},
+ dictWord{150, 0, 46},
+ dictWord{6, 0, 1273},
+ dictWord{
+ 137,
+ 0,
+ 830,
+ },
+ dictWord{5, 10, 848},
+ dictWord{6, 10, 66},
+ dictWord{136, 10, 764},
+ dictWord{6, 0, 825},
+ dictWord{134, 0, 993},
+ dictWord{4, 0, 1006},
+ dictWord{
+ 10,
+ 0,
+ 327,
+ },
+ dictWord{13, 0, 271},
+ dictWord{4, 10, 36},
+ dictWord{7, 10, 1387},
+ dictWord{139, 10, 755},
+ dictWord{134, 0, 1023},
+ dictWord{135, 0, 1580},
+ dictWord{
+ 4,
+ 0,
+ 366,
+ },
+ dictWord{137, 0, 516},
+ dictWord{132, 10, 887},
+ dictWord{6, 0, 1736},
+ dictWord{135, 0, 1891},
+ dictWord{6, 11, 216},
+ dictWord{7, 11, 901},
+ dictWord{
+ 7,
+ 11,
+ 1343,
+ },
+ dictWord{136, 11, 493},
+ dictWord{6, 10, 165},
+ dictWord{138, 10, 388},
+ dictWord{7, 11, 341},
+ dictWord{139, 11, 219},
+ dictWord{4, 10, 719},
+ dictWord{135, 10, 155},
+ dictWord{134, 0, 1935},
+ dictWord{132, 0, 826},
+ dictWord{6, 0, 331},
+ dictWord{6, 0, 1605},
+ dictWord{8, 0, 623},
+ dictWord{11, 0, 139},
+ dictWord{139, 0, 171},
+ dictWord{135, 11, 1734},
+ dictWord{10, 11, 115},
+ dictWord{11, 11, 420},
+ dictWord{12, 11, 154},
+ dictWord{13, 11, 404},
+ dictWord{
+ 14,
+ 11,
+ 346,
+ },
+ dictWord{15, 11, 54},
+ dictWord{143, 11, 112},
+ dictWord{7, 0, 288},
+ dictWord{4, 10, 353},
+ dictWord{6, 10, 146},
+ dictWord{6, 10, 1789},
+ dictWord{
+ 7,
+ 10,
+ 990,
+ },
+ dictWord{7, 10, 1348},
+ dictWord{9, 10, 665},
+ dictWord{9, 10, 898},
+ dictWord{11, 10, 893},
+ dictWord{142, 10, 212},
+ dictWord{6, 0, 916},
+ dictWord{134, 0, 1592},
+ dictWord{7, 0, 1888},
+ dictWord{4, 10, 45},
+ dictWord{135, 10, 1257},
+ dictWord{5, 11, 1011},
+ dictWord{136, 11, 701},
+ dictWord{
+ 139,
+ 11,
+ 596,
+ },
+ dictWord{4, 11, 54},
+ dictWord{5, 11, 666},
+ dictWord{7, 11, 1039},
+ dictWord{7, 11, 1130},
+ dictWord{9, 11, 195},
+ dictWord{138, 11, 302},
+ dictWord{
+ 134,
+ 0,
+ 1471,
+ },
+ dictWord{134, 0, 1570},
+ dictWord{132, 0, 394},
+ dictWord{140, 10, 65},
+ dictWord{136, 10, 816},
+ dictWord{135, 0, 1931},
+ dictWord{7, 0, 574},
+ dictWord{135, 0, 1719},
+ dictWord{134, 11, 467},
+ dictWord{132, 0, 658},
+ dictWord{9, 0, 781},
+ dictWord{10, 0, 144},
+ dictWord{11, 0, 385},
+ dictWord{13, 0, 161},
+ dictWord{13, 0, 228},
+ dictWord{13, 0, 268},
+ dictWord{20, 0, 107},
+ dictWord{134, 11, 1669},
+ dictWord{136, 0, 374},
+ dictWord{135, 0, 735},
+ dictWord{4, 0, 344},
+ dictWord{6, 0, 498},
+ dictWord{139, 0, 323},
+ dictWord{7, 0, 586},
+ dictWord{7, 0, 1063},
+ dictWord{6, 10, 559},
+ dictWord{134, 10, 1691},
+ dictWord{137, 0, 155},
+ dictWord{133, 0, 906},
+ dictWord{7, 11, 122},
+ dictWord{9, 11, 259},
+ dictWord{10, 11, 84},
+ dictWord{11, 11, 470},
+ dictWord{12, 11, 541},
+ dictWord{
+ 141,
+ 11,
+ 379,
+ },
+ dictWord{134, 0, 1139},
+ dictWord{10, 0, 108},
+ dictWord{139, 0, 116},
+ dictWord{134, 10, 456},
+ dictWord{133, 10, 925},
+ dictWord{5, 11, 82},
+ dictWord{
+ 5,
+ 11,
+ 131,
+ },
+ dictWord{7, 11, 1755},
+ dictWord{8, 11, 31},
+ dictWord{9, 11, 168},
+ dictWord{9, 11, 764},
+ dictWord{139, 11, 869},
+ dictWord{134, 11, 605},
+ dictWord{
+ 5,
+ 11,
+ 278,
+ },
+ dictWord{137, 11, 68},
+ dictWord{4, 11, 163},
+ dictWord{5, 11, 201},
+ dictWord{5, 11, 307},
+ dictWord{5, 11, 310},
+ dictWord{6, 11, 335},
+ dictWord{
+ 7,
+ 11,
+ 284,
+ },
+ dictWord{136, 11, 165},
+ dictWord{135, 11, 1660},
+ dictWord{6, 11, 33},
+ dictWord{135, 11, 1244},
+ dictWord{4, 0, 616},
+ dictWord{136, 11, 483},
+ dictWord{8, 0, 857},
+ dictWord{8, 0, 902},
+ dictWord{8, 0, 910},
+ dictWord{10, 0, 879},
+ dictWord{12, 0, 726},
+ dictWord{4, 11, 199},
+ dictWord{139, 11, 34},
+ dictWord{136, 0, 692},
+ dictWord{6, 10, 193},
+ dictWord{7, 10, 240},
+ dictWord{7, 10, 1682},
+ dictWord{10, 10, 51},
+ dictWord{10, 10, 640},
+ dictWord{11, 10, 410},
+ dictWord{13, 10, 82},
+ dictWord{14, 10, 247},
+ dictWord{14, 10, 331},
+ dictWord{142, 10, 377},
+ dictWord{6, 0, 823},
+ dictWord{134, 0, 983},
+ dictWord{
+ 139,
+ 10,
+ 411,
+ },
+ dictWord{132, 0, 305},
+ dictWord{136, 10, 633},
+ dictWord{138, 11, 203},
+ dictWord{134, 0, 681},
+ dictWord{6, 11, 326},
+ dictWord{7, 11, 677},
+ dictWord{137, 11, 425},
+ dictWord{5, 0, 214},
+ dictWord{7, 0, 603},
+ dictWord{8, 0, 611},
+ dictWord{9, 0, 686},
+ dictWord{10, 0, 88},
+ dictWord{11, 0, 459},
+ dictWord{
+ 11,
+ 0,
+ 496,
+ },
+ dictWord{12, 0, 463},
+ dictWord{12, 0, 590},
+ dictWord{141, 0, 0},
+ dictWord{136, 0, 1004},
+ dictWord{142, 0, 23},
+ dictWord{134, 0, 1703},
+ dictWord{
+ 147,
+ 11,
+ 8,
+ },
+ dictWord{145, 11, 56},
+ dictWord{135, 0, 1443},
+ dictWord{4, 10, 237},
+ dictWord{135, 10, 514},
+ dictWord{6, 0, 714},
+ dictWord{145, 0, 19},
+ dictWord{
+ 5,
+ 11,
+ 358,
+ },
+ dictWord{7, 11, 473},
+ dictWord{7, 11, 1184},
+ dictWord{10, 11, 662},
+ dictWord{13, 11, 212},
+ dictWord{13, 11, 304},
+ dictWord{13, 11, 333},
+ dictWord{145, 11, 98},
+ dictWord{4, 0, 737},
+ dictWord{10, 0, 98},
+ dictWord{11, 0, 294},
+ dictWord{12, 0, 60},
+ dictWord{12, 0, 437},
+ dictWord{13, 0, 64},
+ dictWord{
+ 13,
+ 0,
+ 380,
+ },
+ dictWord{142, 0, 430},
+ dictWord{6, 10, 392},
+ dictWord{7, 10, 65},
+ dictWord{135, 10, 2019},
+ dictWord{6, 0, 1758},
+ dictWord{8, 0, 520},
+ dictWord{
+ 9,
+ 0,
+ 345,
+ },
+ dictWord{9, 0, 403},
+ dictWord{142, 0, 350},
+ dictWord{5, 0, 47},
+ dictWord{10, 0, 242},
+ dictWord{138, 0, 579},
+ dictWord{5, 0, 139},
+ dictWord{7, 0, 1168},
+ dictWord{138, 0, 539},
+ dictWord{134, 0, 1459},
+ dictWord{13, 0, 388},
+ dictWord{141, 11, 388},
+ dictWord{134, 0, 253},
+ dictWord{7, 10, 1260},
+ dictWord{
+ 135,
+ 10,
+ 1790,
+ },
+ dictWord{10, 0, 252},
+ dictWord{9, 10, 222},
+ dictWord{139, 10, 900},
+ dictWord{140, 0, 745},
+ dictWord{133, 11, 946},
+ dictWord{4, 0, 107},
+ dictWord{
+ 7,
+ 0,
+ 613,
+ },
+ dictWord{8, 0, 439},
+ dictWord{8, 0, 504},
+ dictWord{9, 0, 501},
+ dictWord{10, 0, 383},
+ dictWord{139, 0, 477},
+ dictWord{135, 11, 1485},
+ dictWord{
+ 132,
+ 0,
+ 871,
+ },
+ dictWord{7, 11, 411},
+ dictWord{7, 11, 590},
+ dictWord{8, 11, 631},
+ dictWord{9, 11, 323},
+ dictWord{10, 11, 355},
+ dictWord{11, 11, 491},
+ dictWord{
+ 12,
+ 11,
+ 143,
+ },
+ dictWord{12, 11, 402},
+ dictWord{13, 11, 73},
+ dictWord{14, 11, 408},
+ dictWord{15, 11, 107},
+ dictWord{146, 11, 71},
+ dictWord{132, 0, 229},
+ dictWord{132, 0, 903},
+ dictWord{140, 0, 71},
+ dictWord{133, 0, 549},
+ dictWord{4, 0, 47},
+ dictWord{6, 0, 373},
+ dictWord{7, 0, 452},
+ dictWord{7, 0, 543},
+ dictWord{
+ 7,
+ 0,
+ 1828,
+ },
+ dictWord{7, 0, 1856},
+ dictWord{9, 0, 6},
+ dictWord{11, 0, 257},
+ dictWord{139, 0, 391},
+ dictWord{7, 11, 1467},
+ dictWord{8, 11, 328},
+ dictWord{
+ 10,
+ 11,
+ 544,
+ },
+ dictWord{11, 11, 955},
+ dictWord{13, 11, 320},
+ dictWord{145, 11, 83},
+ dictWord{5, 0, 980},
+ dictWord{134, 0, 1754},
+ dictWord{136, 0, 865},
+ dictWord{
+ 5,
+ 0,
+ 705,
+ },
+ dictWord{137, 0, 606},
+ dictWord{7, 0, 161},
+ dictWord{8, 10, 201},
+ dictWord{136, 10, 605},
+ dictWord{143, 11, 35},
+ dictWord{5, 11, 835},
+ dictWord{
+ 6,
+ 11,
+ 483,
+ },
+ dictWord{140, 10, 224},
+ dictWord{7, 0, 536},
+ dictWord{7, 0, 1331},
+ dictWord{136, 0, 143},
+ dictWord{134, 0, 1388},
+ dictWord{5, 0, 724},
+ dictWord{
+ 10,
+ 0,
+ 305,
+ },
+ dictWord{11, 0, 151},
+ dictWord{12, 0, 33},
+ dictWord{12, 0, 121},
+ dictWord{12, 0, 381},
+ dictWord{17, 0, 3},
+ dictWord{17, 0, 27},
+ dictWord{17, 0, 78},
+ dictWord{18, 0, 18},
+ dictWord{19, 0, 54},
+ dictWord{149, 0, 5},
+ dictWord{4, 10, 523},
+ dictWord{133, 10, 638},
+ dictWord{5, 0, 19},
+ dictWord{134, 0, 533},
+ dictWord{
+ 5,
+ 0,
+ 395,
+ },
+ dictWord{5, 0, 951},
+ dictWord{134, 0, 1776},
+ dictWord{135, 0, 1908},
+ dictWord{132, 0, 846},
+ dictWord{10, 0, 74},
+ dictWord{11, 0, 663},
+ dictWord{
+ 12,
+ 0,
+ 210,
+ },
+ dictWord{13, 0, 166},
+ dictWord{13, 0, 310},
+ dictWord{14, 0, 373},
+ dictWord{18, 0, 95},
+ dictWord{19, 0, 43},
+ dictWord{6, 10, 242},
+ dictWord{7, 10, 227},
+ dictWord{7, 10, 1581},
+ dictWord{8, 10, 104},
+ dictWord{9, 10, 113},
+ dictWord{9, 10, 220},
+ dictWord{9, 10, 427},
+ dictWord{10, 10, 239},
+ dictWord{11, 10, 579},
+ dictWord{11, 10, 1023},
+ dictWord{13, 10, 4},
+ dictWord{13, 10, 204},
+ dictWord{13, 10, 316},
+ dictWord{148, 10, 86},
+ dictWord{9, 11, 716},
+ dictWord{11, 11, 108},
+ dictWord{13, 11, 123},
+ dictWord{14, 11, 252},
+ dictWord{19, 11, 38},
+ dictWord{21, 11, 3},
+ dictWord{151, 11, 11},
+ dictWord{8, 0, 372},
+ dictWord{9, 0, 122},
+ dictWord{138, 0, 175},
+ dictWord{132, 11, 677},
+ dictWord{7, 11, 1374},
+ dictWord{136, 11, 540},
+ dictWord{135, 10, 861},
+ dictWord{132, 0, 695},
+ dictWord{
+ 7,
+ 0,
+ 497,
+ },
+ dictWord{9, 0, 387},
+ dictWord{147, 0, 81},
+ dictWord{136, 0, 937},
+ dictWord{134, 0, 718},
+ dictWord{7, 0, 1328},
+ dictWord{136, 10, 494},
+ dictWord{
+ 132,
+ 11,
+ 331,
+ },
+ dictWord{6, 0, 1581},
+ dictWord{133, 11, 747},
+ dictWord{5, 0, 284},
+ dictWord{6, 0, 49},
+ dictWord{6, 0, 350},
+ dictWord{7, 0, 1},
+ dictWord{7, 0, 377},
+ dictWord{7, 0, 1693},
+ dictWord{8, 0, 18},
+ dictWord{8, 0, 678},
+ dictWord{9, 0, 161},
+ dictWord{9, 0, 585},
+ dictWord{9, 0, 671},
+ dictWord{9, 0, 839},
+ dictWord{11, 0, 912},
+ dictWord{141, 0, 427},
+ dictWord{7, 10, 1306},
+ dictWord{8, 10, 505},
+ dictWord{9, 10, 482},
+ dictWord{10, 10, 126},
+ dictWord{11, 10, 225},
+ dictWord{12, 10, 347},
+ dictWord{12, 10, 449},
+ dictWord{13, 10, 19},
+ dictWord{14, 10, 218},
+ dictWord{142, 10, 435},
+ dictWord{10, 10, 764},
+ dictWord{12, 10, 120},
+ dictWord{
+ 13,
+ 10,
+ 39,
+ },
+ dictWord{145, 10, 127},
+ dictWord{4, 0, 597},
+ dictWord{133, 10, 268},
+ dictWord{134, 0, 1094},
+ dictWord{4, 0, 1008},
+ dictWord{134, 0, 1973},
+ dictWord{132, 0, 811},
+ dictWord{139, 0, 908},
+ dictWord{135, 0, 1471},
+ dictWord{133, 11, 326},
+ dictWord{4, 10, 384},
+ dictWord{135, 10, 1022},
+ dictWord{
+ 7,
+ 0,
+ 1935,
+ },
+ dictWord{8, 0, 324},
+ dictWord{12, 0, 42},
+ dictWord{4, 11, 691},
+ dictWord{7, 11, 1935},
+ dictWord{8, 11, 324},
+ dictWord{9, 11, 35},
+ dictWord{10, 11, 680},
+ dictWord{11, 11, 364},
+ dictWord{12, 11, 42},
+ dictWord{13, 11, 357},
+ dictWord{146, 11, 16},
+ dictWord{135, 0, 2014},
+ dictWord{7, 0, 2007},
+ dictWord{
+ 9,
+ 0,
+ 101,
+ },
+ dictWord{9, 0, 450},
+ dictWord{10, 0, 66},
+ dictWord{10, 0, 842},
+ dictWord{11, 0, 536},
+ dictWord{12, 0, 587},
+ dictWord{6, 11, 32},
+ dictWord{7, 11, 385},
+ dictWord{7, 11, 757},
+ dictWord{7, 11, 1916},
+ dictWord{8, 11, 37},
+ dictWord{8, 11, 94},
+ dictWord{8, 11, 711},
+ dictWord{9, 11, 541},
+ dictWord{10, 11, 162},
+ dictWord{
+ 10,
+ 11,
+ 795,
+ },
+ dictWord{11, 11, 989},
+ dictWord{11, 11, 1010},
+ dictWord{12, 11, 14},
+ dictWord{142, 11, 308},
+ dictWord{139, 0, 586},
+ dictWord{
+ 135,
+ 10,
+ 1703,
+ },
+ dictWord{7, 0, 1077},
+ dictWord{11, 0, 28},
+ dictWord{9, 10, 159},
+ dictWord{140, 10, 603},
+ dictWord{6, 0, 1221},
+ dictWord{136, 10, 583},
+ dictWord{
+ 6,
+ 11,
+ 152,
+ },
+ dictWord{6, 11, 349},
+ dictWord{6, 11, 1682},
+ dictWord{7, 11, 1252},
+ dictWord{8, 11, 112},
+ dictWord{9, 11, 435},
+ dictWord{9, 11, 668},
+ dictWord{
+ 10,
+ 11,
+ 290,
+ },
+ dictWord{10, 11, 319},
+ dictWord{10, 11, 815},
+ dictWord{11, 11, 180},
+ dictWord{11, 11, 837},
+ dictWord{12, 11, 240},
+ dictWord{13, 11, 152},
+ dictWord{13, 11, 219},
+ dictWord{142, 11, 158},
+ dictWord{139, 0, 62},
+ dictWord{132, 10, 515},
+ dictWord{8, 10, 632},
+ dictWord{8, 10, 697},
+ dictWord{
+ 137,
+ 10,
+ 854,
+ },
+ dictWord{134, 0, 1766},
+ dictWord{132, 11, 581},
+ dictWord{6, 11, 126},
+ dictWord{7, 11, 573},
+ dictWord{8, 11, 397},
+ dictWord{142, 11, 44},
+ dictWord{
+ 150,
+ 0,
+ 28,
+ },
+ dictWord{11, 0, 670},
+ dictWord{22, 0, 25},
+ dictWord{4, 10, 136},
+ dictWord{133, 10, 551},
+ dictWord{6, 0, 1665},
+ dictWord{7, 0, 256},
+ dictWord{
+ 7,
+ 0,
+ 1388,
+ },
+ dictWord{138, 0, 499},
+ dictWord{4, 0, 22},
+ dictWord{5, 0, 10},
+ dictWord{7, 0, 1576},
+ dictWord{136, 0, 97},
+ dictWord{134, 10, 1782},
+ dictWord{5, 0, 481},
+ dictWord{7, 10, 1287},
+ dictWord{9, 10, 44},
+ dictWord{10, 10, 552},
+ dictWord{10, 10, 642},
+ dictWord{11, 10, 839},
+ dictWord{12, 10, 274},
+ dictWord{
+ 12,
+ 10,
+ 275,
+ },
+ dictWord{12, 10, 372},
+ dictWord{13, 10, 91},
+ dictWord{142, 10, 125},
+ dictWord{133, 11, 926},
+ dictWord{7, 11, 1232},
+ dictWord{137, 11, 531},
+ dictWord{6, 0, 134},
+ dictWord{7, 0, 437},
+ dictWord{7, 0, 1824},
+ dictWord{9, 0, 37},
+ dictWord{14, 0, 285},
+ dictWord{142, 0, 371},
+ dictWord{7, 0, 486},
+ dictWord{8, 0, 155},
+ dictWord{11, 0, 93},
+ dictWord{140, 0, 164},
+ dictWord{6, 0, 1391},
+ dictWord{134, 0, 1442},
+ dictWord{133, 11, 670},
+ dictWord{133, 0, 591},
+ dictWord{
+ 6,
+ 10,
+ 147,
+ },
+ dictWord{7, 10, 886},
+ dictWord{7, 11, 1957},
+ dictWord{9, 10, 753},
+ dictWord{138, 10, 268},
+ dictWord{5, 0, 380},
+ dictWord{5, 0, 650},
+ dictWord{
+ 7,
+ 0,
+ 1173,
+ },
+ dictWord{136, 0, 310},
+ dictWord{4, 0, 364},
+ dictWord{7, 0, 1156},
+ dictWord{7, 0, 1187},
+ dictWord{137, 0, 409},
+ dictWord{135, 11, 1621},
+ dictWord{
+ 134,
+ 0,
+ 482,
+ },
+ dictWord{133, 11, 506},
+ dictWord{4, 0, 781},
+ dictWord{6, 0, 487},
+ dictWord{7, 0, 926},
+ dictWord{8, 0, 263},
+ dictWord{139, 0, 500},
+ dictWord{
+ 138,
+ 10,
+ 137,
+ },
+ dictWord{135, 11, 242},
+ dictWord{139, 11, 96},
+ dictWord{133, 10, 414},
+ dictWord{135, 10, 1762},
+ dictWord{134, 0, 804},
+ dictWord{5, 11, 834},
+ dictWord{7, 11, 1202},
+ dictWord{8, 11, 14},
+ dictWord{9, 11, 481},
+ dictWord{137, 11, 880},
+ dictWord{134, 10, 599},
+ dictWord{4, 0, 94},
+ dictWord{135, 0, 1265},
+ dictWord{4, 0, 415},
+ dictWord{132, 0, 417},
+ dictWord{5, 0, 348},
+ dictWord{6, 0, 522},
+ dictWord{6, 10, 1749},
+ dictWord{7, 11, 1526},
+ dictWord{138, 11, 465},
+ dictWord{134, 10, 1627},
+ dictWord{132, 0, 1012},
+ dictWord{132, 10, 488},
+ dictWord{4, 11, 357},
+ dictWord{6, 11, 172},
+ dictWord{7, 11, 143},
+ dictWord{
+ 137,
+ 11,
+ 413,
+ },
+ dictWord{4, 10, 83},
+ dictWord{4, 11, 590},
+ dictWord{146, 11, 76},
+ dictWord{140, 10, 676},
+ dictWord{7, 11, 287},
+ dictWord{8, 11, 355},
+ dictWord{
+ 9,
+ 11,
+ 293,
+ },
+ dictWord{137, 11, 743},
+ dictWord{134, 10, 278},
+ dictWord{6, 0, 1803},
+ dictWord{18, 0, 165},
+ dictWord{24, 0, 21},
+ dictWord{5, 11, 169},
+ dictWord{
+ 7,
+ 11,
+ 333,
+ },
+ dictWord{136, 11, 45},
+ dictWord{12, 10, 97},
+ dictWord{140, 11, 97},
+ dictWord{4, 0, 408},
+ dictWord{4, 0, 741},
+ dictWord{135, 0, 500},
+ dictWord{
+ 132,
+ 11,
+ 198,
+ },
+ dictWord{7, 10, 388},
+ dictWord{7, 10, 644},
+ dictWord{139, 10, 781},
+ dictWord{4, 11, 24},
+ dictWord{5, 11, 140},
+ dictWord{5, 11, 185},
+ dictWord{
+ 7,
+ 11,
+ 1500,
+ },
+ dictWord{11, 11, 565},
+ dictWord{139, 11, 838},
+ dictWord{6, 0, 1321},
+ dictWord{9, 0, 257},
+ dictWord{7, 10, 229},
+ dictWord{8, 10, 59},
+ dictWord{
+ 9,
+ 10,
+ 190,
+ },
+ dictWord{10, 10, 378},
+ dictWord{140, 10, 191},
+ dictWord{4, 11, 334},
+ dictWord{133, 11, 593},
+ dictWord{135, 11, 1885},
+ dictWord{134, 0, 1138},
+ dictWord{4, 0, 249},
+ dictWord{6, 0, 73},
+ dictWord{135, 0, 177},
+ dictWord{133, 0, 576},
+ dictWord{142, 0, 231},
+ dictWord{137, 0, 288},
+ dictWord{132, 10, 660},
+ dictWord{7, 10, 1035},
+ dictWord{138, 10, 737},
+ dictWord{135, 0, 1487},
+ dictWord{6, 0, 989},
+ dictWord{9, 0, 433},
+ dictWord{7, 10, 690},
+ dictWord{9, 10, 587},
+ dictWord{140, 10, 521},
+ dictWord{7, 0, 1264},
+ dictWord{7, 0, 1678},
+ dictWord{11, 0, 945},
+ dictWord{12, 0, 341},
+ dictWord{12, 0, 471},
+ dictWord{140, 0, 569},
+ dictWord{132, 11, 709},
+ dictWord{133, 11, 897},
+ dictWord{5, 11, 224},
+ dictWord{13, 11, 174},
+ dictWord{146, 11, 52},
+ dictWord{135, 11, 1840},
+ dictWord{
+ 134,
+ 10,
+ 1744,
+ },
+ dictWord{12, 0, 87},
+ dictWord{16, 0, 74},
+ dictWord{4, 10, 733},
+ dictWord{9, 10, 194},
+ dictWord{10, 10, 92},
+ dictWord{11, 10, 198},
+ dictWord{
+ 12,
+ 10,
+ 84,
+ },
+ dictWord{141, 10, 128},
+ dictWord{140, 0, 779},
+ dictWord{135, 0, 538},
+ dictWord{4, 11, 608},
+ dictWord{133, 11, 497},
+ dictWord{133, 0, 413},
+ dictWord{7, 11, 1375},
+ dictWord{7, 11, 1466},
+ dictWord{138, 11, 331},
+ dictWord{136, 0, 495},
+ dictWord{6, 11, 540},
+ dictWord{136, 11, 136},
+ dictWord{7, 0, 54},
+ dictWord{8, 0, 312},
+ dictWord{10, 0, 191},
+ dictWord{10, 0, 614},
+ dictWord{140, 0, 567},
+ dictWord{6, 0, 468},
+ dictWord{7, 0, 567},
+ dictWord{7, 0, 1478},
+ dictWord{
+ 8,
+ 0,
+ 530,
+ },
+ dictWord{14, 0, 290},
+ dictWord{133, 11, 999},
+ dictWord{4, 11, 299},
+ dictWord{7, 10, 306},
+ dictWord{135, 11, 1004},
+ dictWord{142, 11, 296},
+ dictWord{134, 0, 1484},
+ dictWord{133, 10, 979},
+ dictWord{6, 0, 609},
+ dictWord{9, 0, 815},
+ dictWord{12, 11, 137},
+ dictWord{14, 11, 9},
+ dictWord{14, 11, 24},
+ dictWord{142, 11, 64},
+ dictWord{133, 11, 456},
+ dictWord{6, 0, 484},
+ dictWord{135, 0, 822},
+ dictWord{133, 10, 178},
+ dictWord{136, 11, 180},
+ dictWord{
+ 132,
+ 11,
+ 755,
+ },
+ dictWord{137, 0, 900},
+ dictWord{135, 0, 1335},
+ dictWord{6, 0, 1724},
+ dictWord{135, 0, 2022},
+ dictWord{135, 11, 1139},
+ dictWord{5, 0, 640},
+ dictWord{132, 10, 390},
+ dictWord{6, 0, 1831},
+ dictWord{138, 11, 633},
+ dictWord{135, 11, 566},
+ dictWord{4, 11, 890},
+ dictWord{5, 11, 805},
+ dictWord{5, 11, 819},
+ dictWord{5, 11, 961},
+ dictWord{6, 11, 396},
+ dictWord{6, 11, 1631},
+ dictWord{6, 11, 1678},
+ dictWord{7, 11, 1967},
+ dictWord{7, 11, 2041},
+ dictWord{
+ 9,
+ 11,
+ 630,
+ },
+ dictWord{11, 11, 8},
+ dictWord{11, 11, 1019},
+ dictWord{12, 11, 176},
+ dictWord{13, 11, 225},
+ dictWord{14, 11, 292},
+ dictWord{149, 11, 24},
+ dictWord{
+ 132,
+ 0,
+ 474,
+ },
+ dictWord{134, 0, 1103},
+ dictWord{135, 0, 1504},
+ dictWord{134, 0, 1576},
+ dictWord{6, 0, 961},
+ dictWord{6, 0, 1034},
+ dictWord{140, 0, 655},
+ dictWord{11, 11, 514},
+ dictWord{149, 11, 20},
+ dictWord{5, 0, 305},
+ dictWord{135, 11, 1815},
+ dictWord{7, 11, 1505},
+ dictWord{10, 11, 190},
+ dictWord{
+ 10,
+ 11,
+ 634,
+ },
+ dictWord{11, 11, 792},
+ dictWord{12, 11, 358},
+ dictWord{140, 11, 447},
+ dictWord{5, 11, 0},
+ dictWord{6, 11, 536},
+ dictWord{7, 11, 604},
+ dictWord{
+ 13,
+ 11,
+ 445,
+ },
+ dictWord{145, 11, 126},
+ dictWord{7, 0, 1236},
+ dictWord{133, 10, 105},
+ dictWord{4, 0, 480},
+ dictWord{6, 0, 217},
+ dictWord{6, 0, 302},
+ dictWord{
+ 6,
+ 0,
+ 1642,
+ },
+ dictWord{7, 0, 130},
+ dictWord{7, 0, 837},
+ dictWord{7, 0, 1321},
+ dictWord{7, 0, 1547},
+ dictWord{7, 0, 1657},
+ dictWord{8, 0, 429},
+ dictWord{9, 0, 228},
+ dictWord{13, 0, 289},
+ dictWord{13, 0, 343},
+ dictWord{19, 0, 101},
+ dictWord{6, 11, 232},
+ dictWord{6, 11, 412},
+ dictWord{7, 11, 1074},
+ dictWord{8, 11, 9},
+ dictWord{
+ 8,
+ 11,
+ 157,
+ },
+ dictWord{8, 11, 786},
+ dictWord{9, 11, 196},
+ dictWord{9, 11, 352},
+ dictWord{9, 11, 457},
+ dictWord{10, 11, 337},
+ dictWord{11, 11, 232},
+ dictWord{
+ 11,
+ 11,
+ 877,
+ },
+ dictWord{12, 11, 480},
+ dictWord{140, 11, 546},
+ dictWord{5, 10, 438},
+ dictWord{7, 11, 958},
+ dictWord{9, 10, 694},
+ dictWord{12, 10, 627},
+ dictWord{
+ 13,
+ 11,
+ 38,
+ },
+ dictWord{141, 10, 210},
+ dictWord{4, 11, 382},
+ dictWord{136, 11, 579},
+ dictWord{7, 0, 278},
+ dictWord{10, 0, 739},
+ dictWord{11, 0, 708},
+ dictWord{
+ 141,
+ 0,
+ 348,
+ },
+ dictWord{4, 11, 212},
+ dictWord{135, 11, 1206},
+ dictWord{135, 11, 1898},
+ dictWord{6, 0, 708},
+ dictWord{6, 0, 1344},
+ dictWord{152, 10, 11},
+ dictWord{137, 11, 768},
+ dictWord{134, 0, 1840},
+ dictWord{140, 0, 233},
+ dictWord{8, 10, 25},
+ dictWord{138, 10, 826},
+ dictWord{6, 0, 2017},
+ dictWord{
+ 133,
+ 11,
+ 655,
+ },
+ dictWord{6, 0, 1488},
+ dictWord{139, 11, 290},
+ dictWord{132, 10, 308},
+ dictWord{134, 0, 1590},
+ dictWord{134, 0, 1800},
+ dictWord{134, 0, 1259},
+ dictWord{16, 0, 28},
+ dictWord{6, 11, 231},
+ dictWord{7, 11, 95},
+ dictWord{136, 11, 423},
+ dictWord{133, 11, 300},
+ dictWord{135, 10, 150},
+ dictWord{
+ 136,
+ 10,
+ 649,
+ },
+ dictWord{7, 11, 1874},
+ dictWord{137, 11, 641},
+ dictWord{6, 11, 237},
+ dictWord{7, 11, 611},
+ dictWord{8, 11, 100},
+ dictWord{9, 11, 416},
+ dictWord{
+ 11,
+ 11,
+ 335,
+ },
+ dictWord{12, 11, 173},
+ dictWord{146, 11, 101},
+ dictWord{137, 0, 45},
+ dictWord{134, 10, 521},
+ dictWord{17, 0, 36},
+ dictWord{14, 11, 26},
+ dictWord{
+ 146,
+ 11,
+ 150,
+ },
+ dictWord{7, 0, 1442},
+ dictWord{14, 0, 22},
+ dictWord{5, 10, 339},
+ dictWord{15, 10, 41},
+ dictWord{15, 10, 166},
+ dictWord{147, 10, 66},
+ dictWord{
+ 8,
+ 0,
+ 378,
+ },
+ dictWord{6, 11, 581},
+ dictWord{135, 11, 1119},
+ dictWord{134, 0, 1507},
+ dictWord{147, 11, 117},
+ dictWord{139, 0, 39},
+ dictWord{134, 0, 1054},
+ dictWord{6, 0, 363},
+ dictWord{7, 0, 1955},
+ dictWord{136, 0, 725},
+ dictWord{134, 0, 2036},
+ dictWord{133, 11, 199},
+ dictWord{6, 0, 1871},
+ dictWord{9, 0, 935},
+ dictWord{9, 0, 961},
+ dictWord{9, 0, 1004},
+ dictWord{9, 0, 1016},
+ dictWord{12, 0, 805},
+ dictWord{12, 0, 852},
+ dictWord{12, 0, 853},
+ dictWord{12, 0, 869},
+ dictWord{
+ 12,
+ 0,
+ 882,
+ },
+ dictWord{12, 0, 896},
+ dictWord{12, 0, 906},
+ dictWord{12, 0, 917},
+ dictWord{12, 0, 940},
+ dictWord{15, 0, 170},
+ dictWord{15, 0, 176},
+ dictWord{
+ 15,
+ 0,
+ 188,
+ },
+ dictWord{15, 0, 201},
+ dictWord{15, 0, 205},
+ dictWord{15, 0, 212},
+ dictWord{15, 0, 234},
+ dictWord{15, 0, 244},
+ dictWord{18, 0, 181},
+ dictWord{18, 0, 193},
+ dictWord{18, 0, 196},
+ dictWord{18, 0, 201},
+ dictWord{18, 0, 202},
+ dictWord{18, 0, 210},
+ dictWord{18, 0, 217},
+ dictWord{18, 0, 235},
+ dictWord{18, 0, 236},
+ dictWord{18, 0, 237},
+ dictWord{21, 0, 54},
+ dictWord{21, 0, 55},
+ dictWord{21, 0, 58},
+ dictWord{21, 0, 59},
+ dictWord{152, 0, 22},
+ dictWord{134, 10, 1628},
+ dictWord{
+ 137,
+ 0,
+ 805,
+ },
+ dictWord{5, 0, 813},
+ dictWord{135, 0, 2046},
+ dictWord{142, 11, 42},
+ dictWord{5, 0, 712},
+ dictWord{6, 0, 1240},
+ dictWord{11, 0, 17},
+ dictWord{
+ 13,
+ 0,
+ 321,
+ },
+ dictWord{144, 0, 67},
+ dictWord{132, 0, 617},
+ dictWord{135, 10, 829},
+ dictWord{6, 0, 320},
+ dictWord{7, 0, 781},
+ dictWord{7, 0, 1921},
+ dictWord{9, 0, 55},
+ dictWord{10, 0, 186},
+ dictWord{10, 0, 273},
+ dictWord{10, 0, 664},
+ dictWord{10, 0, 801},
+ dictWord{11, 0, 996},
+ dictWord{11, 0, 997},
+ dictWord{13, 0, 157},
+ dictWord{142, 0, 170},
+ dictWord{136, 0, 271},
+ dictWord{5, 10, 486},
+ dictWord{135, 10, 1349},
+ dictWord{18, 11, 91},
+ dictWord{147, 11, 70},
+ dictWord{10, 0, 445},
+ dictWord{7, 10, 1635},
+ dictWord{8, 10, 17},
+ dictWord{138, 10, 295},
+ dictWord{136, 11, 404},
+ dictWord{7, 0, 103},
+ dictWord{7, 0, 863},
+ dictWord{11, 0, 184},
+ dictWord{145, 0, 62},
+ dictWord{138, 10, 558},
+ dictWord{137, 0, 659},
+ dictWord{6, 11, 312},
+ dictWord{6, 11, 1715},
+ dictWord{10, 11, 584},
+ dictWord{
+ 11,
+ 11,
+ 546,
+ },
+ dictWord{11, 11, 692},
+ dictWord{12, 11, 259},
+ dictWord{12, 11, 295},
+ dictWord{13, 11, 46},
+ dictWord{141, 11, 154},
+ dictWord{134, 0, 676},
+ dictWord{132, 11, 588},
+ dictWord{4, 11, 231},
+ dictWord{5, 11, 61},
+ dictWord{6, 11, 104},
+ dictWord{7, 11, 729},
+ dictWord{7, 11, 964},
+ dictWord{7, 11, 1658},
+ dictWord{140, 11, 414},
+ dictWord{6, 11, 263},
+ dictWord{138, 11, 757},
+ dictWord{11, 0, 337},
+ dictWord{142, 0, 303},
+ dictWord{135, 11, 1363},
+ dictWord{
+ 132,
+ 11,
+ 320,
+ },
+ dictWord{140, 0, 506},
+ dictWord{134, 10, 447},
+ dictWord{5, 0, 77},
+ dictWord{7, 0, 1455},
+ dictWord{10, 0, 843},
+ dictWord{147, 0, 73},
+ dictWord{
+ 7,
+ 10,
+ 577,
+ },
+ dictWord{7, 10, 1432},
+ dictWord{9, 10, 475},
+ dictWord{9, 10, 505},
+ dictWord{9, 10, 526},
+ dictWord{9, 10, 609},
+ dictWord{9, 10, 689},
+ dictWord{
+ 9,
+ 10,
+ 726,
+ },
+ dictWord{9, 10, 735},
+ dictWord{9, 10, 738},
+ dictWord{10, 10, 556},
+ dictWord{10, 10, 674},
+ dictWord{10, 10, 684},
+ dictWord{11, 10, 89},
+ dictWord{
+ 11,
+ 10,
+ 202,
+ },
+ dictWord{11, 10, 272},
+ dictWord{11, 10, 380},
+ dictWord{11, 10, 415},
+ dictWord{11, 10, 505},
+ dictWord{11, 10, 537},
+ dictWord{11, 10, 550},
+ dictWord{11, 10, 562},
+ dictWord{11, 10, 640},
+ dictWord{11, 10, 667},
+ dictWord{11, 10, 688},
+ dictWord{11, 10, 847},
+ dictWord{11, 10, 927},
+ dictWord{
+ 11,
+ 10,
+ 930,
+ },
+ dictWord{11, 10, 940},
+ dictWord{12, 10, 144},
+ dictWord{12, 10, 325},
+ dictWord{12, 10, 329},
+ dictWord{12, 10, 389},
+ dictWord{12, 10, 403},
+ dictWord{
+ 12,
+ 10,
+ 451,
+ },
+ dictWord{12, 10, 515},
+ dictWord{12, 10, 604},
+ dictWord{12, 10, 616},
+ dictWord{12, 10, 626},
+ dictWord{13, 10, 66},
+ dictWord{13, 10, 131},
+ dictWord{13, 10, 167},
+ dictWord{13, 10, 236},
+ dictWord{13, 10, 368},
+ dictWord{13, 10, 411},
+ dictWord{13, 10, 434},
+ dictWord{13, 10, 453},
+ dictWord{
+ 13,
+ 10,
+ 461,
+ },
+ dictWord{13, 10, 474},
+ dictWord{14, 10, 59},
+ dictWord{14, 10, 60},
+ dictWord{14, 10, 139},
+ dictWord{14, 10, 152},
+ dictWord{14, 10, 276},
+ dictWord{
+ 14,
+ 10,
+ 353,
+ },
+ dictWord{14, 10, 402},
+ dictWord{15, 10, 28},
+ dictWord{15, 10, 81},
+ dictWord{15, 10, 123},
+ dictWord{15, 10, 152},
+ dictWord{18, 10, 136},
+ dictWord{148, 10, 88},
+ dictWord{132, 0, 458},
+ dictWord{135, 0, 1420},
+ dictWord{6, 0, 109},
+ dictWord{10, 0, 382},
+ dictWord{4, 11, 405},
+ dictWord{4, 10, 609},
+ dictWord{7, 10, 756},
+ dictWord{7, 11, 817},
+ dictWord{9, 10, 544},
+ dictWord{11, 10, 413},
+ dictWord{14, 11, 58},
+ dictWord{14, 10, 307},
+ dictWord{16, 10, 25},
+ dictWord{17, 11, 37},
+ dictWord{146, 11, 124},
+ dictWord{6, 0, 330},
+ dictWord{7, 0, 1084},
+ dictWord{11, 0, 142},
+ dictWord{133, 11, 974},
+ dictWord{4, 10, 930},
+ dictWord{133, 10, 947},
+ dictWord{5, 10, 939},
+ dictWord{142, 11, 394},
+ dictWord{16, 0, 91},
+ dictWord{145, 0, 87},
+ dictWord{5, 11, 235},
+ dictWord{5, 10, 962},
+ dictWord{7, 11, 1239},
+ dictWord{11, 11, 131},
+ dictWord{140, 11, 370},
+ dictWord{11, 0, 492},
+ dictWord{5, 10, 651},
+ dictWord{8, 10, 170},
+ dictWord{9, 10, 61},
+ dictWord{9, 10, 63},
+ dictWord{10, 10, 23},
+ dictWord{10, 10, 37},
+ dictWord{10, 10, 834},
+ dictWord{11, 10, 4},
+ dictWord{11, 10, 281},
+ dictWord{11, 10, 503},
+ dictWord{
+ 11,
+ 10,
+ 677,
+ },
+ dictWord{12, 10, 96},
+ dictWord{12, 10, 130},
+ dictWord{12, 10, 244},
+ dictWord{14, 10, 5},
+ dictWord{14, 10, 40},
+ dictWord{14, 10, 162},
+ dictWord{
+ 14,
+ 10,
+ 202,
+ },
+ dictWord{146, 10, 133},
+ dictWord{4, 10, 406},
+ dictWord{5, 10, 579},
+ dictWord{12, 10, 492},
+ dictWord{150, 10, 15},
+ dictWord{9, 11, 137},
+ dictWord{138, 11, 221},
+ dictWord{134, 0, 1239},
+ dictWord{11, 0, 211},
+ dictWord{140, 0, 145},
+ dictWord{7, 11, 390},
+ dictWord{138, 11, 140},
+ dictWord{
+ 135,
+ 11,
+ 1418,
+ },
+ dictWord{135, 11, 1144},
+ dictWord{134, 0, 1049},
+ dictWord{7, 0, 321},
+ dictWord{6, 10, 17},
+ dictWord{7, 10, 1001},
+ dictWord{7, 10, 1982},
+ dictWord{
+ 9,
+ 10,
+ 886,
+ },
+ dictWord{10, 10, 489},
+ dictWord{10, 10, 800},
+ dictWord{11, 10, 782},
+ dictWord{12, 10, 320},
+ dictWord{13, 10, 467},
+ dictWord{14, 10, 145},
+ dictWord{14, 10, 387},
+ dictWord{143, 10, 119},
+ dictWord{145, 10, 17},
+ dictWord{5, 11, 407},
+ dictWord{11, 11, 489},
+ dictWord{19, 11, 37},
+ dictWord{20, 11, 73},
+ dictWord{150, 11, 38},
+ dictWord{133, 10, 458},
+ dictWord{135, 0, 1985},
+ dictWord{7, 10, 1983},
+ dictWord{8, 10, 0},
+ dictWord{8, 10, 171},
+ dictWord{
+ 9,
+ 10,
+ 120,
+ },
+ dictWord{9, 10, 732},
+ dictWord{10, 10, 473},
+ dictWord{11, 10, 656},
+ dictWord{11, 10, 998},
+ dictWord{18, 10, 0},
+ dictWord{18, 10, 2},
+ dictWord{
+ 147,
+ 10,
+ 21,
+ },
+ dictWord{5, 11, 325},
+ dictWord{7, 11, 1483},
+ dictWord{8, 11, 5},
+ dictWord{8, 11, 227},
+ dictWord{9, 11, 105},
+ dictWord{10, 11, 585},
+ dictWord{
+ 140,
+ 11,
+ 614,
+ },
+ dictWord{136, 0, 122},
+ dictWord{132, 0, 234},
+ dictWord{135, 11, 1196},
+ dictWord{6, 0, 976},
+ dictWord{6, 0, 1098},
+ dictWord{134, 0, 1441},
+ dictWord{
+ 7,
+ 0,
+ 253,
+ },
+ dictWord{136, 0, 549},
+ dictWord{6, 11, 621},
+ dictWord{13, 11, 504},
+ dictWord{144, 11, 19},
+ dictWord{132, 10, 519},
+ dictWord{5, 0, 430},
+ dictWord{
+ 5,
+ 0,
+ 932,
+ },
+ dictWord{6, 0, 131},
+ dictWord{7, 0, 417},
+ dictWord{9, 0, 522},
+ dictWord{11, 0, 314},
+ dictWord{141, 0, 390},
+ dictWord{14, 0, 149},
+ dictWord{14, 0, 399},
+ dictWord{143, 0, 57},
+ dictWord{5, 10, 907},
+ dictWord{6, 10, 31},
+ dictWord{6, 11, 218},
+ dictWord{7, 10, 491},
+ dictWord{7, 10, 530},
+ dictWord{8, 10, 592},
+ dictWord{11, 10, 53},
+ dictWord{11, 10, 779},
+ dictWord{12, 10, 167},
+ dictWord{12, 10, 411},
+ dictWord{14, 10, 14},
+ dictWord{14, 10, 136},
+ dictWord{15, 10, 72},
+ dictWord{16, 10, 17},
+ dictWord{144, 10, 72},
+ dictWord{140, 11, 330},
+ dictWord{7, 11, 454},
+ dictWord{7, 11, 782},
+ dictWord{136, 11, 768},
+ dictWord{
+ 132,
+ 0,
+ 507,
+ },
+ dictWord{10, 11, 676},
+ dictWord{140, 11, 462},
+ dictWord{6, 0, 630},
+ dictWord{9, 0, 811},
+ dictWord{4, 10, 208},
+ dictWord{5, 10, 106},
+ dictWord{
+ 6,
+ 10,
+ 531,
+ },
+ dictWord{8, 10, 408},
+ dictWord{9, 10, 188},
+ dictWord{138, 10, 572},
+ dictWord{4, 0, 343},
+ dictWord{5, 0, 511},
+ dictWord{134, 10, 1693},
+ dictWord{
+ 134,
+ 11,
+ 164,
+ },
+ dictWord{132, 0, 448},
+ dictWord{7, 0, 455},
+ dictWord{138, 0, 591},
+ dictWord{135, 0, 1381},
+ dictWord{12, 10, 441},
+ dictWord{150, 11, 50},
+ dictWord{9, 10, 449},
+ dictWord{10, 10, 192},
+ dictWord{138, 10, 740},
+ dictWord{6, 0, 575},
+ dictWord{132, 10, 241},
+ dictWord{134, 0, 1175},
+ dictWord{
+ 134,
+ 0,
+ 653,
+ },
+ dictWord{134, 0, 1761},
+ dictWord{134, 0, 1198},
+ dictWord{132, 10, 259},
+ dictWord{6, 11, 343},
+ dictWord{7, 11, 195},
+ dictWord{9, 11, 226},
+ dictWord{
+ 10,
+ 11,
+ 197,
+ },
+ dictWord{10, 11, 575},
+ dictWord{11, 11, 502},
+ dictWord{139, 11, 899},
+ dictWord{7, 0, 1127},
+ dictWord{7, 0, 1572},
+ dictWord{10, 0, 297},
+ dictWord{10, 0, 422},
+ dictWord{11, 0, 764},
+ dictWord{11, 0, 810},
+ dictWord{12, 0, 264},
+ dictWord{13, 0, 102},
+ dictWord{13, 0, 300},
+ dictWord{13, 0, 484},
+ dictWord{
+ 14,
+ 0,
+ 147,
+ },
+ dictWord{14, 0, 229},
+ dictWord{17, 0, 71},
+ dictWord{18, 0, 118},
+ dictWord{147, 0, 120},
+ dictWord{135, 11, 666},
+ dictWord{132, 0, 678},
+ dictWord{
+ 4,
+ 10,
+ 173,
+ },
+ dictWord{5, 10, 312},
+ dictWord{5, 10, 512},
+ dictWord{135, 10, 1285},
+ dictWord{7, 10, 1603},
+ dictWord{7, 10, 1691},
+ dictWord{9, 10, 464},
+ dictWord{11, 10, 195},
+ dictWord{12, 10, 279},
+ dictWord{12, 10, 448},
+ dictWord{14, 10, 11},
+ dictWord{147, 10, 102},
+ dictWord{16, 0, 99},
+ dictWord{146, 0, 164},
+ dictWord{7, 11, 1125},
+ dictWord{9, 11, 143},
+ dictWord{11, 11, 61},
+ dictWord{14, 11, 405},
+ dictWord{150, 11, 21},
+ dictWord{137, 11, 260},
+ dictWord{
+ 4,
+ 10,
+ 452,
+ },
+ dictWord{5, 10, 583},
+ dictWord{5, 10, 817},
+ dictWord{6, 10, 433},
+ dictWord{7, 10, 593},
+ dictWord{7, 10, 720},
+ dictWord{7, 10, 1378},
+ dictWord{
+ 8,
+ 10,
+ 161,
+ },
+ dictWord{9, 10, 284},
+ dictWord{10, 10, 313},
+ dictWord{139, 10, 886},
+ dictWord{132, 10, 547},
+ dictWord{136, 10, 722},
+ dictWord{14, 0, 35},
+ dictWord{142, 0, 191},
+ dictWord{141, 0, 45},
+ dictWord{138, 0, 121},
+ dictWord{132, 0, 125},
+ dictWord{134, 0, 1622},
+ dictWord{133, 11, 959},
+ dictWord{
+ 8,
+ 10,
+ 420,
+ },
+ dictWord{139, 10, 193},
+ dictWord{132, 0, 721},
+ dictWord{135, 10, 409},
+ dictWord{136, 0, 145},
+ dictWord{7, 0, 792},
+ dictWord{8, 0, 147},
+ dictWord{
+ 10,
+ 0,
+ 821,
+ },
+ dictWord{11, 0, 970},
+ dictWord{11, 0, 1021},
+ dictWord{136, 11, 173},
+ dictWord{134, 11, 266},
+ dictWord{132, 0, 715},
+ dictWord{7, 0, 1999},
+ dictWord{138, 10, 308},
+ dictWord{133, 0, 531},
+ dictWord{5, 0, 168},
+ dictWord{5, 0, 930},
+ dictWord{8, 0, 74},
+ dictWord{9, 0, 623},
+ dictWord{12, 0, 500},
+ dictWord{
+ 140,
+ 0,
+ 579,
+ },
+ dictWord{144, 0, 65},
+ dictWord{138, 11, 246},
+ dictWord{6, 0, 220},
+ dictWord{7, 0, 1101},
+ dictWord{13, 0, 105},
+ dictWord{142, 11, 314},
+ dictWord{
+ 5,
+ 10,
+ 1002,
+ },
+ dictWord{136, 10, 745},
+ dictWord{134, 0, 960},
+ dictWord{20, 0, 0},
+ dictWord{148, 11, 0},
+ dictWord{4, 0, 1005},
+ dictWord{4, 10, 239},
+ dictWord{
+ 6,
+ 10,
+ 477,
+ },
+ dictWord{7, 10, 1607},
+ dictWord{11, 10, 68},
+ dictWord{139, 10, 617},
+ dictWord{6, 0, 19},
+ dictWord{7, 0, 1413},
+ dictWord{139, 0, 428},
+ dictWord{
+ 149,
+ 10,
+ 13,
+ },
+ dictWord{7, 0, 96},
+ dictWord{8, 0, 401},
+ dictWord{8, 0, 703},
+ dictWord{9, 0, 896},
+ dictWord{136, 11, 300},
+ dictWord{134, 0, 1595},
+ dictWord{145, 0, 116},
+ dictWord{136, 0, 1021},
+ dictWord{7, 0, 1961},
+ dictWord{7, 0, 1965},
+ dictWord{7, 0, 2030},
+ dictWord{8, 0, 150},
+ dictWord{8, 0, 702},
+ dictWord{8, 0, 737},
+ dictWord{
+ 8,
+ 0,
+ 750,
+ },
+ dictWord{140, 0, 366},
+ dictWord{11, 11, 75},
+ dictWord{142, 11, 267},
+ dictWord{132, 10, 367},
+ dictWord{8, 0, 800},
+ dictWord{9, 0, 148},
+ dictWord{
+ 9,
+ 0,
+ 872,
+ },
+ dictWord{9, 0, 890},
+ dictWord{11, 0, 309},
+ dictWord{11, 0, 1001},
+ dictWord{13, 0, 267},
+ dictWord{13, 0, 323},
+ dictWord{5, 11, 427},
+ dictWord{
+ 5,
+ 11,
+ 734,
+ },
+ dictWord{7, 11, 478},
+ dictWord{136, 11, 52},
+ dictWord{7, 11, 239},
+ dictWord{11, 11, 217},
+ dictWord{142, 11, 165},
+ dictWord{132, 11, 323},
+ dictWord{140, 11, 419},
+ dictWord{13, 0, 299},
+ dictWord{142, 0, 75},
+ dictWord{6, 11, 87},
+ dictWord{6, 11, 1734},
+ dictWord{7, 11, 20},
+ dictWord{7, 11, 1056},
+ dictWord{
+ 8,
+ 11,
+ 732,
+ },
+ dictWord{9, 11, 406},
+ dictWord{9, 11, 911},
+ dictWord{138, 11, 694},
+ dictWord{134, 0, 1383},
+ dictWord{132, 10, 694},
+ dictWord{
+ 133,
+ 11,
+ 613,
+ },
+ dictWord{137, 0, 779},
+ dictWord{4, 0, 598},
+ dictWord{140, 10, 687},
+ dictWord{6, 0, 970},
+ dictWord{135, 0, 424},
+ dictWord{133, 0, 547},
+ dictWord{
+ 7,
+ 11,
+ 32,
+ },
+ dictWord{7, 11, 984},
+ dictWord{8, 11, 85},
+ dictWord{8, 11, 709},
+ dictWord{9, 11, 579},
+ dictWord{9, 11, 847},
+ dictWord{9, 11, 856},
+ dictWord{10, 11, 799},
+ dictWord{11, 11, 258},
+ dictWord{11, 11, 1007},
+ dictWord{12, 11, 331},
+ dictWord{12, 11, 615},
+ dictWord{13, 11, 188},
+ dictWord{13, 11, 435},
+ dictWord{
+ 14,
+ 11,
+ 8,
+ },
+ dictWord{15, 11, 165},
+ dictWord{16, 11, 27},
+ dictWord{148, 11, 40},
+ dictWord{6, 0, 1222},
+ dictWord{134, 0, 1385},
+ dictWord{132, 0, 876},
+ dictWord{
+ 138,
+ 11,
+ 151,
+ },
+ dictWord{135, 10, 213},
+ dictWord{4, 11, 167},
+ dictWord{135, 11, 82},
+ dictWord{133, 0, 133},
+ dictWord{6, 11, 24},
+ dictWord{7, 11, 74},
+ dictWord{
+ 7,
+ 11,
+ 678,
+ },
+ dictWord{137, 11, 258},
+ dictWord{5, 11, 62},
+ dictWord{6, 11, 534},
+ dictWord{7, 11, 684},
+ dictWord{7, 11, 1043},
+ dictWord{7, 11, 1072},
+ dictWord{
+ 8,
+ 11,
+ 280,
+ },
+ dictWord{8, 11, 541},
+ dictWord{8, 11, 686},
+ dictWord{10, 11, 519},
+ dictWord{11, 11, 252},
+ dictWord{140, 11, 282},
+ dictWord{136, 0, 187},
+ dictWord{8, 0, 8},
+ dictWord{10, 0, 0},
+ dictWord{10, 0, 818},
+ dictWord{139, 0, 988},
+ dictWord{132, 11, 359},
+ dictWord{11, 0, 429},
+ dictWord{15, 0, 51},
+ dictWord{
+ 135,
+ 10,
+ 1672,
+ },
+ dictWord{136, 0, 685},
+ dictWord{5, 11, 211},
+ dictWord{7, 11, 88},
+ dictWord{136, 11, 627},
+ dictWord{134, 0, 472},
+ dictWord{136, 0, 132},
+ dictWord{
+ 6,
+ 11,
+ 145,
+ },
+ dictWord{141, 11, 336},
+ dictWord{4, 10, 751},
+ dictWord{11, 10, 390},
+ dictWord{140, 10, 32},
+ dictWord{6, 0, 938},
+ dictWord{6, 0, 1060},
+ dictWord{
+ 4,
+ 11,
+ 263,
+ },
+ dictWord{4, 10, 409},
+ dictWord{133, 10, 78},
+ dictWord{137, 0, 874},
+ dictWord{8, 0, 774},
+ dictWord{10, 0, 670},
+ dictWord{12, 0, 51},
+ dictWord{
+ 4,
+ 11,
+ 916,
+ },
+ dictWord{6, 10, 473},
+ dictWord{7, 10, 1602},
+ dictWord{10, 10, 698},
+ dictWord{12, 10, 212},
+ dictWord{13, 10, 307},
+ dictWord{145, 10, 105},
+ dictWord{146, 0, 92},
+ dictWord{143, 10, 156},
+ dictWord{132, 0, 830},
+ dictWord{137, 0, 701},
+ dictWord{4, 11, 599},
+ dictWord{6, 11, 1634},
+ dictWord{7, 11, 5},
+ dictWord{7, 11, 55},
+ dictWord{7, 11, 67},
+ dictWord{7, 11, 97},
+ dictWord{7, 11, 691},
+ dictWord{7, 11, 979},
+ dictWord{7, 11, 1697},
+ dictWord{8, 11, 207},
+ dictWord{
+ 8,
+ 11,
+ 214,
+ },
+ dictWord{8, 11, 231},
+ dictWord{8, 11, 294},
+ dictWord{8, 11, 336},
+ dictWord{8, 11, 428},
+ dictWord{8, 11, 451},
+ dictWord{8, 11, 460},
+ dictWord{8, 11, 471},
+ dictWord{8, 11, 622},
+ dictWord{8, 11, 626},
+ dictWord{8, 11, 679},
+ dictWord{8, 11, 759},
+ dictWord{8, 11, 829},
+ dictWord{9, 11, 11},
+ dictWord{9, 11, 246},
+ dictWord{
+ 9,
+ 11,
+ 484,
+ },
+ dictWord{9, 11, 573},
+ dictWord{9, 11, 706},
+ dictWord{9, 11, 762},
+ dictWord{9, 11, 798},
+ dictWord{9, 11, 855},
+ dictWord{9, 11, 870},
+ dictWord{
+ 9,
+ 11,
+ 912,
+ },
+ dictWord{10, 11, 303},
+ dictWord{10, 11, 335},
+ dictWord{10, 11, 424},
+ dictWord{10, 11, 461},
+ dictWord{10, 11, 543},
+ dictWord{10, 11, 759},
+ dictWord{10, 11, 814},
+ dictWord{11, 11, 59},
+ dictWord{11, 11, 199},
+ dictWord{11, 11, 235},
+ dictWord{11, 11, 475},
+ dictWord{11, 11, 590},
+ dictWord{11, 11, 929},
+ dictWord{11, 11, 963},
+ dictWord{12, 11, 114},
+ dictWord{12, 11, 182},
+ dictWord{12, 11, 226},
+ dictWord{12, 11, 332},
+ dictWord{12, 11, 439},
+ dictWord{
+ 12,
+ 11,
+ 575,
+ },
+ dictWord{12, 11, 598},
+ dictWord{13, 11, 8},
+ dictWord{13, 11, 125},
+ dictWord{13, 11, 194},
+ dictWord{13, 11, 287},
+ dictWord{14, 11, 197},
+ dictWord{
+ 14,
+ 11,
+ 383,
+ },
+ dictWord{15, 11, 53},
+ dictWord{17, 11, 63},
+ dictWord{19, 11, 46},
+ dictWord{19, 11, 98},
+ dictWord{19, 11, 106},
+ dictWord{148, 11, 85},
+ dictWord{
+ 4,
+ 0,
+ 127,
+ },
+ dictWord{5, 0, 350},
+ dictWord{6, 0, 356},
+ dictWord{8, 0, 426},
+ dictWord{9, 0, 572},
+ dictWord{10, 0, 247},
+ dictWord{139, 0, 312},
+ dictWord{134, 0, 1215},
+ dictWord{6, 0, 59},
+ dictWord{9, 0, 603},
+ dictWord{13, 0, 397},
+ dictWord{7, 11, 1853},
+ dictWord{138, 11, 437},
+ dictWord{134, 0, 1762},
+ dictWord{
+ 147,
+ 11,
+ 126,
+ },
+ dictWord{135, 10, 883},
+ dictWord{13, 0, 293},
+ dictWord{142, 0, 56},
+ dictWord{133, 10, 617},
+ dictWord{139, 10, 50},
+ dictWord{5, 11, 187},
+ dictWord{
+ 7,
+ 10,
+ 1518,
+ },
+ dictWord{139, 10, 694},
+ dictWord{135, 0, 441},
+ dictWord{6, 0, 111},
+ dictWord{7, 0, 4},
+ dictWord{8, 0, 163},
+ dictWord{8, 0, 776},
+ dictWord{
+ 138,
+ 0,
+ 566,
+ },
+ dictWord{132, 0, 806},
+ dictWord{4, 11, 215},
+ dictWord{9, 11, 38},
+ dictWord{10, 11, 3},
+ dictWord{11, 11, 23},
+ dictWord{11, 11, 127},
+ dictWord{
+ 139,
+ 11,
+ 796,
+ },
+ dictWord{14, 0, 233},
+ dictWord{4, 10, 546},
+ dictWord{135, 10, 2042},
+ dictWord{135, 0, 1994},
+ dictWord{134, 0, 1739},
+ dictWord{135, 11, 1530},
+ dictWord{136, 0, 393},
+ dictWord{5, 0, 297},
+ dictWord{7, 0, 1038},
+ dictWord{14, 0, 359},
+ dictWord{19, 0, 52},
+ dictWord{148, 0, 47},
+ dictWord{135, 0, 309},
+ dictWord{
+ 4,
+ 10,
+ 313,
+ },
+ dictWord{133, 10, 577},
+ dictWord{8, 10, 184},
+ dictWord{141, 10, 433},
+ dictWord{135, 10, 935},
+ dictWord{12, 10, 186},
+ dictWord{
+ 12,
+ 10,
+ 292,
+ },
+ dictWord{14, 10, 100},
+ dictWord{146, 10, 70},
+ dictWord{136, 0, 363},
+ dictWord{14, 0, 175},
+ dictWord{11, 10, 402},
+ dictWord{12, 10, 109},
+ dictWord{
+ 12,
+ 10,
+ 431,
+ },
+ dictWord{13, 10, 179},
+ dictWord{13, 10, 206},
+ dictWord{14, 10, 217},
+ dictWord{16, 10, 3},
+ dictWord{148, 10, 53},
+ dictWord{5, 10, 886},
+ dictWord{
+ 6,
+ 10,
+ 46,
+ },
+ dictWord{6, 10, 1790},
+ dictWord{7, 10, 14},
+ dictWord{7, 10, 732},
+ dictWord{7, 10, 1654},
+ dictWord{8, 10, 95},
+ dictWord{8, 10, 327},
+ dictWord{
+ 8,
+ 10,
+ 616,
+ },
+ dictWord{9, 10, 892},
+ dictWord{10, 10, 598},
+ dictWord{10, 10, 769},
+ dictWord{11, 10, 134},
+ dictWord{11, 10, 747},
+ dictWord{12, 10, 378},
+ dictWord{
+ 142,
+ 10,
+ 97,
+ },
+ dictWord{136, 0, 666},
+ dictWord{135, 0, 1675},
+ dictWord{6, 0, 655},
+ dictWord{134, 0, 1600},
+ dictWord{135, 0, 808},
+ dictWord{133, 10, 1021},
+ dictWord{4, 11, 28},
+ dictWord{5, 11, 440},
+ dictWord{7, 11, 248},
+ dictWord{11, 11, 833},
+ dictWord{140, 11, 344},
+ dictWord{134, 11, 1654},
+ dictWord{
+ 132,
+ 0,
+ 280,
+ },
+ dictWord{140, 0, 54},
+ dictWord{4, 0, 421},
+ dictWord{133, 0, 548},
+ dictWord{132, 10, 153},
+ dictWord{6, 11, 339},
+ dictWord{135, 11, 923},
+ dictWord{
+ 133,
+ 11,
+ 853,
+ },
+ dictWord{133, 10, 798},
+ dictWord{132, 10, 587},
+ dictWord{6, 11, 249},
+ dictWord{7, 11, 1234},
+ dictWord{139, 11, 573},
+ dictWord{6, 10, 598},
+ dictWord{7, 10, 42},
+ dictWord{8, 10, 695},
+ dictWord{10, 10, 212},
+ dictWord{11, 10, 158},
+ dictWord{14, 10, 196},
+ dictWord{145, 10, 85},
+ dictWord{7, 0, 249},
+ dictWord{5, 10, 957},
+ dictWord{133, 10, 1008},
+ dictWord{4, 10, 129},
+ dictWord{135, 10, 465},
+ dictWord{6, 0, 254},
+ dictWord{7, 0, 842},
+ dictWord{7, 0, 1659},
+ dictWord{9, 0, 109},
+ dictWord{10, 0, 103},
+ dictWord{7, 10, 908},
+ dictWord{7, 10, 1201},
+ dictWord{9, 10, 755},
+ dictWord{11, 10, 906},
+ dictWord{12, 10, 527},
+ dictWord{146, 10, 7},
+ dictWord{5, 0, 262},
+ dictWord{136, 10, 450},
+ dictWord{144, 0, 1},
+ dictWord{10, 11, 201},
+ dictWord{142, 11, 319},
+ dictWord{7, 11, 49},
+ dictWord{
+ 7,
+ 11,
+ 392,
+ },
+ dictWord{8, 11, 20},
+ dictWord{8, 11, 172},
+ dictWord{8, 11, 690},
+ dictWord{9, 11, 383},
+ dictWord{9, 11, 845},
+ dictWord{10, 11, 48},
+ dictWord{
+ 11,
+ 11,
+ 293,
+ },
+ dictWord{11, 11, 832},
+ dictWord{11, 11, 920},
+ dictWord{141, 11, 221},
+ dictWord{5, 11, 858},
+ dictWord{133, 11, 992},
+ dictWord{134, 0, 805},
+ dictWord{139, 10, 1003},
+ dictWord{6, 0, 1630},
+ dictWord{134, 11, 307},
+ dictWord{7, 11, 1512},
+ dictWord{135, 11, 1794},
+ dictWord{6, 11, 268},
+ dictWord{
+ 137,
+ 11,
+ 62,
+ },
+ dictWord{135, 10, 1868},
+ dictWord{133, 0, 671},
+ dictWord{4, 0, 989},
+ dictWord{8, 0, 972},
+ dictWord{136, 0, 998},
+ dictWord{132, 11, 423},
+ dictWord{132, 0, 889},
+ dictWord{135, 0, 1382},
+ dictWord{135, 0, 1910},
+ dictWord{7, 10, 965},
+ dictWord{7, 10, 1460},
+ dictWord{135, 10, 1604},
+ dictWord{
+ 4,
+ 0,
+ 627,
+ },
+ dictWord{5, 0, 775},
+ dictWord{138, 11, 106},
+ dictWord{134, 11, 348},
+ dictWord{7, 0, 202},
+ dictWord{11, 0, 362},
+ dictWord{11, 0, 948},
+ dictWord{
+ 140,
+ 0,
+ 388,
+ },
+ dictWord{138, 11, 771},
+ dictWord{6, 11, 613},
+ dictWord{136, 11, 223},
+ dictWord{6, 0, 560},
+ dictWord{7, 0, 451},
+ dictWord{8, 0, 389},
+ dictWord{
+ 12,
+ 0,
+ 490,
+ },
+ dictWord{13, 0, 16},
+ dictWord{13, 0, 215},
+ dictWord{13, 0, 351},
+ dictWord{18, 0, 132},
+ dictWord{147, 0, 125},
+ dictWord{135, 0, 841},
+ dictWord{
+ 136,
+ 0,
+ 566,
+ },
+ dictWord{136, 0, 938},
+ dictWord{132, 11, 670},
+ dictWord{5, 0, 912},
+ dictWord{6, 0, 1695},
+ dictWord{140, 11, 55},
+ dictWord{9, 11, 40},
+ dictWord{
+ 139,
+ 11,
+ 136,
+ },
+ dictWord{7, 0, 1361},
+ dictWord{7, 10, 982},
+ dictWord{10, 10, 32},
+ dictWord{143, 10, 56},
+ dictWord{11, 11, 259},
+ dictWord{140, 11, 270},
+ dictWord{
+ 5,
+ 0,
+ 236,
+ },
+ dictWord{6, 0, 572},
+ dictWord{8, 0, 492},
+ dictWord{11, 0, 618},
+ dictWord{144, 0, 56},
+ dictWord{8, 11, 572},
+ dictWord{9, 11, 310},
+ dictWord{9, 11, 682},
+ dictWord{137, 11, 698},
+ dictWord{134, 0, 1854},
+ dictWord{5, 0, 190},
+ dictWord{136, 0, 318},
+ dictWord{133, 10, 435},
+ dictWord{135, 0, 1376},
+ dictWord{
+ 4,
+ 11,
+ 296,
+ },
+ dictWord{6, 11, 352},
+ dictWord{7, 11, 401},
+ dictWord{7, 11, 1410},
+ dictWord{7, 11, 1594},
+ dictWord{7, 11, 1674},
+ dictWord{8, 11, 63},
+ dictWord{
+ 8,
+ 11,
+ 660,
+ },
+ dictWord{137, 11, 74},
+ dictWord{7, 0, 349},
+ dictWord{5, 10, 85},
+ dictWord{6, 10, 419},
+ dictWord{7, 10, 305},
+ dictWord{7, 10, 361},
+ dictWord{7, 10, 1337},
+ dictWord{8, 10, 71},
+ dictWord{140, 10, 519},
+ dictWord{4, 11, 139},
+ dictWord{4, 11, 388},
+ dictWord{140, 11, 188},
+ dictWord{6, 0, 1972},
+ dictWord{6, 0, 2013},
+ dictWord{8, 0, 951},
+ dictWord{10, 0, 947},
+ dictWord{10, 0, 974},
+ dictWord{10, 0, 1018},
+ dictWord{142, 0, 476},
+ dictWord{140, 10, 688},
+ dictWord{
+ 135,
+ 10,
+ 740,
+ },
+ dictWord{5, 10, 691},
+ dictWord{7, 10, 345},
+ dictWord{9, 10, 94},
+ dictWord{140, 10, 169},
+ dictWord{9, 0, 344},
+ dictWord{5, 10, 183},
+ dictWord{6, 10, 582},
+ dictWord{10, 10, 679},
+ dictWord{140, 10, 435},
+ dictWord{135, 10, 511},
+ dictWord{132, 0, 850},
+ dictWord{8, 11, 441},
+ dictWord{10, 11, 314},
+ dictWord{
+ 143,
+ 11,
+ 3,
+ },
+ dictWord{7, 10, 1993},
+ dictWord{136, 10, 684},
+ dictWord{4, 11, 747},
+ dictWord{6, 11, 290},
+ dictWord{6, 10, 583},
+ dictWord{7, 11, 649},
+ dictWord{
+ 7,
+ 11,
+ 1479,
+ },
+ dictWord{135, 11, 1583},
+ dictWord{133, 11, 232},
+ dictWord{133, 10, 704},
+ dictWord{134, 0, 910},
+ dictWord{4, 10, 179},
+ dictWord{5, 10, 198},
+ dictWord{133, 10, 697},
+ dictWord{7, 10, 347},
+ dictWord{7, 10, 971},
+ dictWord{8, 10, 181},
+ dictWord{138, 10, 711},
+ dictWord{136, 11, 525},
+ dictWord{
+ 14,
+ 0,
+ 19,
+ },
+ dictWord{14, 0, 28},
+ dictWord{144, 0, 29},
+ dictWord{7, 0, 85},
+ dictWord{7, 0, 247},
+ dictWord{8, 0, 585},
+ dictWord{138, 0, 163},
+ dictWord{4, 0, 487},
+ dictWord{
+ 7,
+ 11,
+ 472,
+ },
+ dictWord{7, 11, 1801},
+ dictWord{10, 11, 748},
+ dictWord{141, 11, 458},
+ dictWord{4, 10, 243},
+ dictWord{5, 10, 203},
+ dictWord{7, 10, 19},
+ dictWord{
+ 7,
+ 10,
+ 71,
+ },
+ dictWord{7, 10, 113},
+ dictWord{10, 10, 405},
+ dictWord{11, 10, 357},
+ dictWord{142, 10, 240},
+ dictWord{7, 10, 1450},
+ dictWord{139, 10, 99},
+ dictWord{132, 11, 425},
+ dictWord{138, 0, 145},
+ dictWord{147, 0, 83},
+ dictWord{6, 10, 492},
+ dictWord{137, 11, 247},
+ dictWord{4, 0, 1013},
+ dictWord{
+ 134,
+ 0,
+ 2033,
+ },
+ dictWord{5, 10, 134},
+ dictWord{6, 10, 408},
+ dictWord{6, 10, 495},
+ dictWord{135, 10, 1593},
+ dictWord{135, 0, 1922},
+ dictWord{134, 11, 1768},
+ dictWord{4, 0, 124},
+ dictWord{10, 0, 457},
+ dictWord{11, 0, 121},
+ dictWord{11, 0, 169},
+ dictWord{11, 0, 870},
+ dictWord{11, 0, 874},
+ dictWord{12, 0, 214},
+ dictWord{
+ 14,
+ 0,
+ 187,
+ },
+ dictWord{143, 0, 77},
+ dictWord{5, 0, 557},
+ dictWord{135, 0, 1457},
+ dictWord{139, 0, 66},
+ dictWord{5, 11, 943},
+ dictWord{6, 11, 1779},
+ dictWord{
+ 142,
+ 10,
+ 4,
+ },
+ dictWord{4, 10, 248},
+ dictWord{4, 10, 665},
+ dictWord{7, 10, 137},
+ dictWord{137, 10, 349},
+ dictWord{7, 0, 1193},
+ dictWord{5, 11, 245},
+ dictWord{
+ 6,
+ 11,
+ 576,
+ },
+ dictWord{7, 11, 582},
+ dictWord{136, 11, 225},
+ dictWord{144, 0, 82},
+ dictWord{7, 10, 1270},
+ dictWord{139, 10, 612},
+ dictWord{5, 0, 454},
+ dictWord{
+ 10,
+ 0,
+ 352,
+ },
+ dictWord{138, 11, 352},
+ dictWord{18, 0, 57},
+ dictWord{5, 10, 371},
+ dictWord{135, 10, 563},
+ dictWord{135, 0, 1333},
+ dictWord{6, 0, 107},
+ dictWord{
+ 7,
+ 0,
+ 638,
+ },
+ dictWord{7, 0, 1632},
+ dictWord{9, 0, 396},
+ dictWord{134, 11, 610},
+ dictWord{5, 0, 370},
+ dictWord{134, 0, 1756},
+ dictWord{4, 10, 374},
+ dictWord{
+ 7,
+ 10,
+ 547,
+ },
+ dictWord{7, 10, 1700},
+ dictWord{7, 10, 1833},
+ dictWord{139, 10, 858},
+ dictWord{133, 0, 204},
+ dictWord{6, 0, 1305},
+ dictWord{9, 10, 311},
+ dictWord{
+ 141,
+ 10,
+ 42,
+ },
+ dictWord{5, 0, 970},
+ dictWord{134, 0, 1706},
+ dictWord{6, 10, 1647},
+ dictWord{7, 10, 1552},
+ dictWord{7, 10, 2010},
+ dictWord{9, 10, 494},
+ dictWord{137, 10, 509},
+ dictWord{13, 11, 455},
+ dictWord{15, 11, 99},
+ dictWord{15, 11, 129},
+ dictWord{144, 11, 68},
+ dictWord{135, 0, 3},
+ dictWord{4, 0, 35},
+ dictWord{
+ 5,
+ 0,
+ 121,
+ },
+ dictWord{5, 0, 483},
+ dictWord{5, 0, 685},
+ dictWord{6, 0, 489},
+ dictWord{6, 0, 782},
+ dictWord{6, 0, 1032},
+ dictWord{7, 0, 1204},
+ dictWord{136, 0, 394},
+ dictWord{4, 0, 921},
+ dictWord{133, 0, 1007},
+ dictWord{8, 11, 360},
+ dictWord{138, 11, 63},
+ dictWord{135, 0, 1696},
+ dictWord{134, 0, 1519},
+ dictWord{
+ 132,
+ 11,
+ 443,
+ },
+ dictWord{135, 11, 944},
+ dictWord{6, 10, 123},
+ dictWord{7, 10, 214},
+ dictWord{9, 10, 728},
+ dictWord{10, 10, 157},
+ dictWord{11, 10, 346},
+ dictWord{11, 10, 662},
+ dictWord{143, 10, 106},
+ dictWord{137, 0, 981},
+ dictWord{135, 10, 1435},
+ dictWord{134, 0, 1072},
+ dictWord{132, 0, 712},
+ dictWord{
+ 134,
+ 0,
+ 1629,
+ },
+ dictWord{134, 0, 728},
+ dictWord{4, 11, 298},
+ dictWord{137, 11, 483},
+ dictWord{6, 0, 1177},
+ dictWord{6, 0, 1271},
+ dictWord{5, 11, 164},
+ dictWord{
+ 7,
+ 11,
+ 121,
+ },
+ dictWord{142, 11, 189},
+ dictWord{7, 0, 1608},
+ dictWord{4, 10, 707},
+ dictWord{5, 10, 588},
+ dictWord{6, 10, 393},
+ dictWord{13, 10, 106},
+ dictWord{
+ 18,
+ 10,
+ 49,
+ },
+ dictWord{147, 10, 41},
+ dictWord{23, 0, 16},
+ dictWord{151, 11, 16},
+ dictWord{6, 10, 211},
+ dictWord{7, 10, 1690},
+ dictWord{11, 10, 486},
+ dictWord{140, 10, 369},
+ dictWord{133, 0, 485},
+ dictWord{19, 11, 15},
+ dictWord{149, 11, 27},
+ dictWord{4, 11, 172},
+ dictWord{9, 11, 611},
+ dictWord{10, 11, 436},
+ dictWord{12, 11, 673},
+ dictWord{141, 11, 255},
+ dictWord{5, 11, 844},
+ dictWord{10, 11, 484},
+ dictWord{11, 11, 754},
+ dictWord{12, 11, 457},
+ dictWord{
+ 14,
+ 11,
+ 171,
+ },
+ dictWord{14, 11, 389},
+ dictWord{146, 11, 153},
+ dictWord{4, 0, 285},
+ dictWord{5, 0, 27},
+ dictWord{5, 0, 317},
+ dictWord{6, 0, 301},
+ dictWord{7, 0, 7},
+ dictWord{
+ 8,
+ 0,
+ 153,
+ },
+ dictWord{10, 0, 766},
+ dictWord{11, 0, 468},
+ dictWord{12, 0, 467},
+ dictWord{141, 0, 143},
+ dictWord{134, 0, 1462},
+ dictWord{9, 11, 263},
+ dictWord{
+ 10,
+ 11,
+ 147,
+ },
+ dictWord{138, 11, 492},
+ dictWord{133, 11, 537},
+ dictWord{6, 0, 1945},
+ dictWord{6, 0, 1986},
+ dictWord{6, 0, 1991},
+ dictWord{134, 0, 2038},
+ dictWord{134, 10, 219},
+ dictWord{137, 11, 842},
+ dictWord{14, 0, 52},
+ dictWord{17, 0, 50},
+ dictWord{5, 10, 582},
+ dictWord{6, 10, 1646},
+ dictWord{7, 10, 99},
+ dictWord{7, 10, 1962},
+ dictWord{7, 10, 1986},
+ dictWord{8, 10, 515},
+ dictWord{8, 10, 773},
+ dictWord{9, 10, 23},
+ dictWord{9, 10, 491},
+ dictWord{12, 10, 620},
+ dictWord{142, 10, 93},
+ dictWord{138, 11, 97},
+ dictWord{20, 0, 21},
+ dictWord{20, 0, 44},
+ dictWord{133, 10, 851},
+ dictWord{136, 0, 819},
+ dictWord{139, 0, 917},
+ dictWord{5, 11, 230},
+ dictWord{5, 11, 392},
+ dictWord{6, 11, 420},
+ dictWord{8, 10, 762},
+ dictWord{8, 10, 812},
+ dictWord{9, 11, 568},
+ dictWord{9, 10, 910},
+ dictWord{140, 11, 612},
+ dictWord{135, 0, 784},
+ dictWord{15, 0, 135},
+ dictWord{143, 11, 135},
+ dictWord{10, 0, 454},
+ dictWord{140, 0, 324},
+ dictWord{4, 11, 0},
+ dictWord{5, 11, 41},
+ dictWord{7, 11, 1459},
+ dictWord{7, 11, 1469},
+ dictWord{7, 11, 1618},
+ dictWord{7, 11, 1859},
+ dictWord{9, 11, 549},
+ dictWord{139, 11, 905},
+ dictWord{4, 10, 98},
+ dictWord{7, 10, 1365},
+ dictWord{9, 10, 422},
+ dictWord{9, 10, 670},
+ dictWord{10, 10, 775},
+ dictWord{11, 10, 210},
+ dictWord{13, 10, 26},
+ dictWord{13, 10, 457},
+ dictWord{141, 10, 476},
+ dictWord{6, 0, 1719},
+ dictWord{6, 0, 1735},
+ dictWord{7, 0, 2016},
+ dictWord{7, 0, 2020},
+ dictWord{8, 0, 837},
+ dictWord{137, 0, 852},
+ dictWord{133, 11, 696},
+ dictWord{135, 0, 852},
+ dictWord{132, 0, 952},
+ dictWord{134, 10, 1730},
+ dictWord{132, 11, 771},
+ dictWord{
+ 138,
+ 0,
+ 568,
+ },
+ dictWord{137, 0, 448},
+ dictWord{139, 0, 146},
+ dictWord{8, 0, 67},
+ dictWord{138, 0, 419},
+ dictWord{133, 11, 921},
+ dictWord{137, 10, 147},
+ dictWord{134, 0, 1826},
+ dictWord{10, 0, 657},
+ dictWord{14, 0, 297},
+ dictWord{142, 0, 361},
+ dictWord{6, 0, 666},
+ dictWord{6, 0, 767},
+ dictWord{134, 0, 1542},
+ dictWord{139, 0, 729},
+ dictWord{6, 11, 180},
+ dictWord{7, 11, 1137},
+ dictWord{8, 11, 751},
+ dictWord{139, 11, 805},
+ dictWord{4, 11, 183},
+ dictWord{7, 11, 271},
+ dictWord{11, 11, 824},
+ dictWord{11, 11, 952},
+ dictWord{13, 11, 278},
+ dictWord{13, 11, 339},
+ dictWord{13, 11, 482},
+ dictWord{14, 11, 424},
+ dictWord{
+ 148,
+ 11,
+ 99,
+ },
+ dictWord{4, 0, 669},
+ dictWord{5, 11, 477},
+ dictWord{5, 11, 596},
+ dictWord{6, 11, 505},
+ dictWord{7, 11, 1221},
+ dictWord{11, 11, 907},
+ dictWord{
+ 12,
+ 11,
+ 209,
+ },
+ dictWord{141, 11, 214},
+ dictWord{135, 11, 1215},
+ dictWord{5, 0, 402},
+ dictWord{6, 10, 30},
+ dictWord{11, 10, 56},
+ dictWord{139, 10, 305},
+ dictWord{
+ 7,
+ 11,
+ 564,
+ },
+ dictWord{142, 11, 168},
+ dictWord{139, 0, 152},
+ dictWord{7, 0, 912},
+ dictWord{135, 10, 1614},
+ dictWord{4, 10, 150},
+ dictWord{5, 10, 303},
+ dictWord{134, 10, 327},
+ dictWord{7, 0, 320},
+ dictWord{8, 0, 51},
+ dictWord{9, 0, 868},
+ dictWord{10, 0, 833},
+ dictWord{12, 0, 481},
+ dictWord{12, 0, 570},
+ dictWord{
+ 148,
+ 0,
+ 106,
+ },
+ dictWord{132, 0, 445},
+ dictWord{7, 11, 274},
+ dictWord{11, 11, 263},
+ dictWord{11, 11, 479},
+ dictWord{11, 11, 507},
+ dictWord{140, 11, 277},
+ dictWord{10, 0, 555},
+ dictWord{11, 0, 308},
+ dictWord{19, 0, 95},
+ dictWord{6, 11, 1645},
+ dictWord{8, 10, 192},
+ dictWord{10, 10, 78},
+ dictWord{141, 10, 359},
+ dictWord{135, 10, 786},
+ dictWord{6, 11, 92},
+ dictWord{6, 11, 188},
+ dictWord{7, 11, 1269},
+ dictWord{7, 11, 1524},
+ dictWord{7, 11, 1876},
+ dictWord{10, 11, 228},
+ dictWord{139, 11, 1020},
+ dictWord{4, 11, 459},
+ dictWord{133, 11, 966},
+ dictWord{11, 0, 386},
+ dictWord{6, 10, 1638},
+ dictWord{7, 10, 79},
+ dictWord{
+ 7,
+ 10,
+ 496,
+ },
+ dictWord{9, 10, 138},
+ dictWord{10, 10, 336},
+ dictWord{12, 10, 412},
+ dictWord{12, 10, 440},
+ dictWord{142, 10, 305},
+ dictWord{133, 0, 239},
+ dictWord{
+ 7,
+ 0,
+ 83,
+ },
+ dictWord{7, 0, 1990},
+ dictWord{8, 0, 130},
+ dictWord{139, 0, 720},
+ dictWord{138, 11, 709},
+ dictWord{4, 0, 143},
+ dictWord{5, 0, 550},
+ dictWord{
+ 133,
+ 0,
+ 752,
+ },
+ dictWord{5, 0, 123},
+ dictWord{6, 0, 530},
+ dictWord{7, 0, 348},
+ dictWord{135, 0, 1419},
+ dictWord{135, 0, 2024},
+ dictWord{6, 11, 18},
+ dictWord{7, 11, 179},
+ dictWord{7, 11, 721},
+ dictWord{7, 11, 932},
+ dictWord{8, 11, 548},
+ dictWord{8, 11, 757},
+ dictWord{9, 11, 54},
+ dictWord{9, 11, 65},
+ dictWord{9, 11, 532},
+ dictWord{
+ 9,
+ 11,
+ 844,
+ },
+ dictWord{10, 11, 113},
+ dictWord{10, 11, 117},
+ dictWord{10, 11, 236},
+ dictWord{10, 11, 315},
+ dictWord{10, 11, 430},
+ dictWord{10, 11, 798},
+ dictWord{11, 11, 153},
+ dictWord{11, 11, 351},
+ dictWord{11, 11, 375},
+ dictWord{12, 11, 78},
+ dictWord{12, 11, 151},
+ dictWord{12, 11, 392},
+ dictWord{
+ 14,
+ 11,
+ 248,
+ },
+ dictWord{143, 11, 23},
+ dictWord{7, 10, 204},
+ dictWord{7, 10, 415},
+ dictWord{8, 10, 42},
+ dictWord{10, 10, 85},
+ dictWord{139, 10, 564},
+ dictWord{
+ 134,
+ 0,
+ 958,
+ },
+ dictWord{133, 11, 965},
+ dictWord{132, 0, 210},
+ dictWord{135, 11, 1429},
+ dictWord{138, 11, 480},
+ dictWord{134, 11, 182},
+ dictWord{
+ 139,
+ 11,
+ 345,
+ },
+ dictWord{10, 11, 65},
+ dictWord{10, 11, 488},
+ dictWord{138, 11, 497},
+ dictWord{4, 10, 3},
+ dictWord{5, 10, 247},
+ dictWord{5, 10, 644},
+ dictWord{
+ 7,
+ 10,
+ 744,
+ },
+ dictWord{7, 10, 1207},
+ dictWord{7, 10, 1225},
+ dictWord{7, 10, 1909},
+ dictWord{146, 10, 147},
+ dictWord{132, 0, 430},
+ dictWord{5, 10, 285},
+ dictWord{
+ 9,
+ 10,
+ 67,
+ },
+ dictWord{13, 10, 473},
+ dictWord{143, 10, 82},
+ dictWord{144, 11, 16},
+ dictWord{7, 11, 1162},
+ dictWord{9, 11, 588},
+ dictWord{10, 11, 260},
+ dictWord{151, 10, 8},
+ dictWord{133, 0, 213},
+ dictWord{138, 0, 7},
+ dictWord{135, 0, 801},
+ dictWord{134, 11, 1786},
+ dictWord{135, 11, 308},
+ dictWord{6, 0, 936},
+ dictWord{134, 0, 1289},
+ dictWord{133, 0, 108},
+ dictWord{132, 0, 885},
+ dictWord{133, 0, 219},
+ dictWord{139, 0, 587},
+ dictWord{4, 0, 193},
+ dictWord{5, 0, 916},
+ dictWord{6, 0, 1041},
+ dictWord{7, 0, 364},
+ dictWord{10, 0, 398},
+ dictWord{10, 0, 726},
+ dictWord{11, 0, 317},
+ dictWord{11, 0, 626},
+ dictWord{12, 0, 142},
+ dictWord{12, 0, 288},
+ dictWord{12, 0, 678},
+ dictWord{13, 0, 313},
+ dictWord{15, 0, 113},
+ dictWord{146, 0, 114},
+ dictWord{135, 0, 1165},
+ dictWord{6, 0, 241},
+ dictWord{
+ 9,
+ 0,
+ 342,
+ },
+ dictWord{10, 0, 729},
+ dictWord{11, 0, 284},
+ dictWord{11, 0, 445},
+ dictWord{11, 0, 651},
+ dictWord{11, 0, 863},
+ dictWord{13, 0, 398},
+ dictWord{
+ 146,
+ 0,
+ 99,
+ },
+ dictWord{7, 0, 907},
+ dictWord{136, 0, 832},
+ dictWord{9, 0, 303},
+ dictWord{4, 10, 29},
+ dictWord{6, 10, 532},
+ dictWord{7, 10, 1628},
+ dictWord{7, 10, 1648},
+ dictWord{9, 10, 350},
+ dictWord{10, 10, 433},
+ dictWord{11, 10, 97},
+ dictWord{11, 10, 557},
+ dictWord{11, 10, 745},
+ dictWord{12, 10, 289},
+ dictWord{
+ 12,
+ 10,
+ 335,
+ },
+ dictWord{12, 10, 348},
+ dictWord{12, 10, 606},
+ dictWord{13, 10, 116},
+ dictWord{13, 10, 233},
+ dictWord{13, 10, 466},
+ dictWord{14, 10, 181},
+ dictWord{
+ 14,
+ 10,
+ 209,
+ },
+ dictWord{14, 10, 232},
+ dictWord{14, 10, 236},
+ dictWord{14, 10, 300},
+ dictWord{16, 10, 41},
+ dictWord{148, 10, 97},
+ dictWord{7, 11, 423},
+ dictWord{7, 10, 1692},
+ dictWord{136, 11, 588},
+ dictWord{6, 0, 931},
+ dictWord{134, 0, 1454},
+ dictWord{5, 10, 501},
+ dictWord{7, 10, 1704},
+ dictWord{9, 10, 553},
+ dictWord{11, 10, 520},
+ dictWord{12, 10, 557},
+ dictWord{141, 10, 249},
+ dictWord{136, 11, 287},
+ dictWord{4, 0, 562},
+ dictWord{9, 0, 254},
+ dictWord{
+ 139,
+ 0,
+ 879,
+ },
+ dictWord{132, 0, 786},
+ dictWord{14, 11, 32},
+ dictWord{18, 11, 85},
+ dictWord{20, 11, 2},
+ dictWord{152, 11, 16},
+ dictWord{135, 0, 1294},
+ dictWord{
+ 7,
+ 11,
+ 723,
+ },
+ dictWord{135, 11, 1135},
+ dictWord{6, 0, 216},
+ dictWord{7, 0, 901},
+ dictWord{7, 0, 1343},
+ dictWord{8, 0, 493},
+ dictWord{134, 11, 403},
+ dictWord{
+ 7,
+ 11,
+ 719,
+ },
+ dictWord{8, 11, 809},
+ dictWord{136, 11, 834},
+ dictWord{5, 11, 210},
+ dictWord{6, 11, 213},
+ dictWord{7, 11, 60},
+ dictWord{10, 11, 364},
+ dictWord{
+ 139,
+ 11,
+ 135,
+ },
+ dictWord{7, 0, 341},
+ dictWord{11, 0, 219},
+ dictWord{5, 11, 607},
+ dictWord{8, 11, 326},
+ dictWord{136, 11, 490},
+ dictWord{4, 11, 701},
+ dictWord{
+ 5,
+ 11,
+ 472,
+ },
+ dictWord{5, 11, 639},
+ dictWord{7, 11, 1249},
+ dictWord{9, 11, 758},
+ dictWord{139, 11, 896},
+ dictWord{135, 11, 380},
+ dictWord{135, 11, 1947},
+ dictWord{139, 0, 130},
+ dictWord{135, 0, 1734},
+ dictWord{10, 0, 115},
+ dictWord{11, 0, 420},
+ dictWord{12, 0, 154},
+ dictWord{13, 0, 404},
+ dictWord{14, 0, 346},
+ dictWord{143, 0, 54},
+ dictWord{134, 10, 129},
+ dictWord{4, 11, 386},
+ dictWord{7, 11, 41},
+ dictWord{8, 11, 405},
+ dictWord{9, 11, 497},
+ dictWord{11, 11, 110},
+ dictWord{11, 11, 360},
+ dictWord{15, 11, 37},
+ dictWord{144, 11, 84},
+ dictWord{141, 11, 282},
+ dictWord{5, 11, 46},
+ dictWord{7, 11, 1452},
+ dictWord{7, 11, 1480},
+ dictWord{8, 11, 634},
+ dictWord{140, 11, 472},
+ dictWord{4, 11, 524},
+ dictWord{136, 11, 810},
+ dictWord{10, 11, 238},
+ dictWord{141, 11, 33},
+ dictWord{
+ 133,
+ 0,
+ 604,
+ },
+ dictWord{5, 0, 1011},
+ dictWord{136, 0, 701},
+ dictWord{8, 0, 856},
+ dictWord{8, 0, 858},
+ dictWord{8, 0, 879},
+ dictWord{12, 0, 702},
+ dictWord{142, 0, 447},
+ dictWord{4, 0, 54},
+ dictWord{5, 0, 666},
+ dictWord{7, 0, 1039},
+ dictWord{7, 0, 1130},
+ dictWord{9, 0, 195},
+ dictWord{138, 0, 302},
+ dictWord{4, 10, 25},
+ dictWord{
+ 5,
+ 10,
+ 60,
+ },
+ dictWord{6, 10, 504},
+ dictWord{7, 10, 614},
+ dictWord{7, 10, 1155},
+ dictWord{140, 10, 0},
+ dictWord{7, 10, 1248},
+ dictWord{11, 10, 621},
+ dictWord{
+ 139,
+ 10,
+ 702,
+ },
+ dictWord{133, 11, 997},
+ dictWord{137, 10, 321},
+ dictWord{134, 0, 1669},
+ dictWord{134, 0, 1791},
+ dictWord{4, 10, 379},
+ dictWord{
+ 135,
+ 10,
+ 1397,
+ },
+ dictWord{138, 11, 372},
+ dictWord{5, 11, 782},
+ dictWord{5, 11, 829},
+ dictWord{134, 11, 1738},
+ dictWord{135, 0, 1228},
+ dictWord{4, 10, 118},
+ dictWord{6, 10, 274},
+ dictWord{6, 10, 361},
+ dictWord{7, 10, 75},
+ dictWord{141, 10, 441},
+ dictWord{132, 0, 623},
+ dictWord{9, 11, 279},
+ dictWord{10, 11, 407},
+ dictWord{14, 11, 84},
+ dictWord{150, 11, 18},
+ dictWord{137, 10, 841},
+ dictWord{135, 0, 798},
+ dictWord{140, 10, 693},
+ dictWord{5, 10, 314},
+ dictWord{6, 10, 221},
+ dictWord{7, 10, 419},
+ dictWord{10, 10, 650},
+ dictWord{11, 10, 396},
+ dictWord{12, 10, 156},
+ dictWord{13, 10, 369},
+ dictWord{14, 10, 333},
+ dictWord{
+ 145,
+ 10,
+ 47,
+ },
+ dictWord{135, 11, 1372},
+ dictWord{7, 0, 122},
+ dictWord{9, 0, 259},
+ dictWord{10, 0, 84},
+ dictWord{11, 0, 470},
+ dictWord{12, 0, 541},
+ dictWord{
+ 141,
+ 0,
+ 379,
+ },
+ dictWord{134, 0, 837},
+ dictWord{8, 0, 1013},
+ dictWord{4, 11, 78},
+ dictWord{5, 11, 96},
+ dictWord{5, 11, 182},
+ dictWord{7, 11, 1724},
+ dictWord{
+ 7,
+ 11,
+ 1825,
+ },
+ dictWord{10, 11, 394},
+ dictWord{10, 11, 471},
+ dictWord{11, 11, 532},
+ dictWord{14, 11, 340},
+ dictWord{145, 11, 88},
+ dictWord{134, 0, 577},
+ dictWord{135, 11, 1964},
+ dictWord{132, 10, 913},
+ dictWord{134, 0, 460},
+ dictWord{8, 0, 891},
+ dictWord{10, 0, 901},
+ dictWord{10, 0, 919},
+ dictWord{10, 0, 932},
+ dictWord{12, 0, 715},
+ dictWord{12, 0, 728},
+ dictWord{12, 0, 777},
+ dictWord{14, 0, 457},
+ dictWord{144, 0, 103},
+ dictWord{5, 0, 82},
+ dictWord{5, 0, 131},
+ dictWord{
+ 7,
+ 0,
+ 1755,
+ },
+ dictWord{8, 0, 31},
+ dictWord{9, 0, 168},
+ dictWord{9, 0, 764},
+ dictWord{139, 0, 869},
+ dictWord{136, 10, 475},
+ dictWord{6, 0, 605},
+ dictWord{
+ 5,
+ 10,
+ 1016,
+ },
+ dictWord{9, 11, 601},
+ dictWord{9, 11, 619},
+ dictWord{10, 11, 505},
+ dictWord{10, 11, 732},
+ dictWord{11, 11, 355},
+ dictWord{140, 11, 139},
+ dictWord{
+ 7,
+ 10,
+ 602,
+ },
+ dictWord{8, 10, 179},
+ dictWord{10, 10, 781},
+ dictWord{140, 10, 126},
+ dictWord{134, 0, 1246},
+ dictWord{6, 10, 329},
+ dictWord{138, 10, 111},
+ dictWord{6, 11, 215},
+ dictWord{7, 11, 1028},
+ dictWord{7, 11, 1473},
+ dictWord{7, 11, 1721},
+ dictWord{9, 11, 424},
+ dictWord{138, 11, 779},
+ dictWord{5, 0, 278},
+ dictWord{137, 0, 68},
+ dictWord{6, 0, 932},
+ dictWord{6, 0, 1084},
+ dictWord{144, 0, 86},
+ dictWord{4, 0, 163},
+ dictWord{5, 0, 201},
+ dictWord{5, 0, 307},
+ dictWord{
+ 5,
+ 0,
+ 310,
+ },
+ dictWord{6, 0, 335},
+ dictWord{7, 0, 284},
+ dictWord{7, 0, 1660},
+ dictWord{136, 0, 165},
+ dictWord{136, 0, 781},
+ dictWord{134, 0, 707},
+ dictWord{6, 0, 33},
+ dictWord{135, 0, 1244},
+ dictWord{5, 10, 821},
+ dictWord{6, 11, 67},
+ dictWord{6, 10, 1687},
+ dictWord{7, 11, 258},
+ dictWord{7, 11, 1630},
+ dictWord{9, 11, 354},
+ dictWord{9, 11, 675},
+ dictWord{10, 11, 830},
+ dictWord{14, 11, 80},
+ dictWord{145, 11, 80},
+ dictWord{6, 11, 141},
+ dictWord{7, 11, 225},
+ dictWord{9, 11, 59},
+ dictWord{9, 11, 607},
+ dictWord{10, 11, 312},
+ dictWord{11, 11, 687},
+ dictWord{12, 11, 555},
+ dictWord{13, 11, 373},
+ dictWord{13, 11, 494},
+ dictWord{148, 11, 58},
+ dictWord{134, 0, 1113},
+ dictWord{9, 0, 388},
+ dictWord{5, 10, 71},
+ dictWord{7, 10, 1407},
+ dictWord{9, 10, 704},
+ dictWord{10, 10, 261},
+ dictWord{10, 10, 619},
+ dictWord{11, 10, 547},
+ dictWord{11, 10, 619},
+ dictWord{143, 10, 157},
+ dictWord{7, 0, 1953},
+ dictWord{136, 0, 720},
+ dictWord{138, 0, 203},
+ dictWord{
+ 7,
+ 10,
+ 2008,
+ },
+ dictWord{9, 10, 337},
+ dictWord{138, 10, 517},
+ dictWord{6, 0, 326},
+ dictWord{7, 0, 677},
+ dictWord{137, 0, 425},
+ dictWord{139, 11, 81},
+ dictWord{
+ 7,
+ 0,
+ 1316,
+ },
+ dictWord{7, 0, 1412},
+ dictWord{7, 0, 1839},
+ dictWord{9, 0, 589},
+ dictWord{11, 0, 241},
+ dictWord{11, 0, 676},
+ dictWord{11, 0, 811},
+ dictWord{11, 0, 891},
+ dictWord{12, 0, 140},
+ dictWord{12, 0, 346},
+ dictWord{12, 0, 479},
+ dictWord{13, 0, 140},
+ dictWord{13, 0, 381},
+ dictWord{14, 0, 188},
+ dictWord{18, 0, 30},
+ dictWord{148, 0, 108},
+ dictWord{5, 0, 416},
+ dictWord{6, 10, 86},
+ dictWord{6, 10, 603},
+ dictWord{7, 10, 292},
+ dictWord{7, 10, 561},
+ dictWord{8, 10, 257},
+ dictWord{
+ 8,
+ 10,
+ 382,
+ },
+ dictWord{9, 10, 721},
+ dictWord{9, 10, 778},
+ dictWord{11, 10, 581},
+ dictWord{140, 10, 466},
+ dictWord{4, 10, 486},
+ dictWord{133, 10, 491},
+ dictWord{134, 0, 1300},
+ dictWord{132, 10, 72},
+ dictWord{7, 0, 847},
+ dictWord{6, 10, 265},
+ dictWord{7, 11, 430},
+ dictWord{139, 11, 46},
+ dictWord{5, 11, 602},
+ dictWord{6, 11, 106},
+ dictWord{7, 11, 1786},
+ dictWord{7, 11, 1821},
+ dictWord{7, 11, 2018},
+ dictWord{9, 11, 418},
+ dictWord{137, 11, 763},
+ dictWord{5, 0, 358},
+ dictWord{7, 0, 535},
+ dictWord{7, 0, 1184},
+ dictWord{10, 0, 662},
+ dictWord{13, 0, 212},
+ dictWord{13, 0, 304},
+ dictWord{13, 0, 333},
+ dictWord{145, 0, 98},
+ dictWord{
+ 5,
+ 11,
+ 65,
+ },
+ dictWord{6, 11, 416},
+ dictWord{7, 11, 1720},
+ dictWord{7, 11, 1924},
+ dictWord{8, 11, 677},
+ dictWord{10, 11, 109},
+ dictWord{11, 11, 14},
+ dictWord{
+ 11,
+ 11,
+ 70,
+ },
+ dictWord{11, 11, 569},
+ dictWord{11, 11, 735},
+ dictWord{15, 11, 153},
+ dictWord{148, 11, 80},
+ dictWord{6, 0, 1823},
+ dictWord{8, 0, 839},
+ dictWord{
+ 8,
+ 0,
+ 852,
+ },
+ dictWord{8, 0, 903},
+ dictWord{10, 0, 940},
+ dictWord{12, 0, 707},
+ dictWord{140, 0, 775},
+ dictWord{135, 11, 1229},
+ dictWord{6, 0, 1522},
+ dictWord{
+ 140,
+ 0,
+ 654,
+ },
+ dictWord{136, 11, 595},
+ dictWord{139, 0, 163},
+ dictWord{141, 0, 314},
+ dictWord{132, 0, 978},
+ dictWord{4, 0, 601},
+ dictWord{6, 0, 2035},
+ dictWord{137, 10, 234},
+ dictWord{5, 10, 815},
+ dictWord{6, 10, 1688},
+ dictWord{134, 10, 1755},
+ dictWord{133, 0, 946},
+ dictWord{136, 0, 434},
+ dictWord{
+ 6,
+ 10,
+ 197,
+ },
+ dictWord{136, 10, 205},
+ dictWord{7, 0, 411},
+ dictWord{7, 0, 590},
+ dictWord{8, 0, 631},
+ dictWord{9, 0, 323},
+ dictWord{10, 0, 355},
+ dictWord{11, 0, 491},
+ dictWord{12, 0, 143},
+ dictWord{12, 0, 402},
+ dictWord{13, 0, 73},
+ dictWord{14, 0, 408},
+ dictWord{15, 0, 107},
+ dictWord{146, 0, 71},
+ dictWord{7, 0, 1467},
+ dictWord{
+ 8,
+ 0,
+ 328,
+ },
+ dictWord{10, 0, 544},
+ dictWord{11, 0, 955},
+ dictWord{12, 0, 13},
+ dictWord{13, 0, 320},
+ dictWord{145, 0, 83},
+ dictWord{142, 0, 410},
+ dictWord{
+ 11,
+ 0,
+ 511,
+ },
+ dictWord{13, 0, 394},
+ dictWord{14, 0, 298},
+ dictWord{14, 0, 318},
+ dictWord{146, 0, 103},
+ dictWord{6, 10, 452},
+ dictWord{7, 10, 312},
+ dictWord{
+ 138,
+ 10,
+ 219,
+ },
+ dictWord{138, 10, 589},
+ dictWord{4, 10, 333},
+ dictWord{9, 10, 176},
+ dictWord{12, 10, 353},
+ dictWord{141, 10, 187},
+ dictWord{135, 11, 329},
+ dictWord{132, 11, 469},
+ dictWord{5, 0, 835},
+ dictWord{134, 0, 483},
+ dictWord{134, 11, 1743},
+ dictWord{5, 11, 929},
+ dictWord{6, 11, 340},
+ dictWord{8, 11, 376},
+ dictWord{136, 11, 807},
+ dictWord{134, 10, 1685},
+ dictWord{132, 0, 677},
+ dictWord{5, 11, 218},
+ dictWord{7, 11, 1610},
+ dictWord{138, 11, 83},
+ dictWord{
+ 5,
+ 11,
+ 571,
+ },
+ dictWord{135, 11, 1842},
+ dictWord{132, 11, 455},
+ dictWord{137, 0, 70},
+ dictWord{135, 0, 1405},
+ dictWord{7, 10, 135},
+ dictWord{8, 10, 7},
+ dictWord{
+ 8,
+ 10,
+ 62,
+ },
+ dictWord{9, 10, 243},
+ dictWord{10, 10, 658},
+ dictWord{10, 10, 697},
+ dictWord{11, 10, 456},
+ dictWord{139, 10, 756},
+ dictWord{9, 10, 395},
+ dictWord{138, 10, 79},
+ dictWord{137, 0, 108},
+ dictWord{6, 11, 161},
+ dictWord{7, 11, 372},
+ dictWord{137, 11, 597},
+ dictWord{132, 11, 349},
+ dictWord{
+ 132,
+ 0,
+ 777,
+ },
+ dictWord{132, 0, 331},
+ dictWord{135, 10, 631},
+ dictWord{133, 0, 747},
+ dictWord{6, 11, 432},
+ dictWord{6, 11, 608},
+ dictWord{139, 11, 322},
+ dictWord{138, 10, 835},
+ dictWord{5, 11, 468},
+ dictWord{7, 11, 1809},
+ dictWord{10, 11, 325},
+ dictWord{11, 11, 856},
+ dictWord{12, 11, 345},
+ dictWord{
+ 143,
+ 11,
+ 104,
+ },
+ dictWord{133, 11, 223},
+ dictWord{7, 10, 406},
+ dictWord{7, 10, 459},
+ dictWord{8, 10, 606},
+ dictWord{139, 10, 726},
+ dictWord{132, 11, 566},
+ dictWord{142, 0, 68},
+ dictWord{4, 11, 59},
+ dictWord{135, 11, 1394},
+ dictWord{6, 11, 436},
+ dictWord{139, 11, 481},
+ dictWord{4, 11, 48},
+ dictWord{5, 11, 271},
+ dictWord{135, 11, 953},
+ dictWord{139, 11, 170},
+ dictWord{5, 11, 610},
+ dictWord{136, 11, 457},
+ dictWord{133, 11, 755},
+ dictWord{135, 11, 1217},
+ dictWord{
+ 133,
+ 10,
+ 612,
+ },
+ dictWord{132, 11, 197},
+ dictWord{132, 0, 505},
+ dictWord{4, 10, 372},
+ dictWord{7, 10, 482},
+ dictWord{8, 10, 158},
+ dictWord{9, 10, 602},
+ dictWord{
+ 9,
+ 10,
+ 615,
+ },
+ dictWord{10, 10, 245},
+ dictWord{10, 10, 678},
+ dictWord{10, 10, 744},
+ dictWord{11, 10, 248},
+ dictWord{139, 10, 806},
+ dictWord{133, 0, 326},
+ dictWord{5, 10, 854},
+ dictWord{135, 10, 1991},
+ dictWord{4, 0, 691},
+ dictWord{146, 0, 16},
+ dictWord{6, 0, 628},
+ dictWord{9, 0, 35},
+ dictWord{10, 0, 680},
+ dictWord{10, 0, 793},
+ dictWord{11, 0, 364},
+ dictWord{13, 0, 357},
+ dictWord{143, 0, 164},
+ dictWord{138, 0, 654},
+ dictWord{6, 0, 32},
+ dictWord{7, 0, 385},
+ dictWord{
+ 7,
+ 0,
+ 757,
+ },
+ dictWord{7, 0, 1916},
+ dictWord{8, 0, 37},
+ dictWord{8, 0, 94},
+ dictWord{8, 0, 711},
+ dictWord{9, 0, 541},
+ dictWord{10, 0, 162},
+ dictWord{10, 0, 795},
+ dictWord{
+ 11,
+ 0,
+ 989,
+ },
+ dictWord{11, 0, 1010},
+ dictWord{12, 0, 14},
+ dictWord{142, 0, 308},
+ dictWord{133, 11, 217},
+ dictWord{6, 0, 152},
+ dictWord{6, 0, 349},
+ dictWord{
+ 6,
+ 0,
+ 1682,
+ },
+ dictWord{7, 0, 1252},
+ dictWord{8, 0, 112},
+ dictWord{9, 0, 435},
+ dictWord{9, 0, 668},
+ dictWord{10, 0, 290},
+ dictWord{10, 0, 319},
+ dictWord{10, 0, 815},
+ dictWord{11, 0, 180},
+ dictWord{11, 0, 837},
+ dictWord{12, 0, 240},
+ dictWord{13, 0, 152},
+ dictWord{13, 0, 219},
+ dictWord{142, 0, 158},
+ dictWord{4, 0, 581},
+ dictWord{134, 0, 726},
+ dictWord{5, 10, 195},
+ dictWord{135, 10, 1685},
+ dictWord{6, 0, 126},
+ dictWord{7, 0, 573},
+ dictWord{8, 0, 397},
+ dictWord{142, 0, 44},
+ dictWord{138, 0, 89},
+ dictWord{7, 10, 1997},
+ dictWord{8, 10, 730},
+ dictWord{139, 10, 1006},
+ dictWord{134, 0, 1531},
+ dictWord{134, 0, 1167},
+ dictWord{
+ 5,
+ 0,
+ 926,
+ },
+ dictWord{12, 0, 203},
+ dictWord{133, 10, 751},
+ dictWord{4, 11, 165},
+ dictWord{7, 11, 1398},
+ dictWord{135, 11, 1829},
+ dictWord{7, 0, 1232},
+ dictWord{137, 0, 531},
+ dictWord{135, 10, 821},
+ dictWord{134, 0, 943},
+ dictWord{133, 0, 670},
+ dictWord{4, 0, 880},
+ dictWord{139, 0, 231},
+ dictWord{
+ 134,
+ 0,
+ 1617,
+ },
+ dictWord{135, 0, 1957},
+ dictWord{5, 11, 9},
+ dictWord{7, 11, 297},
+ dictWord{7, 11, 966},
+ dictWord{140, 11, 306},
+ dictWord{6, 0, 975},
+ dictWord{
+ 134,
+ 0,
+ 985,
+ },
+ dictWord{5, 10, 950},
+ dictWord{5, 10, 994},
+ dictWord{134, 10, 351},
+ dictWord{12, 11, 21},
+ dictWord{151, 11, 7},
+ dictWord{5, 11, 146},
+ dictWord{
+ 6,
+ 11,
+ 411,
+ },
+ dictWord{138, 11, 721},
+ dictWord{7, 0, 242},
+ dictWord{135, 0, 1942},
+ dictWord{6, 11, 177},
+ dictWord{135, 11, 467},
+ dictWord{5, 0, 421},
+ dictWord{
+ 7,
+ 10,
+ 47,
+ },
+ dictWord{137, 10, 684},
+ dictWord{5, 0, 834},
+ dictWord{7, 0, 1202},
+ dictWord{8, 0, 14},
+ dictWord{9, 0, 481},
+ dictWord{137, 0, 880},
+ dictWord{138, 0, 465},
+ dictWord{6, 0, 688},
+ dictWord{9, 0, 834},
+ dictWord{132, 10, 350},
+ dictWord{132, 0, 855},
+ dictWord{4, 0, 357},
+ dictWord{6, 0, 172},
+ dictWord{7, 0, 143},
+ dictWord{137, 0, 413},
+ dictWord{133, 11, 200},
+ dictWord{132, 0, 590},
+ dictWord{7, 10, 1812},
+ dictWord{13, 10, 259},
+ dictWord{13, 10, 356},
+ dictWord{
+ 14,
+ 10,
+ 242,
+ },
+ dictWord{147, 10, 114},
+ dictWord{133, 10, 967},
+ dictWord{11, 0, 114},
+ dictWord{4, 10, 473},
+ dictWord{7, 10, 623},
+ dictWord{8, 10, 808},
+ dictWord{
+ 9,
+ 10,
+ 871,
+ },
+ dictWord{9, 10, 893},
+ dictWord{11, 10, 431},
+ dictWord{12, 10, 112},
+ dictWord{12, 10, 217},
+ dictWord{12, 10, 243},
+ dictWord{12, 10, 562},
+ dictWord{
+ 12,
+ 10,
+ 663,
+ },
+ dictWord{12, 10, 683},
+ dictWord{13, 10, 141},
+ dictWord{13, 10, 197},
+ dictWord{13, 10, 227},
+ dictWord{13, 10, 406},
+ dictWord{13, 10, 487},
+ dictWord{14, 10, 156},
+ dictWord{14, 10, 203},
+ dictWord{14, 10, 224},
+ dictWord{14, 10, 256},
+ dictWord{18, 10, 58},
+ dictWord{150, 10, 0},
+ dictWord{
+ 138,
+ 10,
+ 286,
+ },
+ dictWord{4, 10, 222},
+ dictWord{7, 10, 286},
+ dictWord{136, 10, 629},
+ dictWord{5, 0, 169},
+ dictWord{7, 0, 333},
+ dictWord{136, 0, 45},
+ dictWord{
+ 134,
+ 11,
+ 481,
+ },
+ dictWord{132, 0, 198},
+ dictWord{4, 0, 24},
+ dictWord{5, 0, 140},
+ dictWord{5, 0, 185},
+ dictWord{7, 0, 1500},
+ dictWord{11, 0, 565},
+ dictWord{11, 0, 838},
+ dictWord{4, 11, 84},
+ dictWord{7, 11, 1482},
+ dictWord{10, 11, 76},
+ dictWord{138, 11, 142},
+ dictWord{133, 0, 585},
+ dictWord{141, 10, 306},
+ dictWord{
+ 133,
+ 11,
+ 1015,
+ },
+ dictWord{4, 11, 315},
+ dictWord{5, 11, 507},
+ dictWord{135, 11, 1370},
+ dictWord{136, 10, 146},
+ dictWord{6, 0, 691},
+ dictWord{134, 0, 1503},
+ dictWord{
+ 4,
+ 0,
+ 334,
+ },
+ dictWord{133, 0, 593},
+ dictWord{4, 10, 465},
+ dictWord{135, 10, 1663},
+ dictWord{142, 11, 173},
+ dictWord{135, 0, 913},
+ dictWord{12, 0, 116},
+ dictWord{134, 11, 1722},
+ dictWord{134, 0, 1360},
+ dictWord{132, 0, 802},
+ dictWord{8, 11, 222},
+ dictWord{8, 11, 476},
+ dictWord{9, 11, 238},
+ dictWord{
+ 11,
+ 11,
+ 516,
+ },
+ dictWord{11, 11, 575},
+ dictWord{15, 11, 109},
+ dictWord{146, 11, 100},
+ dictWord{6, 0, 308},
+ dictWord{9, 0, 673},
+ dictWord{7, 10, 138},
+ dictWord{
+ 7,
+ 10,
+ 517,
+ },
+ dictWord{139, 10, 238},
+ dictWord{132, 0, 709},
+ dictWord{6, 0, 1876},
+ dictWord{6, 0, 1895},
+ dictWord{9, 0, 994},
+ dictWord{9, 0, 1006},
+ dictWord{
+ 12,
+ 0,
+ 829,
+ },
+ dictWord{12, 0, 888},
+ dictWord{12, 0, 891},
+ dictWord{146, 0, 185},
+ dictWord{148, 10, 94},
+ dictWord{4, 0, 228},
+ dictWord{133, 0, 897},
+ dictWord{
+ 7,
+ 0,
+ 1840,
+ },
+ dictWord{5, 10, 495},
+ dictWord{7, 10, 834},
+ dictWord{9, 10, 733},
+ dictWord{139, 10, 378},
+ dictWord{133, 10, 559},
+ dictWord{6, 10, 21},
+ dictWord{
+ 6,
+ 10,
+ 1737,
+ },
+ dictWord{7, 10, 1444},
+ dictWord{136, 10, 224},
+ dictWord{4, 0, 608},
+ dictWord{133, 0, 497},
+ dictWord{6, 11, 40},
+ dictWord{135, 11, 1781},
+ dictWord{134, 0, 1573},
+ dictWord{135, 0, 2039},
+ dictWord{6, 0, 540},
+ dictWord{136, 0, 136},
+ dictWord{4, 0, 897},
+ dictWord{5, 0, 786},
+ dictWord{133, 10, 519},
+ dictWord{6, 0, 1878},
+ dictWord{6, 0, 1884},
+ dictWord{9, 0, 938},
+ dictWord{9, 0, 948},
+ dictWord{9, 0, 955},
+ dictWord{9, 0, 973},
+ dictWord{9, 0, 1012},
+ dictWord{
+ 12,
+ 0,
+ 895,
+ },
+ dictWord{12, 0, 927},
+ dictWord{143, 0, 254},
+ dictWord{134, 0, 1469},
+ dictWord{133, 0, 999},
+ dictWord{4, 0, 299},
+ dictWord{135, 0, 1004},
+ dictWord{
+ 4,
+ 0,
+ 745,
+ },
+ dictWord{133, 0, 578},
+ dictWord{136, 11, 574},
+ dictWord{133, 0, 456},
+ dictWord{134, 0, 1457},
+ dictWord{7, 0, 1679},
+ dictWord{132, 10, 402},
+ dictWord{7, 0, 693},
+ dictWord{8, 0, 180},
+ dictWord{12, 0, 163},
+ dictWord{8, 10, 323},
+ dictWord{136, 10, 479},
+ dictWord{11, 10, 580},
+ dictWord{142, 10, 201},
+ dictWord{5, 10, 59},
+ dictWord{135, 10, 672},
+ dictWord{132, 11, 354},
+ dictWord{146, 10, 34},
+ dictWord{4, 0, 755},
+ dictWord{135, 11, 1558},
+ dictWord{
+ 7,
+ 0,
+ 1740,
+ },
+ dictWord{146, 0, 48},
+ dictWord{4, 10, 85},
+ dictWord{135, 10, 549},
+ dictWord{139, 0, 338},
+ dictWord{133, 10, 94},
+ dictWord{134, 0, 1091},
+ dictWord{135, 11, 469},
+ dictWord{12, 0, 695},
+ dictWord{12, 0, 704},
+ dictWord{20, 0, 113},
+ dictWord{5, 11, 830},
+ dictWord{14, 11, 338},
+ dictWord{148, 11, 81},
+ dictWord{135, 0, 1464},
+ dictWord{6, 10, 11},
+ dictWord{135, 10, 187},
+ dictWord{135, 0, 975},
+ dictWord{13, 0, 335},
+ dictWord{132, 10, 522},
+ dictWord{
+ 134,
+ 0,
+ 1979,
+ },
+ dictWord{5, 11, 496},
+ dictWord{135, 11, 203},
+ dictWord{4, 10, 52},
+ dictWord{135, 10, 661},
+ dictWord{7, 0, 1566},
+ dictWord{8, 0, 269},
+ dictWord{
+ 9,
+ 0,
+ 212,
+ },
+ dictWord{9, 0, 718},
+ dictWord{14, 0, 15},
+ dictWord{14, 0, 132},
+ dictWord{142, 0, 227},
+ dictWord{4, 0, 890},
+ dictWord{5, 0, 805},
+ dictWord{5, 0, 819},
+ dictWord{
+ 5,
+ 0,
+ 961,
+ },
+ dictWord{6, 0, 396},
+ dictWord{6, 0, 1631},
+ dictWord{6, 0, 1678},
+ dictWord{7, 0, 1967},
+ dictWord{7, 0, 2041},
+ dictWord{9, 0, 630},
+ dictWord{11, 0, 8},
+ dictWord{11, 0, 1019},
+ dictWord{12, 0, 176},
+ dictWord{13, 0, 225},
+ dictWord{14, 0, 292},
+ dictWord{21, 0, 24},
+ dictWord{4, 10, 383},
+ dictWord{133, 10, 520},
+ dictWord{134, 11, 547},
+ dictWord{135, 11, 1748},
+ dictWord{5, 11, 88},
+ dictWord{137, 11, 239},
+ dictWord{146, 11, 128},
+ dictWord{7, 11, 650},
+ dictWord{
+ 135,
+ 11,
+ 1310,
+ },
+ dictWord{4, 10, 281},
+ dictWord{5, 10, 38},
+ dictWord{7, 10, 194},
+ dictWord{7, 10, 668},
+ dictWord{7, 10, 1893},
+ dictWord{137, 10, 397},
+ dictWord{135, 0, 1815},
+ dictWord{9, 10, 635},
+ dictWord{139, 10, 559},
+ dictWord{7, 0, 1505},
+ dictWord{10, 0, 190},
+ dictWord{10, 0, 634},
+ dictWord{11, 0, 792},
+ dictWord{12, 0, 358},
+ dictWord{140, 0, 447},
+ dictWord{5, 0, 0},
+ dictWord{6, 0, 536},
+ dictWord{7, 0, 604},
+ dictWord{13, 0, 445},
+ dictWord{145, 0, 126},
+ dictWord{
+ 7,
+ 11,
+ 1076,
+ },
+ dictWord{9, 11, 80},
+ dictWord{11, 11, 78},
+ dictWord{11, 11, 421},
+ dictWord{11, 11, 534},
+ dictWord{140, 11, 545},
+ dictWord{8, 0, 966},
+ dictWord{
+ 10,
+ 0,
+ 1023,
+ },
+ dictWord{14, 11, 369},
+ dictWord{146, 11, 72},
+ dictWord{135, 11, 1641},
+ dictWord{6, 0, 232},
+ dictWord{6, 0, 412},
+ dictWord{7, 0, 1074},
+ dictWord{
+ 8,
+ 0,
+ 9,
+ },
+ dictWord{8, 0, 157},
+ dictWord{8, 0, 786},
+ dictWord{9, 0, 196},
+ dictWord{9, 0, 352},
+ dictWord{9, 0, 457},
+ dictWord{10, 0, 337},
+ dictWord{11, 0, 232},
+ dictWord{
+ 11,
+ 0,
+ 877,
+ },
+ dictWord{12, 0, 480},
+ dictWord{140, 0, 546},
+ dictWord{135, 0, 958},
+ dictWord{4, 0, 382},
+ dictWord{136, 0, 579},
+ dictWord{4, 0, 212},
+ dictWord{
+ 135,
+ 0,
+ 1206,
+ },
+ dictWord{4, 11, 497},
+ dictWord{5, 11, 657},
+ dictWord{135, 11, 1584},
+ dictWord{132, 0, 681},
+ dictWord{8, 0, 971},
+ dictWord{138, 0, 965},
+ dictWord{
+ 5,
+ 10,
+ 448,
+ },
+ dictWord{136, 10, 535},
+ dictWord{14, 0, 16},
+ dictWord{146, 0, 44},
+ dictWord{11, 0, 584},
+ dictWord{11, 0, 616},
+ dictWord{14, 0, 275},
+ dictWord{
+ 11,
+ 11,
+ 584,
+ },
+ dictWord{11, 11, 616},
+ dictWord{142, 11, 275},
+ dictWord{136, 11, 13},
+ dictWord{7, 10, 610},
+ dictWord{135, 10, 1501},
+ dictWord{7, 11, 642},
+ dictWord{8, 11, 250},
+ dictWord{11, 11, 123},
+ dictWord{11, 11, 137},
+ dictWord{13, 11, 48},
+ dictWord{142, 11, 95},
+ dictWord{133, 0, 655},
+ dictWord{17, 0, 67},
+ dictWord{147, 0, 74},
+ dictWord{134, 0, 751},
+ dictWord{134, 0, 1967},
+ dictWord{6, 0, 231},
+ dictWord{136, 0, 423},
+ dictWord{5, 0, 300},
+ dictWord{138, 0, 1016},
+ dictWord{4, 10, 319},
+ dictWord{5, 10, 699},
+ dictWord{138, 10, 673},
+ dictWord{6, 0, 237},
+ dictWord{7, 0, 611},
+ dictWord{8, 0, 100},
+ dictWord{9, 0, 416},
+ dictWord{
+ 11,
+ 0,
+ 335,
+ },
+ dictWord{12, 0, 173},
+ dictWord{18, 0, 101},
+ dictWord{6, 10, 336},
+ dictWord{8, 10, 552},
+ dictWord{9, 10, 285},
+ dictWord{10, 10, 99},
+ dictWord{
+ 139,
+ 10,
+ 568,
+ },
+ dictWord{134, 0, 1370},
+ dictWord{7, 10, 1406},
+ dictWord{9, 10, 218},
+ dictWord{141, 10, 222},
+ dictWord{133, 10, 256},
+ dictWord{
+ 135,
+ 0,
+ 1208,
+ },
+ dictWord{14, 11, 213},
+ dictWord{148, 11, 38},
+ dictWord{6, 0, 1219},
+ dictWord{135, 11, 1642},
+ dictWord{13, 0, 417},
+ dictWord{14, 0, 129},
+ dictWord{143, 0, 15},
+ dictWord{10, 11, 545},
+ dictWord{140, 11, 301},
+ dictWord{17, 10, 39},
+ dictWord{148, 10, 36},
+ dictWord{133, 0, 199},
+ dictWord{4, 11, 904},
+ dictWord{133, 11, 794},
+ dictWord{12, 0, 427},
+ dictWord{146, 0, 38},
+ dictWord{134, 0, 949},
+ dictWord{8, 0, 665},
+ dictWord{135, 10, 634},
+ dictWord{
+ 132,
+ 10,
+ 618,
+ },
+ dictWord{135, 10, 259},
+ dictWord{132, 10, 339},
+ dictWord{133, 11, 761},
+ dictWord{141, 10, 169},
+ dictWord{132, 10, 759},
+ dictWord{5, 0, 688},
+ dictWord{7, 0, 539},
+ dictWord{135, 0, 712},
+ dictWord{7, 11, 386},
+ dictWord{138, 11, 713},
+ dictWord{134, 0, 1186},
+ dictWord{6, 11, 7},
+ dictWord{6, 11, 35},
+ dictWord{
+ 7,
+ 11,
+ 147,
+ },
+ dictWord{7, 11, 1069},
+ dictWord{7, 11, 1568},
+ dictWord{7, 11, 1575},
+ dictWord{7, 11, 1917},
+ dictWord{8, 11, 43},
+ dictWord{8, 11, 208},
+ dictWord{
+ 9,
+ 11,
+ 128,
+ },
+ dictWord{9, 11, 866},
+ dictWord{10, 11, 20},
+ dictWord{11, 11, 981},
+ dictWord{147, 11, 33},
+ dictWord{7, 11, 893},
+ dictWord{8, 10, 482},
+ dictWord{141, 11, 424},
+ dictWord{6, 0, 312},
+ dictWord{6, 0, 1715},
+ dictWord{10, 0, 584},
+ dictWord{11, 0, 546},
+ dictWord{11, 0, 692},
+ dictWord{12, 0, 259},
+ dictWord{
+ 12,
+ 0,
+ 295,
+ },
+ dictWord{13, 0, 46},
+ dictWord{141, 0, 154},
+ dictWord{5, 10, 336},
+ dictWord{6, 10, 341},
+ dictWord{6, 10, 478},
+ dictWord{6, 10, 1763},
+ dictWord{
+ 136,
+ 10,
+ 386,
+ },
+ dictWord{137, 0, 151},
+ dictWord{132, 0, 588},
+ dictWord{152, 0, 4},
+ dictWord{6, 11, 322},
+ dictWord{9, 11, 552},
+ dictWord{11, 11, 274},
+ dictWord{
+ 13,
+ 11,
+ 209,
+ },
+ dictWord{13, 11, 499},
+ dictWord{14, 11, 85},
+ dictWord{15, 11, 126},
+ dictWord{145, 11, 70},
+ dictWord{135, 10, 73},
+ dictWord{4, 0, 231},
+ dictWord{
+ 5,
+ 0,
+ 61,
+ },
+ dictWord{6, 0, 104},
+ dictWord{7, 0, 729},
+ dictWord{7, 0, 964},
+ dictWord{7, 0, 1658},
+ dictWord{140, 0, 414},
+ dictWord{6, 0, 263},
+ dictWord{138, 0, 757},
+ dictWord{135, 10, 1971},
+ dictWord{4, 0, 612},
+ dictWord{133, 0, 561},
+ dictWord{132, 0, 320},
+ dictWord{135, 10, 1344},
+ dictWord{8, 11, 83},
+ dictWord{
+ 8,
+ 11,
+ 817,
+ },
+ dictWord{9, 11, 28},
+ dictWord{9, 11, 29},
+ dictWord{9, 11, 885},
+ dictWord{10, 11, 387},
+ dictWord{11, 11, 633},
+ dictWord{11, 11, 740},
+ dictWord{
+ 13,
+ 11,
+ 235,
+ },
+ dictWord{13, 11, 254},
+ dictWord{15, 11, 143},
+ dictWord{143, 11, 146},
+ dictWord{5, 10, 396},
+ dictWord{134, 10, 501},
+ dictWord{140, 11, 49},
+ dictWord{132, 0, 225},
+ dictWord{4, 10, 929},
+ dictWord{5, 10, 799},
+ dictWord{8, 10, 46},
+ dictWord{136, 10, 740},
+ dictWord{4, 0, 405},
+ dictWord{7, 0, 817},
+ dictWord{
+ 14,
+ 0,
+ 58,
+ },
+ dictWord{17, 0, 37},
+ dictWord{146, 0, 124},
+ dictWord{133, 0, 974},
+ dictWord{4, 11, 412},
+ dictWord{133, 11, 581},
+ dictWord{4, 10, 892},
+ dictWord{
+ 133,
+ 10,
+ 770,
+ },
+ dictWord{4, 0, 996},
+ dictWord{134, 0, 2026},
+ dictWord{4, 0, 527},
+ dictWord{5, 0, 235},
+ dictWord{7, 0, 1239},
+ dictWord{11, 0, 131},
+ dictWord{
+ 140,
+ 0,
+ 370,
+ },
+ dictWord{9, 0, 16},
+ dictWord{13, 0, 386},
+ dictWord{135, 11, 421},
+ dictWord{7, 0, 956},
+ dictWord{7, 0, 1157},
+ dictWord{7, 0, 1506},
+ dictWord{7, 0, 1606},
+ dictWord{7, 0, 1615},
+ dictWord{7, 0, 1619},
+ dictWord{7, 0, 1736},
+ dictWord{7, 0, 1775},
+ dictWord{8, 0, 590},
+ dictWord{9, 0, 324},
+ dictWord{9, 0, 736},
+ dictWord{
+ 9,
+ 0,
+ 774,
+ },
+ dictWord{9, 0, 776},
+ dictWord{9, 0, 784},
+ dictWord{10, 0, 567},
+ dictWord{10, 0, 708},
+ dictWord{11, 0, 518},
+ dictWord{11, 0, 613},
+ dictWord{11, 0, 695},
+ dictWord{11, 0, 716},
+ dictWord{11, 0, 739},
+ dictWord{11, 0, 770},
+ dictWord{11, 0, 771},
+ dictWord{11, 0, 848},
+ dictWord{11, 0, 857},
+ dictWord{11, 0, 931},
+ dictWord{
+ 11,
+ 0,
+ 947,
+ },
+ dictWord{12, 0, 326},
+ dictWord{12, 0, 387},
+ dictWord{12, 0, 484},
+ dictWord{12, 0, 528},
+ dictWord{12, 0, 552},
+ dictWord{12, 0, 613},
+ dictWord{
+ 13,
+ 0,
+ 189,
+ },
+ dictWord{13, 0, 256},
+ dictWord{13, 0, 340},
+ dictWord{13, 0, 432},
+ dictWord{13, 0, 436},
+ dictWord{13, 0, 440},
+ dictWord{13, 0, 454},
+ dictWord{14, 0, 174},
+ dictWord{14, 0, 220},
+ dictWord{14, 0, 284},
+ dictWord{14, 0, 390},
+ dictWord{145, 0, 121},
+ dictWord{135, 10, 158},
+ dictWord{9, 0, 137},
+ dictWord{138, 0, 221},
+ dictWord{4, 11, 110},
+ dictWord{10, 11, 415},
+ dictWord{10, 11, 597},
+ dictWord{142, 11, 206},
+ dictWord{141, 11, 496},
+ dictWord{135, 11, 205},
+ dictWord{
+ 151,
+ 10,
+ 25,
+ },
+ dictWord{135, 11, 778},
+ dictWord{7, 11, 1656},
+ dictWord{7, 10, 2001},
+ dictWord{9, 11, 369},
+ dictWord{10, 11, 338},
+ dictWord{10, 11, 490},
+ dictWord{11, 11, 154},
+ dictWord{11, 11, 545},
+ dictWord{11, 11, 775},
+ dictWord{13, 11, 77},
+ dictWord{141, 11, 274},
+ dictWord{4, 11, 444},
+ dictWord{
+ 10,
+ 11,
+ 146,
+ },
+ dictWord{140, 11, 9},
+ dictWord{7, 0, 390},
+ dictWord{138, 0, 140},
+ dictWord{135, 0, 1144},
+ dictWord{134, 0, 464},
+ dictWord{7, 10, 1461},
+ dictWord{
+ 140,
+ 10,
+ 91,
+ },
+ dictWord{132, 10, 602},
+ dictWord{4, 11, 283},
+ dictWord{135, 11, 1194},
+ dictWord{5, 0, 407},
+ dictWord{11, 0, 204},
+ dictWord{11, 0, 243},
+ dictWord{
+ 11,
+ 0,
+ 489,
+ },
+ dictWord{12, 0, 293},
+ dictWord{19, 0, 37},
+ dictWord{20, 0, 73},
+ dictWord{150, 0, 38},
+ dictWord{7, 0, 1218},
+ dictWord{136, 0, 303},
+ dictWord{
+ 5,
+ 0,
+ 325,
+ },
+ dictWord{8, 0, 5},
+ dictWord{8, 0, 227},
+ dictWord{9, 0, 105},
+ dictWord{10, 0, 585},
+ dictWord{12, 0, 614},
+ dictWord{4, 10, 13},
+ dictWord{5, 10, 567},
+ dictWord{
+ 7,
+ 10,
+ 1498,
+ },
+ dictWord{9, 10, 124},
+ dictWord{11, 10, 521},
+ dictWord{140, 10, 405},
+ dictWord{135, 10, 1006},
+ dictWord{7, 0, 800},
+ dictWord{10, 0, 12},
+ dictWord{134, 11, 1720},
+ dictWord{135, 0, 1783},
+ dictWord{132, 10, 735},
+ dictWord{138, 10, 812},
+ dictWord{4, 10, 170},
+ dictWord{135, 10, 323},
+ dictWord{
+ 6,
+ 0,
+ 621,
+ },
+ dictWord{13, 0, 504},
+ dictWord{144, 0, 89},
+ dictWord{5, 10, 304},
+ dictWord{135, 10, 1403},
+ dictWord{137, 11, 216},
+ dictWord{6, 0, 920},
+ dictWord{
+ 6,
+ 0,
+ 1104,
+ },
+ dictWord{9, 11, 183},
+ dictWord{139, 11, 286},
+ dictWord{4, 0, 376},
+ dictWord{133, 10, 742},
+ dictWord{134, 0, 218},
+ dictWord{8, 0, 641},
+ dictWord{
+ 11,
+ 0,
+ 388,
+ },
+ dictWord{140, 0, 580},
+ dictWord{7, 0, 454},
+ dictWord{7, 0, 782},
+ dictWord{8, 0, 768},
+ dictWord{140, 0, 686},
+ dictWord{137, 11, 33},
+ dictWord{
+ 133,
+ 10,
+ 111,
+ },
+ dictWord{144, 0, 0},
+ dictWord{10, 0, 676},
+ dictWord{140, 0, 462},
+ dictWord{6, 0, 164},
+ dictWord{136, 11, 735},
+ dictWord{133, 10, 444},
+ dictWord{
+ 150,
+ 0,
+ 50,
+ },
+ dictWord{7, 11, 1862},
+ dictWord{12, 11, 491},
+ dictWord{12, 11, 520},
+ dictWord{13, 11, 383},
+ dictWord{14, 11, 244},
+ dictWord{146, 11, 12},
+ dictWord{
+ 5,
+ 11,
+ 132,
+ },
+ dictWord{9, 11, 486},
+ dictWord{9, 11, 715},
+ dictWord{10, 11, 458},
+ dictWord{11, 11, 373},
+ dictWord{11, 11, 668},
+ dictWord{11, 11, 795},
+ dictWord{11, 11, 897},
+ dictWord{12, 11, 272},
+ dictWord{12, 11, 424},
+ dictWord{12, 11, 539},
+ dictWord{12, 11, 558},
+ dictWord{14, 11, 245},
+ dictWord{
+ 14,
+ 11,
+ 263,
+ },
+ dictWord{14, 11, 264},
+ dictWord{14, 11, 393},
+ dictWord{142, 11, 403},
+ dictWord{8, 10, 123},
+ dictWord{15, 10, 6},
+ dictWord{144, 10, 7},
+ dictWord{
+ 6,
+ 0,
+ 285,
+ },
+ dictWord{8, 0, 654},
+ dictWord{11, 0, 749},
+ dictWord{12, 0, 190},
+ dictWord{12, 0, 327},
+ dictWord{13, 0, 120},
+ dictWord{13, 0, 121},
+ dictWord{13, 0, 327},
+ dictWord{15, 0, 47},
+ dictWord{146, 0, 40},
+ dictWord{5, 11, 8},
+ dictWord{6, 11, 89},
+ dictWord{6, 11, 400},
+ dictWord{7, 11, 1569},
+ dictWord{7, 11, 1623},
+ dictWord{
+ 7,
+ 11,
+ 1850,
+ },
+ dictWord{8, 11, 218},
+ dictWord{8, 11, 422},
+ dictWord{9, 11, 570},
+ dictWord{138, 11, 626},
+ dictWord{6, 11, 387},
+ dictWord{7, 11, 882},
+ dictWord{141, 11, 111},
+ dictWord{6, 0, 343},
+ dictWord{7, 0, 195},
+ dictWord{9, 0, 226},
+ dictWord{10, 0, 197},
+ dictWord{10, 0, 575},
+ dictWord{11, 0, 502},
+ dictWord{
+ 11,
+ 0,
+ 899,
+ },
+ dictWord{6, 11, 224},
+ dictWord{7, 11, 877},
+ dictWord{137, 11, 647},
+ dictWord{5, 10, 937},
+ dictWord{135, 10, 100},
+ dictWord{135, 11, 790},
+ dictWord{150, 0, 29},
+ dictWord{147, 0, 8},
+ dictWord{134, 0, 1812},
+ dictWord{149, 0, 8},
+ dictWord{135, 11, 394},
+ dictWord{7, 0, 1125},
+ dictWord{9, 0, 143},
+ dictWord{
+ 11,
+ 0,
+ 61,
+ },
+ dictWord{14, 0, 405},
+ dictWord{150, 0, 21},
+ dictWord{10, 11, 755},
+ dictWord{147, 11, 29},
+ dictWord{9, 11, 378},
+ dictWord{141, 11, 162},
+ dictWord{135, 10, 922},
+ dictWord{5, 10, 619},
+ dictWord{133, 10, 698},
+ dictWord{134, 0, 1327},
+ dictWord{6, 0, 1598},
+ dictWord{137, 0, 575},
+ dictWord{
+ 9,
+ 11,
+ 569,
+ },
+ dictWord{12, 11, 12},
+ dictWord{12, 11, 81},
+ dictWord{12, 11, 319},
+ dictWord{13, 11, 69},
+ dictWord{14, 11, 259},
+ dictWord{16, 11, 87},
+ dictWord{
+ 17,
+ 11,
+ 1,
+ },
+ dictWord{17, 11, 21},
+ dictWord{17, 11, 24},
+ dictWord{18, 11, 15},
+ dictWord{18, 11, 56},
+ dictWord{18, 11, 59},
+ dictWord{18, 11, 127},
+ dictWord{18, 11, 154},
+ dictWord{19, 11, 19},
+ dictWord{148, 11, 31},
+ dictWord{6, 0, 895},
+ dictWord{135, 11, 1231},
+ dictWord{5, 0, 959},
+ dictWord{7, 11, 124},
+ dictWord{136, 11, 38},
+ dictWord{5, 11, 261},
+ dictWord{7, 11, 78},
+ dictWord{7, 11, 199},
+ dictWord{8, 11, 815},
+ dictWord{9, 11, 126},
+ dictWord{138, 11, 342},
+ dictWord{5, 10, 917},
+ dictWord{134, 10, 1659},
+ dictWord{7, 0, 1759},
+ dictWord{5, 11, 595},
+ dictWord{135, 11, 1863},
+ dictWord{136, 0, 173},
+ dictWord{134, 0, 266},
+ dictWord{
+ 142,
+ 0,
+ 261,
+ },
+ dictWord{132, 11, 628},
+ dictWord{5, 10, 251},
+ dictWord{5, 10, 956},
+ dictWord{8, 10, 268},
+ dictWord{9, 10, 214},
+ dictWord{146, 10, 142},
+ dictWord{
+ 7,
+ 11,
+ 266,
+ },
+ dictWord{136, 11, 804},
+ dictWord{135, 11, 208},
+ dictWord{6, 11, 79},
+ dictWord{7, 11, 1021},
+ dictWord{135, 11, 1519},
+ dictWord{11, 11, 704},
+ dictWord{141, 11, 396},
+ dictWord{5, 10, 346},
+ dictWord{5, 10, 711},
+ dictWord{136, 10, 390},
+ dictWord{136, 11, 741},
+ dictWord{134, 11, 376},
+ dictWord{
+ 134,
+ 0,
+ 1427,
+ },
+ dictWord{6, 0, 1033},
+ dictWord{6, 0, 1217},
+ dictWord{136, 0, 300},
+ dictWord{133, 10, 624},
+ dictWord{6, 11, 100},
+ dictWord{7, 11, 244},
+ dictWord{
+ 7,
+ 11,
+ 632,
+ },
+ dictWord{7, 11, 1609},
+ dictWord{8, 11, 178},
+ dictWord{8, 11, 638},
+ dictWord{141, 11, 58},
+ dictWord{6, 0, 584},
+ dictWord{5, 10, 783},
+ dictWord{
+ 7,
+ 10,
+ 1998,
+ },
+ dictWord{135, 10, 2047},
+ dictWord{5, 0, 427},
+ dictWord{5, 0, 734},
+ dictWord{7, 0, 478},
+ dictWord{136, 0, 52},
+ dictWord{7, 0, 239},
+ dictWord{
+ 11,
+ 0,
+ 217,
+ },
+ dictWord{142, 0, 165},
+ dictWord{134, 0, 1129},
+ dictWord{6, 0, 168},
+ dictWord{6, 0, 1734},
+ dictWord{7, 0, 20},
+ dictWord{7, 0, 1056},
+ dictWord{8, 0, 732},
+ dictWord{9, 0, 406},
+ dictWord{9, 0, 911},
+ dictWord{138, 0, 694},
+ dictWord{132, 10, 594},
+ dictWord{133, 11, 791},
+ dictWord{7, 11, 686},
+ dictWord{8, 11, 33},
+ dictWord{8, 11, 238},
+ dictWord{10, 11, 616},
+ dictWord{11, 11, 467},
+ dictWord{11, 11, 881},
+ dictWord{13, 11, 217},
+ dictWord{13, 11, 253},
+ dictWord{
+ 142,
+ 11,
+ 268,
+ },
+ dictWord{137, 11, 476},
+ dictWord{134, 0, 418},
+ dictWord{133, 0, 613},
+ dictWord{132, 0, 632},
+ dictWord{132, 11, 447},
+ dictWord{7, 0, 32},
+ dictWord{
+ 7,
+ 0,
+ 984,
+ },
+ dictWord{8, 0, 85},
+ dictWord{8, 0, 709},
+ dictWord{9, 0, 579},
+ dictWord{9, 0, 847},
+ dictWord{9, 0, 856},
+ dictWord{10, 0, 799},
+ dictWord{11, 0, 258},
+ dictWord{
+ 11,
+ 0,
+ 1007,
+ },
+ dictWord{12, 0, 331},
+ dictWord{12, 0, 615},
+ dictWord{13, 0, 188},
+ dictWord{13, 0, 435},
+ dictWord{14, 0, 8},
+ dictWord{15, 0, 165},
+ dictWord{
+ 16,
+ 0,
+ 27,
+ },
+ dictWord{20, 0, 40},
+ dictWord{144, 11, 35},
+ dictWord{4, 11, 128},
+ dictWord{5, 11, 415},
+ dictWord{6, 11, 462},
+ dictWord{7, 11, 294},
+ dictWord{7, 11, 578},
+ dictWord{10, 11, 710},
+ dictWord{139, 11, 86},
+ dictWord{5, 0, 694},
+ dictWord{136, 0, 909},
+ dictWord{7, 0, 1109},
+ dictWord{11, 0, 7},
+ dictWord{5, 10, 37},
+ dictWord{
+ 6,
+ 10,
+ 39,
+ },
+ dictWord{6, 10, 451},
+ dictWord{7, 10, 218},
+ dictWord{7, 10, 1166},
+ dictWord{7, 10, 1687},
+ dictWord{8, 10, 662},
+ dictWord{144, 10, 2},
+ dictWord{
+ 136,
+ 11,
+ 587,
+ },
+ dictWord{6, 11, 427},
+ dictWord{7, 11, 1018},
+ dictWord{138, 11, 692},
+ dictWord{4, 11, 195},
+ dictWord{6, 10, 508},
+ dictWord{135, 11, 802},
+ dictWord{4, 0, 167},
+ dictWord{135, 0, 82},
+ dictWord{5, 0, 62},
+ dictWord{6, 0, 24},
+ dictWord{6, 0, 534},
+ dictWord{7, 0, 74},
+ dictWord{7, 0, 678},
+ dictWord{7, 0, 684},
+ dictWord{
+ 7,
+ 0,
+ 1043,
+ },
+ dictWord{7, 0, 1072},
+ dictWord{8, 0, 280},
+ dictWord{8, 0, 541},
+ dictWord{8, 0, 686},
+ dictWord{9, 0, 258},
+ dictWord{10, 0, 519},
+ dictWord{11, 0, 252},
+ dictWord{140, 0, 282},
+ dictWord{138, 0, 33},
+ dictWord{4, 0, 359},
+ dictWord{133, 11, 738},
+ dictWord{7, 0, 980},
+ dictWord{9, 0, 328},
+ dictWord{13, 0, 186},
+ dictWord{13, 0, 364},
+ dictWord{7, 10, 635},
+ dictWord{7, 10, 796},
+ dictWord{8, 10, 331},
+ dictWord{9, 10, 330},
+ dictWord{9, 10, 865},
+ dictWord{10, 10, 119},
+ dictWord{
+ 10,
+ 10,
+ 235,
+ },
+ dictWord{11, 10, 111},
+ dictWord{11, 10, 129},
+ dictWord{11, 10, 240},
+ dictWord{12, 10, 31},
+ dictWord{12, 10, 66},
+ dictWord{12, 10, 222},
+ dictWord{12, 10, 269},
+ dictWord{12, 10, 599},
+ dictWord{12, 10, 684},
+ dictWord{12, 10, 689},
+ dictWord{12, 10, 691},
+ dictWord{142, 10, 345},
+ dictWord{
+ 137,
+ 10,
+ 527,
+ },
+ dictWord{6, 0, 596},
+ dictWord{7, 0, 585},
+ dictWord{135, 10, 702},
+ dictWord{134, 11, 1683},
+ dictWord{133, 0, 211},
+ dictWord{6, 0, 145},
+ dictWord{
+ 141,
+ 0,
+ 336,
+ },
+ dictWord{134, 0, 1130},
+ dictWord{7, 0, 873},
+ dictWord{6, 10, 37},
+ dictWord{7, 10, 1666},
+ dictWord{8, 10, 195},
+ dictWord{8, 10, 316},
+ dictWord{
+ 9,
+ 10,
+ 178,
+ },
+ dictWord{9, 10, 276},
+ dictWord{9, 10, 339},
+ dictWord{9, 10, 536},
+ dictWord{10, 10, 102},
+ dictWord{10, 10, 362},
+ dictWord{10, 10, 785},
+ dictWord{
+ 11,
+ 10,
+ 55,
+ },
+ dictWord{11, 10, 149},
+ dictWord{11, 10, 773},
+ dictWord{13, 10, 416},
+ dictWord{13, 10, 419},
+ dictWord{14, 10, 38},
+ dictWord{14, 10, 41},
+ dictWord{
+ 142,
+ 10,
+ 210,
+ },
+ dictWord{8, 0, 840},
+ dictWord{136, 0, 841},
+ dictWord{132, 0, 263},
+ dictWord{5, 11, 3},
+ dictWord{8, 11, 578},
+ dictWord{9, 11, 118},
+ dictWord{
+ 10,
+ 11,
+ 705,
+ },
+ dictWord{12, 11, 383},
+ dictWord{141, 11, 279},
+ dictWord{132, 0, 916},
+ dictWord{133, 11, 229},
+ dictWord{133, 10, 645},
+ dictWord{15, 0, 155},
+ dictWord{16, 0, 79},
+ dictWord{8, 11, 102},
+ dictWord{10, 11, 578},
+ dictWord{10, 11, 672},
+ dictWord{12, 11, 496},
+ dictWord{13, 11, 408},
+ dictWord{14, 11, 121},
+ dictWord{145, 11, 106},
+ dictWord{4, 0, 599},
+ dictWord{5, 0, 592},
+ dictWord{6, 0, 1634},
+ dictWord{7, 0, 5},
+ dictWord{7, 0, 55},
+ dictWord{7, 0, 67},
+ dictWord{7, 0, 97},
+ dictWord{7, 0, 691},
+ dictWord{7, 0, 979},
+ dictWord{7, 0, 1600},
+ dictWord{7, 0, 1697},
+ dictWord{8, 0, 207},
+ dictWord{8, 0, 214},
+ dictWord{8, 0, 231},
+ dictWord{8, 0, 294},
+ dictWord{8, 0, 336},
+ dictWord{8, 0, 428},
+ dictWord{8, 0, 471},
+ dictWord{8, 0, 622},
+ dictWord{8, 0, 626},
+ dictWord{8, 0, 679},
+ dictWord{8, 0, 759},
+ dictWord{8, 0, 829},
+ dictWord{9, 0, 11},
+ dictWord{9, 0, 246},
+ dictWord{9, 0, 484},
+ dictWord{9, 0, 573},
+ dictWord{9, 0, 706},
+ dictWord{9, 0, 762},
+ dictWord{9, 0, 798},
+ dictWord{9, 0, 855},
+ dictWord{9, 0, 870},
+ dictWord{9, 0, 912},
+ dictWord{10, 0, 303},
+ dictWord{10, 0, 335},
+ dictWord{10, 0, 424},
+ dictWord{10, 0, 461},
+ dictWord{10, 0, 543},
+ dictWord{
+ 10,
+ 0,
+ 759,
+ },
+ dictWord{10, 0, 814},
+ dictWord{11, 0, 59},
+ dictWord{11, 0, 199},
+ dictWord{11, 0, 235},
+ dictWord{11, 0, 590},
+ dictWord{11, 0, 631},
+ dictWord{11, 0, 929},
+ dictWord{11, 0, 963},
+ dictWord{11, 0, 987},
+ dictWord{12, 0, 114},
+ dictWord{12, 0, 182},
+ dictWord{12, 0, 226},
+ dictWord{12, 0, 332},
+ dictWord{12, 0, 439},
+ dictWord{12, 0, 575},
+ dictWord{12, 0, 598},
+ dictWord{12, 0, 675},
+ dictWord{13, 0, 8},
+ dictWord{13, 0, 125},
+ dictWord{13, 0, 194},
+ dictWord{13, 0, 287},
+ dictWord{
+ 14,
+ 0,
+ 197,
+ },
+ dictWord{14, 0, 383},
+ dictWord{15, 0, 53},
+ dictWord{17, 0, 63},
+ dictWord{19, 0, 46},
+ dictWord{19, 0, 98},
+ dictWord{19, 0, 106},
+ dictWord{148, 0, 85},
+ dictWord{
+ 7,
+ 0,
+ 1356,
+ },
+ dictWord{132, 10, 290},
+ dictWord{6, 10, 70},
+ dictWord{7, 10, 1292},
+ dictWord{10, 10, 762},
+ dictWord{139, 10, 288},
+ dictWord{150, 11, 55},
+ dictWord{4, 0, 593},
+ dictWord{8, 11, 115},
+ dictWord{8, 11, 350},
+ dictWord{9, 11, 489},
+ dictWord{10, 11, 128},
+ dictWord{11, 11, 306},
+ dictWord{12, 11, 373},
+ dictWord{14, 11, 30},
+ dictWord{17, 11, 79},
+ dictWord{147, 11, 80},
+ dictWord{135, 11, 1235},
+ dictWord{134, 0, 1392},
+ dictWord{4, 11, 230},
+ dictWord{
+ 133,
+ 11,
+ 702,
+ },
+ dictWord{147, 0, 126},
+ dictWord{7, 10, 131},
+ dictWord{7, 10, 422},
+ dictWord{8, 10, 210},
+ dictWord{140, 10, 573},
+ dictWord{134, 0, 1179},
+ dictWord{
+ 139,
+ 11,
+ 435,
+ },
+ dictWord{139, 10, 797},
+ dictWord{134, 11, 1728},
+ dictWord{4, 0, 162},
+ dictWord{18, 11, 26},
+ dictWord{19, 11, 42},
+ dictWord{20, 11, 43},
+ dictWord{21, 11, 0},
+ dictWord{23, 11, 27},
+ dictWord{152, 11, 14},
+ dictWord{132, 10, 936},
+ dictWord{6, 0, 765},
+ dictWord{5, 10, 453},
+ dictWord{134, 10, 441},
+ dictWord{133, 0, 187},
+ dictWord{135, 0, 1286},
+ dictWord{6, 0, 635},
+ dictWord{6, 0, 904},
+ dictWord{6, 0, 1210},
+ dictWord{134, 0, 1489},
+ dictWord{4, 0, 215},
+ dictWord{
+ 8,
+ 0,
+ 890,
+ },
+ dictWord{9, 0, 38},
+ dictWord{10, 0, 923},
+ dictWord{11, 0, 23},
+ dictWord{11, 0, 127},
+ dictWord{139, 0, 796},
+ dictWord{6, 0, 1165},
+ dictWord{
+ 134,
+ 0,
+ 1306,
+ },
+ dictWord{7, 0, 716},
+ dictWord{13, 0, 97},
+ dictWord{141, 0, 251},
+ dictWord{132, 10, 653},
+ dictWord{136, 0, 657},
+ dictWord{146, 10, 80},
+ dictWord{
+ 5,
+ 11,
+ 622,
+ },
+ dictWord{7, 11, 1032},
+ dictWord{11, 11, 26},
+ dictWord{11, 11, 213},
+ dictWord{11, 11, 707},
+ dictWord{12, 11, 380},
+ dictWord{13, 11, 226},
+ dictWord{141, 11, 355},
+ dictWord{6, 0, 299},
+ dictWord{5, 11, 70},
+ dictWord{6, 11, 334},
+ dictWord{9, 11, 171},
+ dictWord{11, 11, 637},
+ dictWord{12, 11, 202},
+ dictWord{14, 11, 222},
+ dictWord{145, 11, 42},
+ dictWord{142, 0, 134},
+ dictWord{4, 11, 23},
+ dictWord{5, 11, 313},
+ dictWord{5, 11, 1014},
+ dictWord{6, 11, 50},
+ dictWord{
+ 6,
+ 11,
+ 51,
+ },
+ dictWord{7, 11, 142},
+ dictWord{7, 11, 384},
+ dictWord{9, 11, 783},
+ dictWord{139, 11, 741},
+ dictWord{4, 11, 141},
+ dictWord{7, 11, 559},
+ dictWord{
+ 8,
+ 11,
+ 640,
+ },
+ dictWord{9, 11, 460},
+ dictWord{12, 11, 183},
+ dictWord{141, 11, 488},
+ dictWord{136, 11, 614},
+ dictWord{7, 10, 1368},
+ dictWord{8, 10, 232},
+ dictWord{8, 10, 361},
+ dictWord{10, 10, 682},
+ dictWord{138, 10, 742},
+ dictWord{137, 10, 534},
+ dictWord{6, 0, 1082},
+ dictWord{140, 0, 658},
+ dictWord{
+ 137,
+ 10,
+ 27,
+ },
+ dictWord{135, 0, 2002},
+ dictWord{142, 10, 12},
+ dictWord{4, 0, 28},
+ dictWord{5, 0, 440},
+ dictWord{7, 0, 248},
+ dictWord{11, 0, 833},
+ dictWord{140, 0, 344},
+ dictWord{7, 10, 736},
+ dictWord{139, 10, 264},
+ dictWord{134, 10, 1657},
+ dictWord{134, 0, 1654},
+ dictWord{138, 0, 531},
+ dictWord{5, 11, 222},
+ dictWord{
+ 9,
+ 11,
+ 140,
+ },
+ dictWord{138, 11, 534},
+ dictWord{6, 0, 634},
+ dictWord{6, 0, 798},
+ dictWord{134, 0, 840},
+ dictWord{138, 11, 503},
+ dictWord{135, 10, 127},
+ dictWord{133, 0, 853},
+ dictWord{5, 11, 154},
+ dictWord{7, 11, 1491},
+ dictWord{10, 11, 379},
+ dictWord{138, 11, 485},
+ dictWord{6, 0, 249},
+ dictWord{7, 0, 1234},
+ dictWord{139, 0, 573},
+ dictWord{133, 11, 716},
+ dictWord{7, 11, 1570},
+ dictWord{140, 11, 542},
+ dictWord{136, 10, 364},
+ dictWord{138, 0, 527},
+ dictWord{
+ 4,
+ 11,
+ 91,
+ },
+ dictWord{5, 11, 388},
+ dictWord{5, 11, 845},
+ dictWord{6, 11, 206},
+ dictWord{6, 11, 252},
+ dictWord{6, 11, 365},
+ dictWord{7, 11, 136},
+ dictWord{7, 11, 531},
+ dictWord{8, 11, 264},
+ dictWord{136, 11, 621},
+ dictWord{134, 0, 1419},
+ dictWord{135, 11, 1441},
+ dictWord{7, 0, 49},
+ dictWord{7, 0, 392},
+ dictWord{8, 0, 20},
+ dictWord{8, 0, 172},
+ dictWord{8, 0, 690},
+ dictWord{9, 0, 383},
+ dictWord{9, 0, 845},
+ dictWord{10, 0, 48},
+ dictWord{11, 0, 293},
+ dictWord{11, 0, 832},
+ dictWord{
+ 11,
+ 0,
+ 920,
+ },
+ dictWord{11, 0, 984},
+ dictWord{141, 0, 221},
+ dictWord{5, 0, 858},
+ dictWord{133, 0, 992},
+ dictWord{5, 0, 728},
+ dictWord{137, 10, 792},
+ dictWord{
+ 5,
+ 10,
+ 909,
+ },
+ dictWord{9, 10, 849},
+ dictWord{138, 10, 805},
+ dictWord{7, 0, 525},
+ dictWord{7, 0, 1579},
+ dictWord{8, 0, 497},
+ dictWord{136, 0, 573},
+ dictWord{6, 0, 268},
+ dictWord{137, 0, 62},
+ dictWord{135, 11, 576},
+ dictWord{134, 0, 1201},
+ dictWord{5, 11, 771},
+ dictWord{5, 11, 863},
+ dictWord{5, 11, 898},
+ dictWord{
+ 6,
+ 11,
+ 1632,
+ },
+ dictWord{6, 11, 1644},
+ dictWord{134, 11, 1780},
+ dictWord{133, 11, 331},
+ dictWord{7, 0, 193},
+ dictWord{7, 0, 1105},
+ dictWord{10, 0, 495},
+ dictWord{
+ 7,
+ 10,
+ 397,
+ },
+ dictWord{8, 10, 124},
+ dictWord{8, 10, 619},
+ dictWord{9, 10, 305},
+ dictWord{11, 10, 40},
+ dictWord{12, 10, 349},
+ dictWord{13, 10, 134},
+ dictWord{
+ 13,
+ 10,
+ 295,
+ },
+ dictWord{14, 10, 155},
+ dictWord{15, 10, 120},
+ dictWord{146, 10, 105},
+ dictWord{138, 0, 106},
+ dictWord{6, 0, 859},
+ dictWord{5, 11, 107},
+ dictWord{
+ 7,
+ 11,
+ 201,
+ },
+ dictWord{136, 11, 518},
+ dictWord{6, 11, 446},
+ dictWord{135, 11, 1817},
+ dictWord{13, 0, 23},
+ dictWord{4, 10, 262},
+ dictWord{135, 10, 342},
+ dictWord{133, 10, 641},
+ dictWord{137, 11, 851},
+ dictWord{6, 0, 925},
+ dictWord{137, 0, 813},
+ dictWord{132, 11, 504},
+ dictWord{6, 0, 613},
+ dictWord{
+ 136,
+ 0,
+ 223,
+ },
+ dictWord{4, 10, 99},
+ dictWord{6, 10, 250},
+ dictWord{6, 10, 346},
+ dictWord{8, 10, 127},
+ dictWord{138, 10, 81},
+ dictWord{136, 0, 953},
+ dictWord{
+ 132,
+ 10,
+ 915,
+ },
+ dictWord{139, 11, 892},
+ dictWord{5, 10, 75},
+ dictWord{9, 10, 517},
+ dictWord{10, 10, 470},
+ dictWord{12, 10, 155},
+ dictWord{141, 10, 224},
+ dictWord{
+ 4,
+ 0,
+ 666,
+ },
+ dictWord{7, 0, 1017},
+ dictWord{7, 11, 996},
+ dictWord{138, 11, 390},
+ dictWord{5, 11, 883},
+ dictWord{133, 11, 975},
+ dictWord{14, 10, 83},
+ dictWord{
+ 142,
+ 11,
+ 83,
+ },
+ dictWord{4, 0, 670},
+ dictWord{5, 11, 922},
+ dictWord{134, 11, 1707},
+ dictWord{135, 0, 216},
+ dictWord{9, 0, 40},
+ dictWord{11, 0, 136},
+ dictWord{
+ 135,
+ 11,
+ 787,
+ },
+ dictWord{5, 10, 954},
+ dictWord{5, 11, 993},
+ dictWord{7, 11, 515},
+ dictWord{137, 11, 91},
+ dictWord{139, 0, 259},
+ dictWord{7, 0, 1114},
+ dictWord{
+ 9,
+ 0,
+ 310,
+ },
+ dictWord{9, 0, 682},
+ dictWord{10, 0, 440},
+ dictWord{13, 0, 40},
+ dictWord{6, 10, 304},
+ dictWord{8, 10, 418},
+ dictWord{11, 10, 341},
+ dictWord{
+ 139,
+ 10,
+ 675,
+ },
+ dictWord{14, 0, 296},
+ dictWord{9, 10, 410},
+ dictWord{139, 10, 425},
+ dictWord{10, 11, 377},
+ dictWord{12, 11, 363},
+ dictWord{13, 11, 68},
+ dictWord{
+ 13,
+ 11,
+ 94,
+ },
+ dictWord{14, 11, 108},
+ dictWord{142, 11, 306},
+ dictWord{7, 0, 1401},
+ dictWord{135, 0, 1476},
+ dictWord{4, 0, 296},
+ dictWord{6, 0, 475},
+ dictWord{
+ 7,
+ 0,
+ 401,
+ },
+ dictWord{7, 0, 1410},
+ dictWord{7, 0, 1594},
+ dictWord{7, 0, 1674},
+ dictWord{8, 0, 63},
+ dictWord{8, 0, 660},
+ dictWord{137, 0, 74},
+ dictWord{4, 0, 139},
+ dictWord{4, 0, 388},
+ dictWord{140, 0, 188},
+ dictWord{132, 0, 797},
+ dictWord{132, 11, 766},
+ dictWord{5, 11, 103},
+ dictWord{7, 11, 921},
+ dictWord{8, 11, 580},
+ dictWord{8, 11, 593},
+ dictWord{8, 11, 630},
+ dictWord{138, 11, 28},
+ dictWord{4, 11, 911},
+ dictWord{5, 11, 867},
+ dictWord{133, 11, 1013},
+ dictWord{134, 10, 14},
+ dictWord{134, 0, 1572},
+ dictWord{134, 10, 1708},
+ dictWord{21, 0, 39},
+ dictWord{5, 10, 113},
+ dictWord{6, 10, 243},
+ dictWord{7, 10, 1865},
+ dictWord{
+ 11,
+ 10,
+ 161,
+ },
+ dictWord{16, 10, 37},
+ dictWord{145, 10, 99},
+ dictWord{7, 11, 1563},
+ dictWord{141, 11, 182},
+ dictWord{5, 11, 135},
+ dictWord{6, 11, 519},
+ dictWord{
+ 7,
+ 11,
+ 1722,
+ },
+ dictWord{10, 11, 271},
+ dictWord{11, 11, 261},
+ dictWord{145, 11, 54},
+ dictWord{132, 10, 274},
+ dictWord{134, 0, 1594},
+ dictWord{4, 11, 300},
+ dictWord{5, 11, 436},
+ dictWord{135, 11, 484},
+ dictWord{4, 0, 747},
+ dictWord{6, 0, 290},
+ dictWord{7, 0, 649},
+ dictWord{7, 0, 1479},
+ dictWord{135, 0, 1583},
+ dictWord{133, 11, 535},
+ dictWord{147, 11, 82},
+ dictWord{133, 0, 232},
+ dictWord{137, 0, 887},
+ dictWord{135, 10, 166},
+ dictWord{136, 0, 521},
+ dictWord{4, 0, 14},
+ dictWord{7, 0, 472},
+ dictWord{7, 0, 1801},
+ dictWord{10, 0, 748},
+ dictWord{141, 0, 458},
+ dictWord{134, 0, 741},
+ dictWord{134, 0, 992},
+ dictWord{16, 0, 111},
+ dictWord{137, 10, 304},
+ dictWord{4, 0, 425},
+ dictWord{5, 11, 387},
+ dictWord{7, 11, 557},
+ dictWord{12, 11, 547},
+ dictWord{142, 11, 86},
+ dictWord{
+ 135,
+ 11,
+ 1747,
+ },
+ dictWord{5, 10, 654},
+ dictWord{135, 11, 1489},
+ dictWord{7, 0, 789},
+ dictWord{4, 11, 6},
+ dictWord{5, 11, 708},
+ dictWord{136, 11, 75},
+ dictWord{
+ 6,
+ 10,
+ 273,
+ },
+ dictWord{10, 10, 188},
+ dictWord{13, 10, 377},
+ dictWord{146, 10, 77},
+ dictWord{6, 0, 1593},
+ dictWord{4, 11, 303},
+ dictWord{7, 11, 619},
+ dictWord{
+ 10,
+ 11,
+ 547,
+ },
+ dictWord{10, 11, 687},
+ dictWord{11, 11, 122},
+ dictWord{140, 11, 601},
+ dictWord{134, 0, 1768},
+ dictWord{135, 10, 410},
+ dictWord{138, 11, 772},
+ dictWord{11, 0, 233},
+ dictWord{139, 10, 524},
+ dictWord{5, 0, 943},
+ dictWord{134, 0, 1779},
+ dictWord{134, 10, 1785},
+ dictWord{136, 11, 529},
+ dictWord{
+ 132,
+ 0,
+ 955,
+ },
+ dictWord{5, 0, 245},
+ dictWord{6, 0, 576},
+ dictWord{7, 0, 582},
+ dictWord{136, 0, 225},
+ dictWord{132, 10, 780},
+ dictWord{142, 0, 241},
+ dictWord{
+ 134,
+ 0,
+ 1943,
+ },
+ dictWord{4, 11, 106},
+ dictWord{7, 11, 310},
+ dictWord{7, 11, 1785},
+ dictWord{10, 11, 690},
+ dictWord{139, 11, 717},
+ dictWord{134, 0, 1284},
+ dictWord{5, 11, 890},
+ dictWord{133, 11, 988},
+ dictWord{6, 11, 626},
+ dictWord{142, 11, 431},
+ dictWord{10, 11, 706},
+ dictWord{145, 11, 32},
+ dictWord{
+ 137,
+ 11,
+ 332,
+ },
+ dictWord{132, 11, 698},
+ dictWord{135, 0, 709},
+ dictWord{5, 10, 948},
+ dictWord{138, 11, 17},
+ dictWord{136, 0, 554},
+ dictWord{134, 0, 1564},
+ dictWord{139, 10, 941},
+ dictWord{132, 0, 443},
+ dictWord{134, 0, 909},
+ dictWord{134, 11, 84},
+ dictWord{142, 0, 280},
+ dictWord{4, 10, 532},
+ dictWord{5, 10, 706},
+ dictWord{135, 10, 662},
+ dictWord{132, 0, 729},
+ dictWord{5, 10, 837},
+ dictWord{6, 10, 1651},
+ dictWord{139, 10, 985},
+ dictWord{135, 10, 1861},
+ dictWord{
+ 4,
+ 0,
+ 348,
+ },
+ dictWord{152, 11, 3},
+ dictWord{5, 11, 986},
+ dictWord{6, 11, 130},
+ dictWord{7, 11, 1582},
+ dictWord{8, 11, 458},
+ dictWord{10, 11, 101},
+ dictWord{
+ 10,
+ 11,
+ 318,
+ },
+ dictWord{138, 11, 823},
+ dictWord{134, 0, 758},
+ dictWord{4, 0, 298},
+ dictWord{137, 0, 848},
+ dictWord{4, 10, 330},
+ dictWord{7, 10, 933},
+ dictWord{
+ 7,
+ 10,
+ 2012,
+ },
+ dictWord{136, 10, 292},
+ dictWord{7, 11, 1644},
+ dictWord{137, 11, 129},
+ dictWord{6, 0, 1422},
+ dictWord{9, 0, 829},
+ dictWord{135, 10, 767},
+ dictWord{5, 0, 164},
+ dictWord{7, 0, 121},
+ dictWord{142, 0, 189},
+ dictWord{7, 0, 812},
+ dictWord{7, 0, 1261},
+ dictWord{7, 0, 1360},
+ dictWord{9, 0, 632},
+ dictWord{
+ 140,
+ 0,
+ 352,
+ },
+ dictWord{135, 11, 1788},
+ dictWord{139, 0, 556},
+ dictWord{135, 11, 997},
+ dictWord{145, 10, 114},
+ dictWord{4, 0, 172},
+ dictWord{9, 0, 611},
+ dictWord{10, 0, 436},
+ dictWord{12, 0, 673},
+ dictWord{13, 0, 255},
+ dictWord{137, 10, 883},
+ dictWord{11, 0, 530},
+ dictWord{138, 10, 274},
+ dictWord{133, 0, 844},
+ dictWord{134, 0, 984},
+ dictWord{13, 0, 232},
+ dictWord{18, 0, 35},
+ dictWord{4, 10, 703},
+ dictWord{135, 10, 207},
+ dictWord{132, 10, 571},
+ dictWord{9, 0, 263},
+ dictWord{10, 0, 147},
+ dictWord{138, 0, 492},
+ dictWord{7, 11, 1756},
+ dictWord{137, 11, 98},
+ dictWord{5, 10, 873},
+ dictWord{5, 10, 960},
+ dictWord{8, 10, 823},
+ dictWord{137, 10, 881},
+ dictWord{133, 0, 537},
+ dictWord{132, 0, 859},
+ dictWord{7, 11, 1046},
+ dictWord{139, 11, 160},
+ dictWord{137, 0, 842},
+ dictWord{
+ 139,
+ 10,
+ 283,
+ },
+ dictWord{5, 10, 33},
+ dictWord{6, 10, 470},
+ dictWord{139, 10, 424},
+ dictWord{6, 11, 45},
+ dictWord{7, 11, 433},
+ dictWord{8, 11, 129},
+ dictWord{
+ 9,
+ 11,
+ 21,
+ },
+ dictWord{10, 11, 392},
+ dictWord{11, 11, 79},
+ dictWord{12, 11, 499},
+ dictWord{13, 11, 199},
+ dictWord{141, 11, 451},
+ dictWord{135, 0, 1291},
+ dictWord{135, 10, 1882},
+ dictWord{7, 11, 558},
+ dictWord{136, 11, 353},
+ dictWord{134, 0, 1482},
+ dictWord{5, 0, 230},
+ dictWord{5, 0, 392},
+ dictWord{6, 0, 420},
+ dictWord{9, 0, 568},
+ dictWord{140, 0, 612},
+ dictWord{6, 0, 262},
+ dictWord{7, 10, 90},
+ dictWord{7, 10, 664},
+ dictWord{7, 10, 830},
+ dictWord{7, 10, 1380},
+ dictWord{
+ 7,
+ 10,
+ 2025,
+ },
+ dictWord{8, 11, 81},
+ dictWord{8, 10, 448},
+ dictWord{8, 10, 828},
+ dictWord{9, 11, 189},
+ dictWord{9, 11, 201},
+ dictWord{11, 11, 478},
+ dictWord{
+ 11,
+ 11,
+ 712,
+ },
+ dictWord{141, 11, 338},
+ dictWord{142, 0, 31},
+ dictWord{5, 11, 353},
+ dictWord{151, 11, 26},
+ dictWord{132, 0, 753},
+ dictWord{4, 0, 0},
+ dictWord{
+ 5,
+ 0,
+ 41,
+ },
+ dictWord{7, 0, 1459},
+ dictWord{7, 0, 1469},
+ dictWord{7, 0, 1859},
+ dictWord{9, 0, 549},
+ dictWord{139, 0, 905},
+ dictWord{9, 10, 417},
+ dictWord{
+ 137,
+ 10,
+ 493,
+ },
+ dictWord{135, 11, 1113},
+ dictWord{133, 0, 696},
+ dictWord{141, 11, 448},
+ dictWord{134, 10, 295},
+ dictWord{132, 0, 834},
+ dictWord{4, 0, 771},
+ dictWord{5, 10, 1019},
+ dictWord{6, 11, 25},
+ dictWord{7, 11, 855},
+ dictWord{7, 11, 1258},
+ dictWord{144, 11, 32},
+ dictWord{134, 0, 1076},
+ dictWord{133, 0, 921},
+ dictWord{133, 0, 674},
+ dictWord{4, 11, 4},
+ dictWord{7, 11, 1118},
+ dictWord{7, 11, 1320},
+ dictWord{7, 11, 1706},
+ dictWord{8, 11, 277},
+ dictWord{9, 11, 622},
+ dictWord{10, 11, 9},
+ dictWord{11, 11, 724},
+ dictWord{12, 11, 350},
+ dictWord{12, 11, 397},
+ dictWord{13, 11, 28},
+ dictWord{13, 11, 159},
+ dictWord{15, 11, 89},
+ dictWord{18, 11, 5},
+ dictWord{19, 11, 9},
+ dictWord{20, 11, 34},
+ dictWord{150, 11, 47},
+ dictWord{134, 10, 208},
+ dictWord{6, 0, 444},
+ dictWord{136, 0, 308},
+ dictWord{
+ 6,
+ 0,
+ 180,
+ },
+ dictWord{7, 0, 1137},
+ dictWord{8, 0, 751},
+ dictWord{139, 0, 805},
+ dictWord{4, 0, 183},
+ dictWord{7, 0, 271},
+ dictWord{11, 0, 824},
+ dictWord{
+ 11,
+ 0,
+ 952,
+ },
+ dictWord{13, 0, 278},
+ dictWord{13, 0, 339},
+ dictWord{13, 0, 482},
+ dictWord{14, 0, 424},
+ dictWord{148, 0, 99},
+ dictWord{7, 11, 317},
+ dictWord{
+ 135,
+ 11,
+ 569,
+ },
+ dictWord{4, 0, 19},
+ dictWord{5, 0, 477},
+ dictWord{5, 0, 596},
+ dictWord{6, 0, 505},
+ dictWord{7, 0, 1221},
+ dictWord{11, 0, 907},
+ dictWord{12, 0, 209},
+ dictWord{141, 0, 214},
+ dictWord{135, 0, 1215},
+ dictWord{6, 0, 271},
+ dictWord{7, 0, 398},
+ dictWord{8, 0, 387},
+ dictWord{10, 0, 344},
+ dictWord{7, 10, 448},
+ dictWord{
+ 7,
+ 10,
+ 1629,
+ },
+ dictWord{7, 10, 1813},
+ dictWord{8, 10, 442},
+ dictWord{9, 10, 710},
+ dictWord{10, 10, 282},
+ dictWord{138, 10, 722},
+ dictWord{11, 10, 844},
+ dictWord{12, 10, 104},
+ dictWord{140, 10, 625},
+ dictWord{134, 11, 255},
+ dictWord{133, 10, 787},
+ dictWord{134, 0, 1645},
+ dictWord{11, 11, 956},
+ dictWord{
+ 151,
+ 11,
+ 3,
+ },
+ dictWord{6, 0, 92},
+ dictWord{6, 0, 188},
+ dictWord{7, 0, 209},
+ dictWord{7, 0, 1269},
+ dictWord{7, 0, 1524},
+ dictWord{7, 0, 1876},
+ dictWord{8, 0, 661},
+ dictWord{10, 0, 42},
+ dictWord{10, 0, 228},
+ dictWord{11, 0, 58},
+ dictWord{11, 0, 1020},
+ dictWord{12, 0, 58},
+ dictWord{12, 0, 118},
+ dictWord{141, 0, 32},
+ dictWord{
+ 4,
+ 0,
+ 459,
+ },
+ dictWord{133, 0, 966},
+ dictWord{4, 11, 536},
+ dictWord{7, 11, 1141},
+ dictWord{10, 11, 723},
+ dictWord{139, 11, 371},
+ dictWord{140, 0, 330},
+ dictWord{134, 0, 1557},
+ dictWord{7, 11, 285},
+ dictWord{135, 11, 876},
+ dictWord{136, 10, 491},
+ dictWord{135, 11, 560},
+ dictWord{6, 0, 18},
+ dictWord{7, 0, 179},
+ dictWord{7, 0, 932},
+ dictWord{8, 0, 548},
+ dictWord{8, 0, 757},
+ dictWord{9, 0, 54},
+ dictWord{9, 0, 65},
+ dictWord{9, 0, 532},
+ dictWord{9, 0, 844},
+ dictWord{10, 0, 113},
+ dictWord{10, 0, 117},
+ dictWord{10, 0, 315},
+ dictWord{10, 0, 560},
+ dictWord{10, 0, 622},
+ dictWord{10, 0, 798},
+ dictWord{11, 0, 153},
+ dictWord{11, 0, 351},
+ dictWord{
+ 11,
+ 0,
+ 375,
+ },
+ dictWord{12, 0, 78},
+ dictWord{12, 0, 151},
+ dictWord{12, 0, 392},
+ dictWord{12, 0, 666},
+ dictWord{14, 0, 248},
+ dictWord{143, 0, 23},
+ dictWord{
+ 6,
+ 0,
+ 1742,
+ },
+ dictWord{132, 11, 690},
+ dictWord{4, 10, 403},
+ dictWord{5, 10, 441},
+ dictWord{7, 10, 450},
+ dictWord{10, 10, 840},
+ dictWord{11, 10, 101},
+ dictWord{
+ 12,
+ 10,
+ 193,
+ },
+ dictWord{141, 10, 430},
+ dictWord{133, 0, 965},
+ dictWord{134, 0, 182},
+ dictWord{10, 0, 65},
+ dictWord{10, 0, 488},
+ dictWord{138, 0, 497},
+ dictWord{135, 11, 1346},
+ dictWord{6, 0, 973},
+ dictWord{6, 0, 1158},
+ dictWord{10, 11, 200},
+ dictWord{19, 11, 2},
+ dictWord{151, 11, 22},
+ dictWord{4, 11, 190},
+ dictWord{133, 11, 554},
+ dictWord{133, 10, 679},
+ dictWord{7, 0, 328},
+ dictWord{137, 10, 326},
+ dictWord{133, 11, 1001},
+ dictWord{9, 0, 588},
+ dictWord{
+ 138,
+ 0,
+ 260,
+ },
+ dictWord{133, 11, 446},
+ dictWord{135, 10, 1128},
+ dictWord{135, 10, 1796},
+ dictWord{147, 11, 119},
+ dictWord{134, 0, 1786},
+ dictWord{
+ 6,
+ 0,
+ 1328,
+ },
+ dictWord{6, 0, 1985},
+ dictWord{8, 0, 962},
+ dictWord{138, 0, 1017},
+ dictWord{135, 0, 308},
+ dictWord{11, 0, 508},
+ dictWord{4, 10, 574},
+ dictWord{
+ 7,
+ 10,
+ 350,
+ },
+ dictWord{7, 10, 1024},
+ dictWord{8, 10, 338},
+ dictWord{9, 10, 677},
+ dictWord{138, 10, 808},
+ dictWord{138, 11, 752},
+ dictWord{135, 10, 1081},
+ dictWord{137, 11, 96},
+ dictWord{7, 10, 1676},
+ dictWord{135, 10, 2037},
+ dictWord{136, 0, 588},
+ dictWord{132, 11, 304},
+ dictWord{133, 0, 614},
+ dictWord{
+ 140,
+ 0,
+ 793,
+ },
+ dictWord{136, 0, 287},
+ dictWord{137, 10, 297},
+ dictWord{141, 10, 37},
+ dictWord{6, 11, 53},
+ dictWord{6, 11, 199},
+ dictWord{7, 11, 1408},
+ dictWord{
+ 8,
+ 11,
+ 32,
+ },
+ dictWord{8, 11, 93},
+ dictWord{9, 11, 437},
+ dictWord{10, 11, 397},
+ dictWord{10, 11, 629},
+ dictWord{11, 11, 593},
+ dictWord{11, 11, 763},
+ dictWord{
+ 13,
+ 11,
+ 326,
+ },
+ dictWord{145, 11, 35},
+ dictWord{134, 11, 105},
+ dictWord{9, 11, 320},
+ dictWord{10, 11, 506},
+ dictWord{138, 11, 794},
+ dictWord{5, 11, 114},
+ dictWord{5, 11, 255},
+ dictWord{141, 11, 285},
+ dictWord{140, 0, 290},
+ dictWord{7, 11, 2035},
+ dictWord{8, 11, 19},
+ dictWord{9, 11, 89},
+ dictWord{138, 11, 831},
+ dictWord{134, 0, 1136},
+ dictWord{7, 0, 719},
+ dictWord{8, 0, 796},
+ dictWord{8, 0, 809},
+ dictWord{8, 0, 834},
+ dictWord{6, 10, 306},
+ dictWord{7, 10, 1140},
+ dictWord{
+ 7,
+ 10,
+ 1340,
+ },
+ dictWord{8, 10, 133},
+ dictWord{138, 10, 449},
+ dictWord{139, 10, 1011},
+ dictWord{5, 0, 210},
+ dictWord{6, 0, 213},
+ dictWord{7, 0, 60},
+ dictWord{
+ 10,
+ 0,
+ 364,
+ },
+ dictWord{139, 0, 135},
+ dictWord{5, 0, 607},
+ dictWord{8, 0, 326},
+ dictWord{136, 0, 490},
+ dictWord{138, 11, 176},
+ dictWord{132, 0, 701},
+ dictWord{
+ 5,
+ 0,
+ 472,
+ },
+ dictWord{7, 0, 380},
+ dictWord{137, 0, 758},
+ dictWord{135, 0, 1947},
+ dictWord{6, 0, 1079},
+ dictWord{138, 0, 278},
+ dictWord{138, 11, 391},
+ dictWord{
+ 5,
+ 10,
+ 329,
+ },
+ dictWord{8, 10, 260},
+ dictWord{139, 11, 156},
+ dictWord{4, 0, 386},
+ dictWord{7, 0, 41},
+ dictWord{8, 0, 405},
+ dictWord{8, 0, 728},
+ dictWord{9, 0, 497},
+ dictWord{11, 0, 110},
+ dictWord{11, 0, 360},
+ dictWord{15, 0, 37},
+ dictWord{144, 0, 84},
+ dictWord{5, 0, 46},
+ dictWord{7, 0, 1452},
+ dictWord{7, 0, 1480},
+ dictWord{
+ 8,
+ 0,
+ 634,
+ },
+ dictWord{140, 0, 472},
+ dictWord{136, 0, 961},
+ dictWord{4, 0, 524},
+ dictWord{136, 0, 810},
+ dictWord{10, 0, 238},
+ dictWord{141, 0, 33},
+ dictWord{
+ 132,
+ 10,
+ 657,
+ },
+ dictWord{152, 10, 7},
+ dictWord{133, 0, 532},
+ dictWord{5, 0, 997},
+ dictWord{135, 10, 1665},
+ dictWord{7, 11, 594},
+ dictWord{7, 11, 851},
+ dictWord{
+ 7,
+ 11,
+ 1858,
+ },
+ dictWord{9, 11, 411},
+ dictWord{9, 11, 574},
+ dictWord{9, 11, 666},
+ dictWord{9, 11, 737},
+ dictWord{10, 11, 346},
+ dictWord{10, 11, 712},
+ dictWord{
+ 11,
+ 11,
+ 246,
+ },
+ dictWord{11, 11, 432},
+ dictWord{11, 11, 517},
+ dictWord{11, 11, 647},
+ dictWord{11, 11, 679},
+ dictWord{11, 11, 727},
+ dictWord{12, 11, 304},
+ dictWord{12, 11, 305},
+ dictWord{12, 11, 323},
+ dictWord{12, 11, 483},
+ dictWord{12, 11, 572},
+ dictWord{12, 11, 593},
+ dictWord{12, 11, 602},
+ dictWord{
+ 13,
+ 11,
+ 95,
+ },
+ dictWord{13, 11, 101},
+ dictWord{13, 11, 171},
+ dictWord{13, 11, 315},
+ dictWord{13, 11, 378},
+ dictWord{13, 11, 425},
+ dictWord{13, 11, 475},
+ dictWord{
+ 14,
+ 11,
+ 63,
+ },
+ dictWord{14, 11, 380},
+ dictWord{14, 11, 384},
+ dictWord{15, 11, 133},
+ dictWord{18, 11, 112},
+ dictWord{148, 11, 72},
+ dictWord{5, 11, 955},
+ dictWord{136, 11, 814},
+ dictWord{134, 0, 1301},
+ dictWord{5, 10, 66},
+ dictWord{7, 10, 1896},
+ dictWord{136, 10, 288},
+ dictWord{133, 11, 56},
+ dictWord{
+ 134,
+ 10,
+ 1643,
+ },
+ dictWord{6, 0, 1298},
+ dictWord{148, 11, 100},
+ dictWord{5, 0, 782},
+ dictWord{5, 0, 829},
+ dictWord{6, 0, 671},
+ dictWord{6, 0, 1156},
+ dictWord{6, 0, 1738},
+ dictWord{137, 11, 621},
+ dictWord{4, 0, 306},
+ dictWord{5, 0, 570},
+ dictWord{7, 0, 1347},
+ dictWord{5, 10, 91},
+ dictWord{5, 10, 648},
+ dictWord{5, 10, 750},
+ dictWord{
+ 5,
+ 10,
+ 781,
+ },
+ dictWord{6, 10, 54},
+ dictWord{6, 10, 112},
+ dictWord{6, 10, 402},
+ dictWord{6, 10, 1732},
+ dictWord{7, 10, 315},
+ dictWord{7, 10, 749},
+ dictWord{
+ 7,
+ 10,
+ 1900,
+ },
+ dictWord{9, 10, 78},
+ dictWord{9, 10, 508},
+ dictWord{10, 10, 611},
+ dictWord{10, 10, 811},
+ dictWord{11, 10, 510},
+ dictWord{11, 10, 728},
+ dictWord{
+ 13,
+ 10,
+ 36,
+ },
+ dictWord{14, 10, 39},
+ dictWord{16, 10, 83},
+ dictWord{17, 10, 124},
+ dictWord{148, 10, 30},
+ dictWord{8, 10, 570},
+ dictWord{9, 11, 477},
+ dictWord{
+ 141,
+ 11,
+ 78,
+ },
+ dictWord{4, 11, 639},
+ dictWord{10, 11, 4},
+ dictWord{10, 10, 322},
+ dictWord{10, 10, 719},
+ dictWord{11, 10, 407},
+ dictWord{11, 11, 638},
+ dictWord{
+ 12,
+ 11,
+ 177,
+ },
+ dictWord{148, 11, 57},
+ dictWord{7, 0, 1823},
+ dictWord{139, 0, 693},
+ dictWord{7, 0, 759},
+ dictWord{5, 11, 758},
+ dictWord{8, 10, 125},
+ dictWord{
+ 8,
+ 10,
+ 369,
+ },
+ dictWord{8, 10, 524},
+ dictWord{10, 10, 486},
+ dictWord{11, 10, 13},
+ dictWord{11, 10, 381},
+ dictWord{11, 10, 736},
+ dictWord{11, 10, 766},
+ dictWord{
+ 11,
+ 10,
+ 845,
+ },
+ dictWord{13, 10, 114},
+ dictWord{13, 10, 292},
+ dictWord{142, 10, 47},
+ dictWord{7, 0, 1932},
+ dictWord{6, 10, 1684},
+ dictWord{6, 10, 1731},
+ dictWord{7, 10, 356},
+ dictWord{8, 10, 54},
+ dictWord{8, 10, 221},
+ dictWord{9, 10, 225},
+ dictWord{9, 10, 356},
+ dictWord{10, 10, 77},
+ dictWord{10, 10, 446},
+ dictWord{
+ 10,
+ 10,
+ 731,
+ },
+ dictWord{12, 10, 404},
+ dictWord{141, 10, 491},
+ dictWord{135, 11, 552},
+ dictWord{135, 11, 1112},
+ dictWord{4, 0, 78},
+ dictWord{5, 0, 96},
+ dictWord{
+ 5,
+ 0,
+ 182,
+ },
+ dictWord{6, 0, 1257},
+ dictWord{7, 0, 1724},
+ dictWord{7, 0, 1825},
+ dictWord{10, 0, 394},
+ dictWord{10, 0, 471},
+ dictWord{11, 0, 532},
+ dictWord{
+ 14,
+ 0,
+ 340,
+ },
+ dictWord{145, 0, 88},
+ dictWord{139, 11, 328},
+ dictWord{135, 0, 1964},
+ dictWord{132, 10, 411},
+ dictWord{4, 10, 80},
+ dictWord{5, 10, 44},
+ dictWord{
+ 137,
+ 11,
+ 133,
+ },
+ dictWord{5, 11, 110},
+ dictWord{6, 11, 169},
+ dictWord{6, 11, 1702},
+ dictWord{7, 11, 400},
+ dictWord{8, 11, 538},
+ dictWord{9, 11, 184},
+ dictWord{
+ 9,
+ 11,
+ 524,
+ },
+ dictWord{140, 11, 218},
+ dictWord{4, 0, 521},
+ dictWord{5, 10, 299},
+ dictWord{7, 10, 1083},
+ dictWord{140, 11, 554},
+ dictWord{6, 11, 133},
+ dictWord{
+ 9,
+ 11,
+ 353,
+ },
+ dictWord{12, 11, 628},
+ dictWord{146, 11, 79},
+ dictWord{6, 0, 215},
+ dictWord{7, 0, 584},
+ dictWord{7, 0, 1028},
+ dictWord{7, 0, 1473},
+ dictWord{
+ 7,
+ 0,
+ 1721,
+ },
+ dictWord{9, 0, 424},
+ dictWord{138, 0, 779},
+ dictWord{7, 0, 857},
+ dictWord{7, 0, 1209},
+ dictWord{7, 10, 1713},
+ dictWord{9, 10, 537},
+ dictWord{
+ 10,
+ 10,
+ 165,
+ },
+ dictWord{12, 10, 219},
+ dictWord{140, 10, 561},
+ dictWord{4, 10, 219},
+ dictWord{6, 11, 93},
+ dictWord{7, 11, 1422},
+ dictWord{7, 10, 1761},
+ dictWord{
+ 7,
+ 11,
+ 1851,
+ },
+ dictWord{8, 11, 673},
+ dictWord{9, 10, 86},
+ dictWord{9, 11, 529},
+ dictWord{140, 11, 43},
+ dictWord{137, 11, 371},
+ dictWord{136, 0, 671},
+ dictWord{
+ 5,
+ 0,
+ 328,
+ },
+ dictWord{135, 0, 918},
+ dictWord{132, 0, 529},
+ dictWord{9, 11, 25},
+ dictWord{10, 11, 467},
+ dictWord{138, 11, 559},
+ dictWord{4, 11, 335},
+ dictWord{
+ 135,
+ 11,
+ 942,
+ },
+ dictWord{134, 0, 716},
+ dictWord{134, 0, 1509},
+ dictWord{6, 0, 67},
+ dictWord{7, 0, 258},
+ dictWord{7, 0, 1630},
+ dictWord{9, 0, 354},
+ dictWord{
+ 9,
+ 0,
+ 675,
+ },
+ dictWord{10, 0, 830},
+ dictWord{14, 0, 80},
+ dictWord{17, 0, 80},
+ dictWord{140, 10, 428},
+ dictWord{134, 0, 1112},
+ dictWord{6, 0, 141},
+ dictWord{7, 0, 225},
+ dictWord{9, 0, 59},
+ dictWord{9, 0, 607},
+ dictWord{10, 0, 312},
+ dictWord{11, 0, 687},
+ dictWord{12, 0, 555},
+ dictWord{13, 0, 373},
+ dictWord{13, 0, 494},
+ dictWord{
+ 148,
+ 0,
+ 58,
+ },
+ dictWord{133, 10, 514},
+ dictWord{8, 11, 39},
+ dictWord{10, 11, 773},
+ dictWord{11, 11, 84},
+ dictWord{12, 11, 205},
+ dictWord{142, 11, 1},
+ dictWord{
+ 8,
+ 0,
+ 783,
+ },
+ dictWord{5, 11, 601},
+ dictWord{133, 11, 870},
+ dictWord{136, 11, 594},
+ dictWord{4, 10, 55},
+ dictWord{5, 10, 301},
+ dictWord{6, 10, 571},
+ dictWord{
+ 14,
+ 10,
+ 49,
+ },
+ dictWord{146, 10, 102},
+ dictWord{132, 11, 181},
+ dictWord{134, 11, 1652},
+ dictWord{133, 10, 364},
+ dictWord{4, 11, 97},
+ dictWord{5, 11, 147},
+ dictWord{6, 11, 286},
+ dictWord{7, 11, 1362},
+ dictWord{141, 11, 176},
+ dictWord{4, 10, 76},
+ dictWord{7, 10, 1550},
+ dictWord{9, 10, 306},
+ dictWord{9, 10, 430},
+ dictWord{9, 10, 663},
+ dictWord{10, 10, 683},
+ dictWord{11, 10, 427},
+ dictWord{11, 10, 753},
+ dictWord{12, 10, 334},
+ dictWord{12, 10, 442},
+ dictWord{
+ 14,
+ 10,
+ 258,
+ },
+ dictWord{14, 10, 366},
+ dictWord{143, 10, 131},
+ dictWord{137, 10, 52},
+ dictWord{6, 0, 955},
+ dictWord{134, 0, 1498},
+ dictWord{6, 11, 375},
+ dictWord{
+ 7,
+ 11,
+ 169,
+ },
+ dictWord{7, 11, 254},
+ dictWord{136, 11, 780},
+ dictWord{7, 0, 430},
+ dictWord{11, 0, 46},
+ dictWord{14, 0, 343},
+ dictWord{142, 11, 343},
+ dictWord{
+ 135,
+ 0,
+ 1183,
+ },
+ dictWord{5, 0, 602},
+ dictWord{7, 0, 2018},
+ dictWord{9, 0, 418},
+ dictWord{9, 0, 803},
+ dictWord{135, 11, 1447},
+ dictWord{8, 0, 677},
+ dictWord{
+ 135,
+ 11,
+ 1044,
+ },
+ dictWord{139, 11, 285},
+ dictWord{4, 10, 656},
+ dictWord{135, 10, 779},
+ dictWord{135, 10, 144},
+ dictWord{5, 11, 629},
+ dictWord{
+ 135,
+ 11,
+ 1549,
+ },
+ dictWord{135, 10, 1373},
+ dictWord{138, 11, 209},
+ dictWord{7, 10, 554},
+ dictWord{7, 10, 605},
+ dictWord{141, 10, 10},
+ dictWord{5, 10, 838},
+ dictWord{
+ 5,
+ 10,
+ 841,
+ },
+ dictWord{134, 10, 1649},
+ dictWord{133, 10, 1012},
+ dictWord{6, 0, 1357},
+ dictWord{134, 0, 1380},
+ dictWord{144, 0, 53},
+ dictWord{6, 0, 590},
+ dictWord{7, 10, 365},
+ dictWord{7, 10, 1357},
+ dictWord{7, 10, 1497},
+ dictWord{8, 10, 154},
+ dictWord{141, 10, 281},
+ dictWord{133, 10, 340},
+ dictWord{
+ 132,
+ 11,
+ 420,
+ },
+ dictWord{135, 0, 329},
+ dictWord{147, 11, 32},
+ dictWord{4, 0, 469},
+ dictWord{10, 11, 429},
+ dictWord{139, 10, 495},
+ dictWord{8, 10, 261},
+ dictWord{
+ 9,
+ 10,
+ 144,
+ },
+ dictWord{9, 10, 466},
+ dictWord{10, 10, 370},
+ dictWord{12, 10, 470},
+ dictWord{13, 10, 144},
+ dictWord{142, 10, 348},
+ dictWord{142, 0, 460},
+ dictWord{4, 11, 325},
+ dictWord{9, 10, 897},
+ dictWord{138, 11, 125},
+ dictWord{6, 0, 1743},
+ dictWord{6, 10, 248},
+ dictWord{9, 10, 546},
+ dictWord{10, 10, 535},
+ dictWord{11, 10, 681},
+ dictWord{141, 10, 135},
+ dictWord{4, 0, 990},
+ dictWord{5, 0, 929},
+ dictWord{6, 0, 340},
+ dictWord{8, 0, 376},
+ dictWord{8, 0, 807},
+ dictWord{
+ 8,
+ 0,
+ 963,
+ },
+ dictWord{8, 0, 980},
+ dictWord{138, 0, 1007},
+ dictWord{134, 0, 1603},
+ dictWord{140, 0, 250},
+ dictWord{4, 11, 714},
+ dictWord{133, 11, 469},
+ dictWord{134, 10, 567},
+ dictWord{136, 10, 445},
+ dictWord{5, 0, 218},
+ dictWord{7, 0, 1610},
+ dictWord{8, 0, 646},
+ dictWord{10, 0, 83},
+ dictWord{11, 11, 138},
+ dictWord{140, 11, 40},
+ dictWord{7, 0, 1512},
+ dictWord{135, 0, 1794},
+ dictWord{135, 11, 1216},
+ dictWord{11, 0, 0},
+ dictWord{16, 0, 78},
+ dictWord{132, 11, 718},
+ dictWord{133, 0, 571},
+ dictWord{132, 0, 455},
+ dictWord{134, 0, 1012},
+ dictWord{5, 11, 124},
+ dictWord{5, 11, 144},
+ dictWord{6, 11, 548},
+ dictWord{7, 11, 15},
+ dictWord{7, 11, 153},
+ dictWord{137, 11, 629},
+ dictWord{142, 11, 10},
+ dictWord{6, 11, 75},
+ dictWord{7, 11, 1531},
+ dictWord{8, 11, 416},
+ dictWord{9, 11, 240},
+ dictWord{9, 11, 275},
+ dictWord{10, 11, 100},
+ dictWord{11, 11, 658},
+ dictWord{11, 11, 979},
+ dictWord{12, 11, 86},
+ dictWord{13, 11, 468},
+ dictWord{14, 11, 66},
+ dictWord{14, 11, 207},
+ dictWord{15, 11, 20},
+ dictWord{15, 11, 25},
+ dictWord{144, 11, 58},
+ dictWord{132, 10, 577},
+ dictWord{5, 11, 141},
+ dictWord{
+ 5,
+ 11,
+ 915,
+ },
+ dictWord{6, 11, 1783},
+ dictWord{7, 11, 211},
+ dictWord{7, 11, 698},
+ dictWord{7, 11, 1353},
+ dictWord{9, 11, 83},
+ dictWord{9, 11, 281},
+ dictWord{
+ 10,
+ 11,
+ 376,
+ },
+ dictWord{10, 11, 431},
+ dictWord{11, 11, 543},
+ dictWord{12, 11, 664},
+ dictWord{13, 11, 280},
+ dictWord{13, 11, 428},
+ dictWord{14, 11, 61},
+ dictWord{
+ 14,
+ 11,
+ 128,
+ },
+ dictWord{17, 11, 52},
+ dictWord{145, 11, 81},
+ dictWord{6, 0, 161},
+ dictWord{7, 0, 372},
+ dictWord{137, 0, 597},
+ dictWord{132, 0, 349},
+ dictWord{
+ 10,
+ 11,
+ 702,
+ },
+ dictWord{139, 11, 245},
+ dictWord{134, 0, 524},
+ dictWord{134, 10, 174},
+ dictWord{6, 0, 432},
+ dictWord{9, 0, 751},
+ dictWord{139, 0, 322},
+ dictWord{147, 11, 94},
+ dictWord{4, 11, 338},
+ dictWord{133, 11, 400},
+ dictWord{5, 0, 468},
+ dictWord{10, 0, 325},
+ dictWord{11, 0, 856},
+ dictWord{12, 0, 345},
+ dictWord{143, 0, 104},
+ dictWord{133, 0, 223},
+ dictWord{132, 0, 566},
+ dictWord{4, 11, 221},
+ dictWord{5, 11, 659},
+ dictWord{5, 11, 989},
+ dictWord{7, 11, 697},
+ dictWord{7, 11, 1211},
+ dictWord{138, 11, 284},
+ dictWord{135, 11, 1070},
+ dictWord{4, 0, 59},
+ dictWord{135, 0, 1394},
+ dictWord{6, 0, 436},
+ dictWord{11, 0, 481},
+ dictWord{5, 10, 878},
+ dictWord{133, 10, 972},
+ dictWord{4, 0, 48},
+ dictWord{5, 0, 271},
+ dictWord{135, 0, 953},
+ dictWord{5, 0, 610},
+ dictWord{136, 0, 457},
+ dictWord{
+ 4,
+ 0,
+ 773,
+ },
+ dictWord{5, 0, 618},
+ dictWord{137, 0, 756},
+ dictWord{133, 0, 755},
+ dictWord{135, 0, 1217},
+ dictWord{138, 11, 507},
+ dictWord{132, 10, 351},
+ dictWord{132, 0, 197},
+ dictWord{143, 11, 78},
+ dictWord{4, 11, 188},
+ dictWord{7, 11, 805},
+ dictWord{11, 11, 276},
+ dictWord{142, 11, 293},
+ dictWord{
+ 5,
+ 11,
+ 884,
+ },
+ dictWord{139, 11, 991},
+ dictWord{132, 10, 286},
+ dictWord{10, 0, 259},
+ dictWord{10, 0, 428},
+ dictWord{7, 10, 438},
+ dictWord{7, 10, 627},
+ dictWord{
+ 7,
+ 10,
+ 1516,
+ },
+ dictWord{8, 10, 40},
+ dictWord{9, 10, 56},
+ dictWord{9, 10, 294},
+ dictWord{11, 10, 969},
+ dictWord{11, 10, 995},
+ dictWord{146, 10, 148},
+ dictWord{
+ 4,
+ 0,
+ 356,
+ },
+ dictWord{5, 0, 217},
+ dictWord{5, 0, 492},
+ dictWord{5, 0, 656},
+ dictWord{8, 0, 544},
+ dictWord{136, 11, 544},
+ dictWord{5, 0, 259},
+ dictWord{6, 0, 1230},
+ dictWord{7, 0, 414},
+ dictWord{7, 0, 854},
+ dictWord{142, 0, 107},
+ dictWord{132, 0, 1007},
+ dictWord{15, 0, 14},
+ dictWord{144, 0, 5},
+ dictWord{6, 0, 1580},
+ dictWord{
+ 132,
+ 10,
+ 738,
+ },
+ dictWord{132, 11, 596},
+ dictWord{132, 0, 673},
+ dictWord{133, 10, 866},
+ dictWord{6, 0, 1843},
+ dictWord{135, 11, 1847},
+ dictWord{4, 0, 165},
+ dictWord{7, 0, 1398},
+ dictWord{135, 0, 1829},
+ dictWord{135, 11, 1634},
+ dictWord{147, 11, 65},
+ dictWord{6, 0, 885},
+ dictWord{6, 0, 1009},
+ dictWord{
+ 137,
+ 0,
+ 809,
+ },
+ dictWord{133, 10, 116},
+ dictWord{132, 10, 457},
+ dictWord{136, 11, 770},
+ dictWord{9, 0, 498},
+ dictWord{12, 0, 181},
+ dictWord{10, 11, 361},
+ dictWord{142, 11, 316},
+ dictWord{134, 11, 595},
+ dictWord{5, 0, 9},
+ dictWord{7, 0, 297},
+ dictWord{7, 0, 966},
+ dictWord{140, 0, 306},
+ dictWord{4, 11, 89},
+ dictWord{
+ 5,
+ 11,
+ 489,
+ },
+ dictWord{6, 11, 315},
+ dictWord{7, 11, 553},
+ dictWord{7, 11, 1745},
+ dictWord{138, 11, 243},
+ dictWord{134, 0, 1487},
+ dictWord{132, 0, 437},
+ dictWord{
+ 5,
+ 0,
+ 146,
+ },
+ dictWord{6, 0, 411},
+ dictWord{138, 0, 721},
+ dictWord{5, 10, 527},
+ dictWord{6, 10, 189},
+ dictWord{135, 10, 859},
+ dictWord{11, 10, 104},
+ dictWord{
+ 11,
+ 10,
+ 554,
+ },
+ dictWord{15, 10, 60},
+ dictWord{143, 10, 125},
+ dictWord{6, 11, 1658},
+ dictWord{9, 11, 3},
+ dictWord{10, 11, 154},
+ dictWord{11, 11, 641},
+ dictWord{13, 11, 85},
+ dictWord{13, 11, 201},
+ dictWord{141, 11, 346},
+ dictWord{6, 0, 177},
+ dictWord{135, 0, 467},
+ dictWord{134, 0, 1377},
+ dictWord{
+ 134,
+ 10,
+ 116,
+ },
+ dictWord{136, 11, 645},
+ dictWord{4, 11, 166},
+ dictWord{5, 11, 505},
+ dictWord{6, 11, 1670},
+ dictWord{137, 11, 110},
+ dictWord{133, 10, 487},
+ dictWord{
+ 4,
+ 10,
+ 86,
+ },
+ dictWord{5, 10, 667},
+ dictWord{5, 10, 753},
+ dictWord{6, 10, 316},
+ dictWord{6, 10, 455},
+ dictWord{135, 10, 946},
+ dictWord{133, 0, 200},
+ dictWord{132, 0, 959},
+ dictWord{6, 0, 1928},
+ dictWord{134, 0, 1957},
+ dictWord{139, 11, 203},
+ dictWord{150, 10, 45},
+ dictWord{4, 10, 79},
+ dictWord{7, 10, 1773},
+ dictWord{10, 10, 450},
+ dictWord{11, 10, 589},
+ dictWord{13, 10, 332},
+ dictWord{13, 10, 493},
+ dictWord{14, 10, 183},
+ dictWord{14, 10, 334},
+ dictWord{
+ 14,
+ 10,
+ 362,
+ },
+ dictWord{14, 10, 368},
+ dictWord{14, 10, 376},
+ dictWord{14, 10, 379},
+ dictWord{19, 10, 90},
+ dictWord{19, 10, 103},
+ dictWord{19, 10, 127},
+ dictWord{148, 10, 90},
+ dictWord{6, 0, 1435},
+ dictWord{135, 11, 1275},
+ dictWord{134, 0, 481},
+ dictWord{7, 11, 445},
+ dictWord{8, 11, 307},
+ dictWord{8, 11, 704},
+ dictWord{10, 11, 41},
+ dictWord{10, 11, 439},
+ dictWord{11, 11, 237},
+ dictWord{11, 11, 622},
+ dictWord{140, 11, 201},
+ dictWord{135, 11, 869},
+ dictWord{
+ 4,
+ 0,
+ 84,
+ },
+ dictWord{7, 0, 1482},
+ dictWord{10, 0, 76},
+ dictWord{138, 0, 142},
+ dictWord{11, 11, 277},
+ dictWord{144, 11, 14},
+ dictWord{135, 11, 1977},
+ dictWord{
+ 4,
+ 11,
+ 189,
+ },
+ dictWord{5, 11, 713},
+ dictWord{136, 11, 57},
+ dictWord{133, 0, 1015},
+ dictWord{138, 11, 371},
+ dictWord{4, 0, 315},
+ dictWord{5, 0, 507},
+ dictWord{
+ 135,
+ 0,
+ 1370,
+ },
+ dictWord{4, 11, 552},
+ dictWord{142, 10, 381},
+ dictWord{9, 0, 759},
+ dictWord{16, 0, 31},
+ dictWord{16, 0, 39},
+ dictWord{16, 0, 75},
+ dictWord{18, 0, 24},
+ dictWord{20, 0, 42},
+ dictWord{152, 0, 1},
+ dictWord{134, 0, 712},
+ dictWord{134, 0, 1722},
+ dictWord{133, 10, 663},
+ dictWord{133, 10, 846},
+ dictWord{
+ 8,
+ 0,
+ 222,
+ },
+ dictWord{8, 0, 476},
+ dictWord{9, 0, 238},
+ dictWord{11, 0, 516},
+ dictWord{11, 0, 575},
+ dictWord{15, 0, 109},
+ dictWord{146, 0, 100},
+ dictWord{7, 0, 1402},
+ dictWord{7, 0, 1414},
+ dictWord{12, 0, 456},
+ dictWord{5, 10, 378},
+ dictWord{8, 10, 465},
+ dictWord{9, 10, 286},
+ dictWord{10, 10, 185},
+ dictWord{10, 10, 562},
+ dictWord{10, 10, 635},
+ dictWord{11, 10, 31},
+ dictWord{11, 10, 393},
+ dictWord{13, 10, 312},
+ dictWord{18, 10, 65},
+ dictWord{18, 10, 96},
+ dictWord{147, 10, 89},
+ dictWord{4, 0, 986},
+ dictWord{6, 0, 1958},
+ dictWord{6, 0, 2032},
+ dictWord{8, 0, 934},
+ dictWord{138, 0, 985},
+ dictWord{7, 10, 1880},
+ dictWord{9, 10, 680},
+ dictWord{139, 10, 798},
+ dictWord{134, 10, 1770},
+ dictWord{145, 11, 49},
+ dictWord{132, 11, 614},
+ dictWord{132, 10, 648},
+ dictWord{5, 10, 945},
+ dictWord{
+ 6,
+ 10,
+ 1656,
+ },
+ dictWord{6, 10, 1787},
+ dictWord{7, 10, 167},
+ dictWord{8, 10, 824},
+ dictWord{9, 10, 391},
+ dictWord{10, 10, 375},
+ dictWord{139, 10, 185},
+ dictWord{138, 11, 661},
+ dictWord{7, 0, 1273},
+ dictWord{135, 11, 1945},
+ dictWord{7, 0, 706},
+ dictWord{7, 0, 1058},
+ dictWord{138, 0, 538},
+ dictWord{7, 10, 1645},
+ dictWord{8, 10, 352},
+ dictWord{137, 10, 249},
+ dictWord{132, 10, 152},
+ dictWord{11, 0, 92},
+ dictWord{11, 0, 196},
+ dictWord{11, 0, 409},
+ dictWord{11, 0, 450},
+ dictWord{11, 0, 666},
+ dictWord{11, 0, 777},
+ dictWord{12, 0, 262},
+ dictWord{13, 0, 385},
+ dictWord{13, 0, 393},
+ dictWord{15, 0, 115},
+ dictWord{16, 0, 45},
+ dictWord{145, 0, 82},
+ dictWord{133, 10, 1006},
+ dictWord{6, 0, 40},
+ dictWord{135, 0, 1781},
+ dictWord{9, 11, 614},
+ dictWord{139, 11, 327},
+ dictWord{5, 10, 420},
+ dictWord{135, 10, 1449},
+ dictWord{135, 0, 431},
+ dictWord{10, 0, 97},
+ dictWord{135, 10, 832},
+ dictWord{6, 0, 423},
+ dictWord{7, 0, 665},
+ dictWord{
+ 135,
+ 0,
+ 1210,
+ },
+ dictWord{7, 0, 237},
+ dictWord{8, 0, 664},
+ dictWord{9, 0, 42},
+ dictWord{9, 0, 266},
+ dictWord{9, 0, 380},
+ dictWord{9, 0, 645},
+ dictWord{10, 0, 177},
+ dictWord{
+ 138,
+ 0,
+ 276,
+ },
+ dictWord{7, 0, 264},
+ dictWord{133, 10, 351},
+ dictWord{8, 0, 213},
+ dictWord{5, 10, 40},
+ dictWord{7, 10, 598},
+ dictWord{7, 10, 1638},
+ dictWord{
+ 9,
+ 10,
+ 166,
+ },
+ dictWord{9, 10, 640},
+ dictWord{9, 10, 685},
+ dictWord{9, 10, 773},
+ dictWord{11, 10, 215},
+ dictWord{13, 10, 65},
+ dictWord{14, 10, 172},
+ dictWord{
+ 14,
+ 10,
+ 317,
+ },
+ dictWord{145, 10, 6},
+ dictWord{5, 11, 84},
+ dictWord{134, 11, 163},
+ dictWord{8, 10, 60},
+ dictWord{9, 10, 343},
+ dictWord{139, 10, 769},
+ dictWord{
+ 137,
+ 0,
+ 455,
+ },
+ dictWord{133, 11, 410},
+ dictWord{8, 0, 906},
+ dictWord{12, 0, 700},
+ dictWord{12, 0, 706},
+ dictWord{140, 0, 729},
+ dictWord{21, 11, 33},
+ dictWord{
+ 150,
+ 11,
+ 40,
+ },
+ dictWord{7, 10, 1951},
+ dictWord{8, 10, 765},
+ dictWord{8, 10, 772},
+ dictWord{140, 10, 671},
+ dictWord{7, 10, 108},
+ dictWord{8, 10, 219},
+ dictWord{
+ 8,
+ 10,
+ 388,
+ },
+ dictWord{9, 10, 639},
+ dictWord{9, 10, 775},
+ dictWord{11, 10, 275},
+ dictWord{140, 10, 464},
+ dictWord{5, 11, 322},
+ dictWord{7, 11, 1941},
+ dictWord{
+ 8,
+ 11,
+ 186,
+ },
+ dictWord{9, 11, 262},
+ dictWord{10, 11, 187},
+ dictWord{14, 11, 208},
+ dictWord{146, 11, 130},
+ dictWord{139, 0, 624},
+ dictWord{8, 0, 574},
+ dictWord{
+ 5,
+ 11,
+ 227,
+ },
+ dictWord{140, 11, 29},
+ dictWord{7, 11, 1546},
+ dictWord{11, 11, 299},
+ dictWord{142, 11, 407},
+ dictWord{5, 10, 15},
+ dictWord{6, 10, 56},
+ dictWord{
+ 7,
+ 10,
+ 1758,
+ },
+ dictWord{8, 10, 500},
+ dictWord{9, 10, 730},
+ dictWord{11, 10, 331},
+ dictWord{13, 10, 150},
+ dictWord{142, 10, 282},
+ dictWord{7, 11, 1395},
+ dictWord{8, 11, 486},
+ dictWord{9, 11, 236},
+ dictWord{9, 11, 878},
+ dictWord{10, 11, 218},
+ dictWord{11, 11, 95},
+ dictWord{19, 11, 17},
+ dictWord{147, 11, 31},
+ dictWord{135, 11, 2043},
+ dictWord{4, 0, 354},
+ dictWord{146, 11, 4},
+ dictWord{140, 11, 80},
+ dictWord{135, 0, 1558},
+ dictWord{134, 10, 1886},
+ dictWord{
+ 5,
+ 10,
+ 205,
+ },
+ dictWord{6, 10, 438},
+ dictWord{137, 10, 711},
+ dictWord{133, 11, 522},
+ dictWord{133, 10, 534},
+ dictWord{7, 0, 235},
+ dictWord{7, 0, 1475},
+ dictWord{
+ 15,
+ 0,
+ 68,
+ },
+ dictWord{146, 0, 120},
+ dictWord{137, 10, 691},
+ dictWord{4, 0, 942},
+ dictWord{6, 0, 1813},
+ dictWord{8, 0, 917},
+ dictWord{10, 0, 884},
+ dictWord{
+ 12,
+ 0,
+ 696,
+ },
+ dictWord{12, 0, 717},
+ dictWord{12, 0, 723},
+ dictWord{12, 0, 738},
+ dictWord{12, 0, 749},
+ dictWord{12, 0, 780},
+ dictWord{16, 0, 97},
+ dictWord{146, 0, 169},
+ dictWord{6, 10, 443},
+ dictWord{8, 11, 562},
+ dictWord{9, 10, 237},
+ dictWord{9, 10, 571},
+ dictWord{9, 10, 695},
+ dictWord{10, 10, 139},
+ dictWord{11, 10, 715},
+ dictWord{12, 10, 417},
+ dictWord{141, 10, 421},
+ dictWord{135, 0, 957},
+ dictWord{133, 0, 830},
+ dictWord{134, 11, 1771},
+ dictWord{146, 0, 23},
+ dictWord{
+ 5,
+ 0,
+ 496,
+ },
+ dictWord{6, 0, 694},
+ dictWord{7, 0, 203},
+ dictWord{7, 11, 1190},
+ dictWord{137, 11, 620},
+ dictWord{137, 11, 132},
+ dictWord{6, 0, 547},
+ dictWord{
+ 134,
+ 0,
+ 1549,
+ },
+ dictWord{8, 11, 258},
+ dictWord{9, 11, 208},
+ dictWord{137, 11, 359},
+ dictWord{4, 0, 864},
+ dictWord{5, 0, 88},
+ dictWord{137, 0, 239},
+ dictWord{
+ 135,
+ 11,
+ 493,
+ },
+ dictWord{4, 11, 317},
+ dictWord{135, 11, 1279},
+ dictWord{132, 11, 477},
+ dictWord{4, 10, 578},
+ dictWord{5, 11, 63},
+ dictWord{133, 11, 509},
+ dictWord{
+ 7,
+ 0,
+ 650,
+ },
+ dictWord{135, 0, 1310},
+ dictWord{7, 0, 1076},
+ dictWord{9, 0, 80},
+ dictWord{11, 0, 78},
+ dictWord{11, 0, 421},
+ dictWord{11, 0, 534},
+ dictWord{
+ 140,
+ 0,
+ 545,
+ },
+ dictWord{132, 11, 288},
+ dictWord{12, 0, 553},
+ dictWord{14, 0, 118},
+ dictWord{133, 10, 923},
+ dictWord{7, 0, 274},
+ dictWord{11, 0, 479},
+ dictWord{
+ 139,
+ 0,
+ 507,
+ },
+ dictWord{8, 11, 89},
+ dictWord{8, 11, 620},
+ dictWord{9, 11, 49},
+ dictWord{10, 11, 774},
+ dictWord{11, 11, 628},
+ dictWord{12, 11, 322},
+ dictWord{
+ 143,
+ 11,
+ 124,
+ },
+ dictWord{4, 0, 497},
+ dictWord{135, 0, 1584},
+ dictWord{7, 0, 261},
+ dictWord{7, 0, 1115},
+ dictWord{7, 0, 1354},
+ dictWord{7, 0, 1404},
+ dictWord{
+ 7,
+ 0,
+ 1588,
+ },
+ dictWord{7, 0, 1705},
+ dictWord{7, 0, 1902},
+ dictWord{9, 0, 465},
+ dictWord{10, 0, 248},
+ dictWord{10, 0, 349},
+ dictWord{10, 0, 647},
+ dictWord{11, 0, 527},
+ dictWord{11, 0, 660},
+ dictWord{11, 0, 669},
+ dictWord{12, 0, 529},
+ dictWord{13, 0, 305},
+ dictWord{132, 10, 924},
+ dictWord{133, 10, 665},
+ dictWord{
+ 136,
+ 0,
+ 13,
+ },
+ dictWord{6, 0, 791},
+ dictWord{138, 11, 120},
+ dictWord{7, 0, 642},
+ dictWord{8, 0, 250},
+ dictWord{11, 0, 123},
+ dictWord{11, 0, 137},
+ dictWord{13, 0, 48},
+ dictWord{142, 0, 95},
+ dictWord{4, 10, 265},
+ dictWord{7, 10, 807},
+ dictWord{135, 10, 950},
+ dictWord{5, 10, 93},
+ dictWord{140, 10, 267},
+ dictWord{135, 0, 1429},
+ dictWord{4, 0, 949},
+ dictWord{10, 0, 885},
+ dictWord{10, 0, 891},
+ dictWord{10, 0, 900},
+ dictWord{10, 0, 939},
+ dictWord{12, 0, 760},
+ dictWord{142, 0, 449},
+ dictWord{139, 11, 366},
+ dictWord{132, 0, 818},
+ dictWord{134, 11, 85},
+ dictWord{135, 10, 994},
+ dictWord{7, 0, 330},
+ dictWord{5, 10, 233},
+ dictWord{5, 10, 320},
+ dictWord{6, 10, 140},
+ dictWord{136, 10, 295},
+ dictWord{4, 0, 1004},
+ dictWord{8, 0, 982},
+ dictWord{136, 0, 993},
+ dictWord{133, 10, 978},
+ dictWord{4, 10, 905},
+ dictWord{6, 10, 1701},
+ dictWord{137, 10, 843},
+ dictWord{10, 0, 545},
+ dictWord{140, 0, 301},
+ dictWord{6, 0, 947},
+ dictWord{134, 0, 1062},
+ dictWord{
+ 134,
+ 0,
+ 1188,
+ },
+ dictWord{4, 0, 904},
+ dictWord{5, 0, 794},
+ dictWord{152, 10, 6},
+ dictWord{134, 0, 1372},
+ dictWord{135, 11, 608},
+ dictWord{5, 11, 279},
+ dictWord{
+ 6,
+ 11,
+ 235,
+ },
+ dictWord{7, 11, 468},
+ dictWord{8, 11, 446},
+ dictWord{9, 11, 637},
+ dictWord{10, 11, 717},
+ dictWord{11, 11, 738},
+ dictWord{140, 11, 514},
+ dictWord{
+ 132,
+ 10,
+ 509,
+ },
+ dictWord{5, 11, 17},
+ dictWord{6, 11, 371},
+ dictWord{137, 11, 528},
+ dictWord{132, 0, 693},
+ dictWord{4, 11, 115},
+ dictWord{5, 11, 669},
+ dictWord{
+ 6,
+ 11,
+ 407,
+ },
+ dictWord{8, 11, 311},
+ dictWord{11, 11, 10},
+ dictWord{141, 11, 5},
+ dictWord{11, 0, 377},
+ dictWord{7, 10, 273},
+ dictWord{137, 11, 381},
+ dictWord{
+ 135,
+ 0,
+ 695,
+ },
+ dictWord{7, 0, 386},
+ dictWord{138, 0, 713},
+ dictWord{135, 10, 1041},
+ dictWord{134, 0, 1291},
+ dictWord{6, 0, 7},
+ dictWord{6, 0, 35},
+ dictWord{
+ 7,
+ 0,
+ 147,
+ },
+ dictWord{7, 0, 1069},
+ dictWord{7, 0, 1568},
+ dictWord{7, 0, 1575},
+ dictWord{7, 0, 1917},
+ dictWord{8, 0, 43},
+ dictWord{8, 0, 208},
+ dictWord{9, 0, 128},
+ dictWord{
+ 9,
+ 0,
+ 866,
+ },
+ dictWord{10, 0, 20},
+ dictWord{11, 0, 981},
+ dictWord{147, 0, 33},
+ dictWord{7, 0, 893},
+ dictWord{141, 0, 424},
+ dictWord{139, 10, 234},
+ dictWord{
+ 150,
+ 11,
+ 56,
+ },
+ dictWord{5, 11, 779},
+ dictWord{5, 11, 807},
+ dictWord{6, 11, 1655},
+ dictWord{134, 11, 1676},
+ dictWord{5, 10, 802},
+ dictWord{7, 10, 2021},
+ dictWord{136, 10, 805},
+ dictWord{4, 11, 196},
+ dictWord{5, 10, 167},
+ dictWord{5, 11, 558},
+ dictWord{5, 10, 899},
+ dictWord{5, 11, 949},
+ dictWord{6, 10, 410},
+ dictWord{137, 10, 777},
+ dictWord{137, 10, 789},
+ dictWord{134, 10, 1705},
+ dictWord{8, 0, 904},
+ dictWord{140, 0, 787},
+ dictWord{6, 0, 322},
+ dictWord{9, 0, 552},
+ dictWord{11, 0, 274},
+ dictWord{13, 0, 209},
+ dictWord{13, 0, 499},
+ dictWord{14, 0, 85},
+ dictWord{15, 0, 126},
+ dictWord{145, 0, 70},
+ dictWord{135, 10, 10},
+ dictWord{
+ 5,
+ 10,
+ 11,
+ },
+ dictWord{6, 10, 117},
+ dictWord{6, 10, 485},
+ dictWord{7, 10, 1133},
+ dictWord{9, 10, 582},
+ dictWord{9, 10, 594},
+ dictWord{11, 10, 21},
+ dictWord{
+ 11,
+ 10,
+ 818,
+ },
+ dictWord{12, 10, 535},
+ dictWord{141, 10, 86},
+ dictWord{4, 10, 264},
+ dictWord{7, 10, 1067},
+ dictWord{8, 10, 204},
+ dictWord{8, 10, 385},
+ dictWord{139, 10, 953},
+ dictWord{132, 11, 752},
+ dictWord{138, 10, 56},
+ dictWord{133, 10, 470},
+ dictWord{6, 0, 1808},
+ dictWord{8, 0, 83},
+ dictWord{8, 0, 742},
+ dictWord{8, 0, 817},
+ dictWord{9, 0, 28},
+ dictWord{9, 0, 29},
+ dictWord{9, 0, 885},
+ dictWord{10, 0, 387},
+ dictWord{11, 0, 633},
+ dictWord{11, 0, 740},
+ dictWord{13, 0, 235},
+ dictWord{13, 0, 254},
+ dictWord{15, 0, 143},
+ dictWord{143, 0, 146},
+ dictWord{140, 0, 49},
+ dictWord{134, 0, 1832},
+ dictWord{4, 11, 227},
+ dictWord{5, 11, 159},
+ dictWord{5, 11, 409},
+ dictWord{7, 11, 80},
+ dictWord{10, 11, 294},
+ dictWord{10, 11, 479},
+ dictWord{12, 11, 418},
+ dictWord{14, 11, 50},
+ dictWord{14, 11, 249},
+ dictWord{142, 11, 295},
+ dictWord{7, 11, 1470},
+ dictWord{8, 11, 66},
+ dictWord{8, 11, 137},
+ dictWord{8, 11, 761},
+ dictWord{9, 11, 638},
+ dictWord{11, 11, 80},
+ dictWord{11, 11, 212},
+ dictWord{11, 11, 368},
+ dictWord{11, 11, 418},
+ dictWord{12, 11, 8},
+ dictWord{13, 11, 15},
+ dictWord{16, 11, 61},
+ dictWord{17, 11, 59},
+ dictWord{19, 11, 28},
+ dictWord{148, 11, 84},
+ dictWord{139, 10, 1015},
+ dictWord{138, 11, 468},
+ dictWord{135, 0, 421},
+ dictWord{6, 0, 415},
+ dictWord{
+ 7,
+ 0,
+ 1049,
+ },
+ dictWord{137, 0, 442},
+ dictWord{6, 11, 38},
+ dictWord{7, 11, 1220},
+ dictWord{8, 11, 185},
+ dictWord{8, 11, 256},
+ dictWord{9, 11, 22},
+ dictWord{
+ 9,
+ 11,
+ 331,
+ },
+ dictWord{10, 11, 738},
+ dictWord{11, 11, 205},
+ dictWord{11, 11, 540},
+ dictWord{11, 11, 746},
+ dictWord{13, 11, 399},
+ dictWord{13, 11, 465},
+ dictWord{
+ 14,
+ 11,
+ 88,
+ },
+ dictWord{142, 11, 194},
+ dictWord{139, 0, 289},
+ dictWord{133, 10, 715},
+ dictWord{4, 0, 110},
+ dictWord{10, 0, 415},
+ dictWord{10, 0, 597},
+ dictWord{142, 0, 206},
+ dictWord{4, 11, 159},
+ dictWord{6, 11, 115},
+ dictWord{7, 11, 252},
+ dictWord{7, 11, 257},
+ dictWord{7, 11, 1928},
+ dictWord{8, 11, 69},
+ dictWord{
+ 9,
+ 11,
+ 384,
+ },
+ dictWord{10, 11, 91},
+ dictWord{10, 11, 615},
+ dictWord{12, 11, 375},
+ dictWord{14, 11, 235},
+ dictWord{18, 11, 117},
+ dictWord{147, 11, 123},
+ dictWord{5, 11, 911},
+ dictWord{136, 11, 278},
+ dictWord{7, 0, 205},
+ dictWord{7, 0, 2000},
+ dictWord{8, 10, 794},
+ dictWord{9, 10, 400},
+ dictWord{10, 10, 298},
+ dictWord{142, 10, 228},
+ dictWord{135, 11, 1774},
+ dictWord{4, 11, 151},
+ dictWord{7, 11, 1567},
+ dictWord{8, 11, 351},
+ dictWord{137, 11, 322},
+ dictWord{
+ 136,
+ 10,
+ 724,
+ },
+ dictWord{133, 11, 990},
+ dictWord{7, 0, 1539},
+ dictWord{11, 0, 512},
+ dictWord{13, 0, 205},
+ dictWord{19, 0, 30},
+ dictWord{22, 0, 36},
+ dictWord{23, 0, 19},
+ dictWord{135, 11, 1539},
+ dictWord{5, 11, 194},
+ dictWord{7, 11, 1662},
+ dictWord{9, 11, 90},
+ dictWord{140, 11, 180},
+ dictWord{6, 10, 190},
+ dictWord{
+ 7,
+ 10,
+ 768,
+ },
+ dictWord{135, 10, 1170},
+ dictWord{134, 0, 1340},
+ dictWord{4, 0, 283},
+ dictWord{135, 0, 1194},
+ dictWord{133, 11, 425},
+ dictWord{133, 11, 971},
+ dictWord{12, 0, 549},
+ dictWord{14, 10, 67},
+ dictWord{147, 10, 60},
+ dictWord{135, 10, 1023},
+ dictWord{134, 0, 1720},
+ dictWord{138, 11, 587},
+ dictWord{
+ 5,
+ 11,
+ 72,
+ },
+ dictWord{6, 11, 264},
+ dictWord{7, 11, 21},
+ dictWord{7, 11, 46},
+ dictWord{7, 11, 2013},
+ dictWord{8, 11, 215},
+ dictWord{8, 11, 513},
+ dictWord{10, 11, 266},
+ dictWord{139, 11, 22},
+ dictWord{5, 0, 319},
+ dictWord{135, 0, 534},
+ dictWord{6, 10, 137},
+ dictWord{9, 10, 75},
+ dictWord{9, 10, 253},
+ dictWord{10, 10, 194},
+ dictWord{138, 10, 444},
+ dictWord{7, 0, 1180},
+ dictWord{20, 0, 112},
+ dictWord{6, 11, 239},
+ dictWord{7, 11, 118},
+ dictWord{10, 11, 95},
+ dictWord{11, 11, 603},
+ dictWord{13, 11, 443},
+ dictWord{14, 11, 160},
+ dictWord{143, 11, 4},
+ dictWord{134, 11, 431},
+ dictWord{5, 11, 874},
+ dictWord{6, 11, 1677},
+ dictWord{
+ 11,
+ 10,
+ 643,
+ },
+ dictWord{12, 10, 115},
+ dictWord{143, 11, 0},
+ dictWord{134, 0, 967},
+ dictWord{6, 11, 65},
+ dictWord{7, 11, 939},
+ dictWord{7, 11, 1172},
+ dictWord{
+ 7,
+ 11,
+ 1671,
+ },
+ dictWord{9, 11, 540},
+ dictWord{10, 11, 696},
+ dictWord{11, 11, 265},
+ dictWord{11, 11, 732},
+ dictWord{11, 11, 928},
+ dictWord{11, 11, 937},
+ dictWord{
+ 12,
+ 11,
+ 399,
+ },
+ dictWord{13, 11, 438},
+ dictWord{149, 11, 19},
+ dictWord{137, 11, 200},
+ dictWord{135, 0, 1940},
+ dictWord{5, 10, 760},
+ dictWord{7, 10, 542},
+ dictWord{8, 10, 135},
+ dictWord{136, 10, 496},
+ dictWord{140, 11, 44},
+ dictWord{7, 11, 1655},
+ dictWord{136, 11, 305},
+ dictWord{7, 10, 319},
+ dictWord{
+ 7,
+ 10,
+ 355,
+ },
+ dictWord{7, 10, 763},
+ dictWord{10, 10, 389},
+ dictWord{145, 10, 43},
+ dictWord{136, 0, 735},
+ dictWord{138, 10, 786},
+ dictWord{137, 11, 19},
+ dictWord{132, 11, 696},
+ dictWord{5, 0, 132},
+ dictWord{9, 0, 486},
+ dictWord{9, 0, 715},
+ dictWord{10, 0, 458},
+ dictWord{11, 0, 373},
+ dictWord{11, 0, 668},
+ dictWord{
+ 11,
+ 0,
+ 795,
+ },
+ dictWord{11, 0, 897},
+ dictWord{12, 0, 272},
+ dictWord{12, 0, 424},
+ dictWord{12, 0, 539},
+ dictWord{12, 0, 558},
+ dictWord{14, 0, 245},
+ dictWord{
+ 14,
+ 0,
+ 263,
+ },
+ dictWord{14, 0, 264},
+ dictWord{14, 0, 393},
+ dictWord{142, 0, 403},
+ dictWord{10, 0, 38},
+ dictWord{139, 0, 784},
+ dictWord{132, 0, 838},
+ dictWord{
+ 4,
+ 11,
+ 302,
+ },
+ dictWord{135, 11, 1766},
+ dictWord{133, 0, 379},
+ dictWord{5, 0, 8},
+ dictWord{6, 0, 89},
+ dictWord{6, 0, 400},
+ dictWord{7, 0, 1569},
+ dictWord{7, 0, 1623},
+ dictWord{7, 0, 1850},
+ dictWord{8, 0, 218},
+ dictWord{8, 0, 422},
+ dictWord{9, 0, 570},
+ dictWord{10, 0, 626},
+ dictWord{4, 11, 726},
+ dictWord{133, 11, 630},
+ dictWord{
+ 4,
+ 0,
+ 1017,
+ },
+ dictWord{138, 0, 660},
+ dictWord{6, 0, 387},
+ dictWord{7, 0, 882},
+ dictWord{141, 0, 111},
+ dictWord{6, 0, 224},
+ dictWord{7, 0, 877},
+ dictWord{
+ 137,
+ 0,
+ 647,
+ },
+ dictWord{4, 10, 58},
+ dictWord{5, 10, 286},
+ dictWord{6, 10, 319},
+ dictWord{7, 10, 402},
+ dictWord{7, 10, 1254},
+ dictWord{7, 10, 1903},
+ dictWord{
+ 8,
+ 10,
+ 356,
+ },
+ dictWord{140, 10, 408},
+ dictWord{135, 0, 790},
+ dictWord{9, 0, 510},
+ dictWord{10, 0, 53},
+ dictWord{4, 10, 389},
+ dictWord{9, 10, 181},
+ dictWord{
+ 10,
+ 10,
+ 29,
+ },
+ dictWord{10, 10, 816},
+ dictWord{11, 10, 311},
+ dictWord{11, 10, 561},
+ dictWord{12, 10, 67},
+ dictWord{141, 10, 181},
+ dictWord{142, 0, 458},
+ dictWord{
+ 6,
+ 11,
+ 118,
+ },
+ dictWord{7, 11, 215},
+ dictWord{7, 11, 1521},
+ dictWord{140, 11, 11},
+ dictWord{134, 0, 954},
+ dictWord{135, 0, 394},
+ dictWord{134, 0, 1367},
+ dictWord{5, 11, 225},
+ dictWord{133, 10, 373},
+ dictWord{132, 0, 882},
+ dictWord{7, 0, 1409},
+ dictWord{135, 10, 1972},
+ dictWord{135, 10, 1793},
+ dictWord{
+ 4,
+ 11,
+ 370,
+ },
+ dictWord{5, 11, 756},
+ dictWord{135, 11, 1326},
+ dictWord{150, 11, 13},
+ dictWord{7, 11, 354},
+ dictWord{10, 11, 410},
+ dictWord{139, 11, 815},
+ dictWord{6, 11, 1662},
+ dictWord{7, 11, 48},
+ dictWord{8, 11, 771},
+ dictWord{10, 11, 116},
+ dictWord{13, 11, 104},
+ dictWord{14, 11, 105},
+ dictWord{14, 11, 184},
+ dictWord{15, 11, 168},
+ dictWord{19, 11, 92},
+ dictWord{148, 11, 68},
+ dictWord{7, 0, 124},
+ dictWord{136, 0, 38},
+ dictWord{5, 0, 261},
+ dictWord{7, 0, 78},
+ dictWord{
+ 7,
+ 0,
+ 199,
+ },
+ dictWord{8, 0, 815},
+ dictWord{9, 0, 126},
+ dictWord{10, 0, 342},
+ dictWord{140, 0, 647},
+ dictWord{4, 0, 628},
+ dictWord{140, 0, 724},
+ dictWord{7, 0, 266},
+ dictWord{8, 0, 804},
+ dictWord{7, 10, 1651},
+ dictWord{145, 10, 89},
+ dictWord{135, 0, 208},
+ dictWord{134, 0, 1178},
+ dictWord{6, 0, 79},
+ dictWord{135, 0, 1519},
+ dictWord{132, 10, 672},
+ dictWord{133, 10, 737},
+ dictWord{136, 0, 741},
+ dictWord{132, 11, 120},
+ dictWord{4, 0, 710},
+ dictWord{6, 0, 376},
+ dictWord{
+ 134,
+ 0,
+ 606,
+ },
+ dictWord{134, 0, 1347},
+ dictWord{134, 0, 1494},
+ dictWord{6, 0, 850},
+ dictWord{6, 0, 1553},
+ dictWord{137, 0, 821},
+ dictWord{5, 10, 145},
+ dictWord{
+ 134,
+ 11,
+ 593,
+ },
+ dictWord{7, 0, 1311},
+ dictWord{140, 0, 135},
+ dictWord{4, 0, 467},
+ dictWord{5, 0, 405},
+ dictWord{134, 0, 544},
+ dictWord{5, 11, 820},
+ dictWord{
+ 135,
+ 11,
+ 931,
+ },
+ dictWord{6, 0, 100},
+ dictWord{7, 0, 244},
+ dictWord{7, 0, 632},
+ dictWord{7, 0, 1609},
+ dictWord{8, 0, 178},
+ dictWord{8, 0, 638},
+ dictWord{141, 0, 58},
+ dictWord{4, 10, 387},
+ dictWord{135, 10, 1288},
+ dictWord{6, 11, 151},
+ dictWord{6, 11, 1675},
+ dictWord{7, 11, 383},
+ dictWord{151, 11, 10},
+ dictWord{
+ 132,
+ 0,
+ 481,
+ },
+ dictWord{135, 10, 550},
+ dictWord{134, 0, 1378},
+ dictWord{6, 11, 1624},
+ dictWord{11, 11, 11},
+ dictWord{12, 11, 422},
+ dictWord{13, 11, 262},
+ dictWord{142, 11, 360},
+ dictWord{133, 0, 791},
+ dictWord{4, 11, 43},
+ dictWord{5, 11, 344},
+ dictWord{133, 11, 357},
+ dictWord{7, 0, 1227},
+ dictWord{140, 0, 978},
+ dictWord{7, 0, 686},
+ dictWord{8, 0, 33},
+ dictWord{8, 0, 238},
+ dictWord{10, 0, 616},
+ dictWord{11, 0, 467},
+ dictWord{11, 0, 881},
+ dictWord{13, 0, 217},
+ dictWord{
+ 13,
+ 0,
+ 253,
+ },
+ dictWord{142, 0, 268},
+ dictWord{137, 0, 857},
+ dictWord{8, 0, 467},
+ dictWord{8, 0, 1006},
+ dictWord{7, 11, 148},
+ dictWord{8, 11, 284},
+ dictWord{
+ 141,
+ 11,
+ 63,
+ },
+ dictWord{4, 10, 576},
+ dictWord{135, 10, 1263},
+ dictWord{133, 11, 888},
+ dictWord{5, 10, 919},
+ dictWord{134, 10, 1673},
+ dictWord{20, 10, 37},
+ dictWord{148, 11, 37},
+ dictWord{132, 0, 447},
+ dictWord{132, 11, 711},
+ dictWord{4, 0, 128},
+ dictWord{5, 0, 415},
+ dictWord{6, 0, 462},
+ dictWord{7, 0, 294},
+ dictWord{
+ 7,
+ 0,
+ 578,
+ },
+ dictWord{10, 0, 710},
+ dictWord{139, 0, 86},
+ dictWord{4, 10, 82},
+ dictWord{5, 10, 333},
+ dictWord{5, 10, 904},
+ dictWord{6, 10, 207},
+ dictWord{7, 10, 325},
+ dictWord{7, 10, 1726},
+ dictWord{8, 10, 101},
+ dictWord{10, 10, 778},
+ dictWord{139, 10, 220},
+ dictWord{136, 0, 587},
+ dictWord{137, 11, 440},
+ dictWord{
+ 133,
+ 10,
+ 903,
+ },
+ dictWord{6, 0, 427},
+ dictWord{7, 0, 1018},
+ dictWord{138, 0, 692},
+ dictWord{4, 0, 195},
+ dictWord{135, 0, 802},
+ dictWord{140, 10, 147},
+ dictWord{
+ 134,
+ 0,
+ 1546,
+ },
+ dictWord{134, 0, 684},
+ dictWord{132, 10, 705},
+ dictWord{136, 0, 345},
+ dictWord{11, 11, 678},
+ dictWord{140, 11, 307},
+ dictWord{
+ 133,
+ 0,
+ 365,
+ },
+ dictWord{134, 0, 1683},
+ dictWord{4, 11, 65},
+ dictWord{5, 11, 479},
+ dictWord{5, 11, 1004},
+ dictWord{7, 11, 1913},
+ dictWord{8, 11, 317},
+ dictWord{
+ 9,
+ 11,
+ 302,
+ },
+ dictWord{10, 11, 612},
+ dictWord{141, 11, 22},
+ dictWord{138, 0, 472},
+ dictWord{4, 11, 261},
+ dictWord{135, 11, 510},
+ dictWord{134, 10, 90},
+ dictWord{142, 0, 433},
+ dictWord{151, 0, 28},
+ dictWord{4, 11, 291},
+ dictWord{7, 11, 101},
+ dictWord{9, 11, 515},
+ dictWord{12, 11, 152},
+ dictWord{12, 11, 443},
+ dictWord{13, 11, 392},
+ dictWord{142, 11, 357},
+ dictWord{140, 0, 997},
+ dictWord{5, 0, 3},
+ dictWord{8, 0, 578},
+ dictWord{9, 0, 118},
+ dictWord{10, 0, 705},
+ dictWord{
+ 141,
+ 0,
+ 279,
+ },
+ dictWord{135, 11, 1266},
+ dictWord{7, 10, 813},
+ dictWord{12, 10, 497},
+ dictWord{141, 10, 56},
+ dictWord{133, 0, 229},
+ dictWord{6, 10, 125},
+ dictWord{135, 10, 1277},
+ dictWord{8, 0, 102},
+ dictWord{10, 0, 578},
+ dictWord{10, 0, 672},
+ dictWord{12, 0, 496},
+ dictWord{13, 0, 408},
+ dictWord{14, 0, 121},
+ dictWord{17, 0, 106},
+ dictWord{151, 10, 12},
+ dictWord{6, 0, 866},
+ dictWord{134, 0, 1080},
+ dictWord{136, 0, 1022},
+ dictWord{4, 11, 130},
+ dictWord{135, 11, 843},
+ dictWord{5, 11, 42},
+ dictWord{5, 11, 879},
+ dictWord{7, 11, 245},
+ dictWord{7, 11, 324},
+ dictWord{7, 11, 1532},
+ dictWord{11, 11, 463},
+ dictWord{11, 11, 472},
+ dictWord{13, 11, 363},
+ dictWord{144, 11, 52},
+ dictWord{150, 0, 55},
+ dictWord{8, 0, 115},
+ dictWord{8, 0, 350},
+ dictWord{9, 0, 489},
+ dictWord{10, 0, 128},
+ dictWord{
+ 11,
+ 0,
+ 306,
+ },
+ dictWord{12, 0, 373},
+ dictWord{14, 0, 30},
+ dictWord{17, 0, 79},
+ dictWord{19, 0, 80},
+ dictWord{4, 11, 134},
+ dictWord{133, 11, 372},
+ dictWord{
+ 134,
+ 0,
+ 657,
+ },
+ dictWord{134, 0, 933},
+ dictWord{135, 11, 1147},
+ dictWord{4, 0, 230},
+ dictWord{133, 0, 702},
+ dictWord{134, 0, 1728},
+ dictWord{4, 0, 484},
+ dictWord{
+ 18,
+ 0,
+ 26,
+ },
+ dictWord{19, 0, 42},
+ dictWord{20, 0, 43},
+ dictWord{21, 0, 0},
+ dictWord{23, 0, 27},
+ dictWord{152, 0, 14},
+ dictWord{7, 0, 185},
+ dictWord{135, 0, 703},
+ dictWord{
+ 6,
+ 0,
+ 417,
+ },
+ dictWord{10, 0, 618},
+ dictWord{7, 10, 1106},
+ dictWord{9, 10, 770},
+ dictWord{11, 10, 112},
+ dictWord{140, 10, 413},
+ dictWord{134, 0, 803},
+ dictWord{132, 11, 644},
+ dictWord{134, 0, 1262},
+ dictWord{7, 11, 540},
+ dictWord{12, 10, 271},
+ dictWord{145, 10, 109},
+ dictWord{135, 11, 123},
+ dictWord{
+ 132,
+ 0,
+ 633,
+ },
+ dictWord{134, 11, 623},
+ dictWord{4, 11, 908},
+ dictWord{5, 11, 359},
+ dictWord{5, 11, 508},
+ dictWord{6, 11, 1723},
+ dictWord{7, 11, 343},
+ dictWord{
+ 7,
+ 11,
+ 1996,
+ },
+ dictWord{135, 11, 2026},
+ dictWord{135, 0, 479},
+ dictWord{10, 0, 262},
+ dictWord{7, 10, 304},
+ dictWord{9, 10, 646},
+ dictWord{9, 10, 862},
+ dictWord{
+ 11,
+ 10,
+ 696,
+ },
+ dictWord{12, 10, 208},
+ dictWord{15, 10, 79},
+ dictWord{147, 10, 108},
+ dictWord{4, 11, 341},
+ dictWord{135, 11, 480},
+ dictWord{134, 0, 830},
+ dictWord{5, 0, 70},
+ dictWord{5, 0, 622},
+ dictWord{6, 0, 334},
+ dictWord{7, 0, 1032},
+ dictWord{9, 0, 171},
+ dictWord{11, 0, 26},
+ dictWord{11, 0, 213},
+ dictWord{
+ 11,
+ 0,
+ 637,
+ },
+ dictWord{11, 0, 707},
+ dictWord{12, 0, 202},
+ dictWord{12, 0, 380},
+ dictWord{13, 0, 226},
+ dictWord{13, 0, 355},
+ dictWord{14, 0, 222},
+ dictWord{145, 0, 42},
+ dictWord{135, 10, 981},
+ dictWord{143, 0, 217},
+ dictWord{137, 11, 114},
+ dictWord{4, 0, 23},
+ dictWord{4, 0, 141},
+ dictWord{5, 0, 313},
+ dictWord{5, 0, 1014},
+ dictWord{6, 0, 50},
+ dictWord{6, 0, 51},
+ dictWord{7, 0, 142},
+ dictWord{7, 0, 384},
+ dictWord{7, 0, 559},
+ dictWord{8, 0, 640},
+ dictWord{9, 0, 460},
+ dictWord{9, 0, 783},
+ dictWord{11, 0, 741},
+ dictWord{12, 0, 183},
+ dictWord{141, 0, 488},
+ dictWord{141, 0, 360},
+ dictWord{7, 0, 1586},
+ dictWord{7, 11, 1995},
+ dictWord{8, 11, 299},
+ dictWord{11, 11, 890},
+ dictWord{140, 11, 674},
+ dictWord{132, 10, 434},
+ dictWord{7, 0, 652},
+ dictWord{134, 10, 550},
+ dictWord{7, 0, 766},
+ dictWord{5, 10, 553},
+ dictWord{138, 10, 824},
+ dictWord{7, 0, 737},
+ dictWord{8, 0, 298},
+ dictWord{136, 10, 452},
+ dictWord{4, 11, 238},
+ dictWord{5, 11, 503},
+ dictWord{6, 11, 179},
+ dictWord{7, 11, 2003},
+ dictWord{8, 11, 381},
+ dictWord{8, 11, 473},
+ dictWord{9, 11, 149},
+ dictWord{10, 11, 183},
+ dictWord{15, 11, 45},
+ dictWord{143, 11, 86},
+ dictWord{133, 10, 292},
+ dictWord{5, 0, 222},
+ dictWord{9, 0, 655},
+ dictWord{138, 0, 534},
+ dictWord{138, 10, 135},
+ dictWord{4, 11, 121},
+ dictWord{5, 11, 156},
+ dictWord{5, 11, 349},
+ dictWord{9, 11, 136},
+ dictWord{10, 11, 605},
+ dictWord{14, 11, 342},
+ dictWord{147, 11, 107},
+ dictWord{137, 0, 906},
+ dictWord{6, 0, 1013},
+ dictWord{134, 0, 1250},
+ dictWord{6, 0, 1956},
+ dictWord{6, 0, 2009},
+ dictWord{8, 0, 991},
+ dictWord{144, 0, 120},
+ dictWord{135, 11, 1192},
+ dictWord{
+ 138,
+ 0,
+ 503,
+ },
+ dictWord{5, 0, 154},
+ dictWord{7, 0, 1491},
+ dictWord{10, 0, 379},
+ dictWord{138, 0, 485},
+ dictWord{6, 0, 1867},
+ dictWord{6, 0, 1914},
+ dictWord{6, 0, 1925},
+ dictWord{9, 0, 917},
+ dictWord{9, 0, 925},
+ dictWord{9, 0, 932},
+ dictWord{9, 0, 951},
+ dictWord{9, 0, 1007},
+ dictWord{9, 0, 1013},
+ dictWord{12, 0, 806},
+ dictWord{
+ 12,
+ 0,
+ 810,
+ },
+ dictWord{12, 0, 814},
+ dictWord{12, 0, 816},
+ dictWord{12, 0, 824},
+ dictWord{12, 0, 832},
+ dictWord{12, 0, 837},
+ dictWord{12, 0, 863},
+ dictWord{
+ 12,
+ 0,
+ 868,
+ },
+ dictWord{12, 0, 870},
+ dictWord{12, 0, 889},
+ dictWord{12, 0, 892},
+ dictWord{12, 0, 900},
+ dictWord{12, 0, 902},
+ dictWord{12, 0, 908},
+ dictWord{12, 0, 933},
+ dictWord{12, 0, 942},
+ dictWord{12, 0, 949},
+ dictWord{12, 0, 954},
+ dictWord{15, 0, 175},
+ dictWord{15, 0, 203},
+ dictWord{15, 0, 213},
+ dictWord{15, 0, 218},
+ dictWord{15, 0, 225},
+ dictWord{15, 0, 231},
+ dictWord{15, 0, 239},
+ dictWord{15, 0, 248},
+ dictWord{15, 0, 252},
+ dictWord{18, 0, 190},
+ dictWord{18, 0, 204},
+ dictWord{
+ 18,
+ 0,
+ 215,
+ },
+ dictWord{18, 0, 216},
+ dictWord{18, 0, 222},
+ dictWord{18, 0, 225},
+ dictWord{18, 0, 230},
+ dictWord{18, 0, 239},
+ dictWord{18, 0, 241},
+ dictWord{
+ 21,
+ 0,
+ 42,
+ },
+ dictWord{21, 0, 43},
+ dictWord{21, 0, 44},
+ dictWord{21, 0, 45},
+ dictWord{21, 0, 46},
+ dictWord{21, 0, 53},
+ dictWord{24, 0, 27},
+ dictWord{152, 0, 31},
+ dictWord{
+ 133,
+ 0,
+ 716,
+ },
+ dictWord{135, 0, 844},
+ dictWord{4, 0, 91},
+ dictWord{5, 0, 388},
+ dictWord{5, 0, 845},
+ dictWord{6, 0, 206},
+ dictWord{6, 0, 252},
+ dictWord{6, 0, 365},
+ dictWord{
+ 7,
+ 0,
+ 136,
+ },
+ dictWord{7, 0, 531},
+ dictWord{136, 0, 621},
+ dictWord{7, 10, 393},
+ dictWord{10, 10, 603},
+ dictWord{139, 10, 206},
+ dictWord{6, 11, 80},
+ dictWord{
+ 6,
+ 11,
+ 1694,
+ },
+ dictWord{7, 11, 173},
+ dictWord{7, 11, 1974},
+ dictWord{9, 11, 547},
+ dictWord{10, 11, 730},
+ dictWord{14, 11, 18},
+ dictWord{150, 11, 39},
+ dictWord{137, 0, 748},
+ dictWord{4, 11, 923},
+ dictWord{134, 11, 1711},
+ dictWord{4, 10, 912},
+ dictWord{137, 10, 232},
+ dictWord{7, 10, 98},
+ dictWord{7, 10, 1973},
+ dictWord{136, 10, 716},
+ dictWord{14, 0, 103},
+ dictWord{133, 10, 733},
+ dictWord{132, 11, 595},
+ dictWord{12, 0, 158},
+ dictWord{18, 0, 8},
+ dictWord{19, 0, 62},
+ dictWord{20, 0, 6},
+ dictWord{22, 0, 4},
+ dictWord{23, 0, 2},
+ dictWord{23, 0, 9},
+ dictWord{5, 11, 240},
+ dictWord{6, 11, 459},
+ dictWord{7, 11, 12},
+ dictWord{7, 11, 114},
+ dictWord{7, 11, 502},
+ dictWord{7, 11, 1751},
+ dictWord{7, 11, 1753},
+ dictWord{7, 11, 1805},
+ dictWord{8, 11, 658},
+ dictWord{9, 11, 1},
+ dictWord{11, 11, 959},
+ dictWord{13, 11, 446},
+ dictWord{142, 11, 211},
+ dictWord{135, 0, 576},
+ dictWord{5, 0, 771},
+ dictWord{5, 0, 863},
+ dictWord{5, 0, 898},
+ dictWord{6, 0, 648},
+ dictWord{
+ 6,
+ 0,
+ 1632,
+ },
+ dictWord{6, 0, 1644},
+ dictWord{134, 0, 1780},
+ dictWord{133, 0, 331},
+ dictWord{7, 11, 633},
+ dictWord{7, 11, 905},
+ dictWord{7, 11, 909},
+ dictWord{
+ 7,
+ 11,
+ 1538,
+ },
+ dictWord{9, 11, 767},
+ dictWord{140, 11, 636},
+ dictWord{140, 0, 632},
+ dictWord{5, 0, 107},
+ dictWord{7, 0, 201},
+ dictWord{136, 0, 518},
+ dictWord{
+ 6,
+ 0,
+ 446,
+ },
+ dictWord{7, 0, 1817},
+ dictWord{134, 11, 490},
+ dictWord{9, 0, 851},
+ dictWord{141, 0, 510},
+ dictWord{7, 11, 250},
+ dictWord{8, 11, 506},
+ dictWord{
+ 136,
+ 11,
+ 507,
+ },
+ dictWord{4, 0, 504},
+ dictWord{137, 10, 72},
+ dictWord{132, 11, 158},
+ dictWord{4, 11, 140},
+ dictWord{7, 11, 362},
+ dictWord{8, 11, 209},
+ dictWord{
+ 9,
+ 11,
+ 10,
+ },
+ dictWord{9, 11, 160},
+ dictWord{9, 11, 503},
+ dictWord{10, 11, 689},
+ dictWord{11, 11, 350},
+ dictWord{11, 11, 553},
+ dictWord{11, 11, 725},
+ dictWord{
+ 12,
+ 11,
+ 252,
+ },
+ dictWord{12, 11, 583},
+ dictWord{13, 11, 192},
+ dictWord{13, 11, 352},
+ dictWord{14, 11, 269},
+ dictWord{14, 11, 356},
+ dictWord{148, 11, 50},
+ dictWord{6, 11, 597},
+ dictWord{135, 11, 1318},
+ dictWord{135, 10, 1454},
+ dictWord{5, 0, 883},
+ dictWord{5, 0, 975},
+ dictWord{8, 0, 392},
+ dictWord{148, 0, 7},
+ dictWord{6, 11, 228},
+ dictWord{7, 11, 1341},
+ dictWord{9, 11, 408},
+ dictWord{138, 11, 343},
+ dictWord{11, 11, 348},
+ dictWord{11, 10, 600},
+ dictWord{12, 11, 99},
+ dictWord{13, 10, 245},
+ dictWord{18, 11, 1},
+ dictWord{18, 11, 11},
+ dictWord{147, 11, 4},
+ dictWord{134, 11, 296},
+ dictWord{5, 0, 922},
+ dictWord{134, 0, 1707},
+ dictWord{132, 11, 557},
+ dictWord{4, 11, 548},
+ dictWord{7, 10, 164},
+ dictWord{7, 10, 1571},
+ dictWord{9, 10, 107},
+ dictWord{140, 10, 225},
+ dictWord{
+ 7,
+ 11,
+ 197,
+ },
+ dictWord{8, 11, 142},
+ dictWord{8, 11, 325},
+ dictWord{9, 11, 150},
+ dictWord{9, 11, 596},
+ dictWord{10, 11, 350},
+ dictWord{10, 11, 353},
+ dictWord{
+ 11,
+ 11,
+ 74,
+ },
+ dictWord{11, 11, 315},
+ dictWord{14, 11, 423},
+ dictWord{143, 11, 141},
+ dictWord{5, 0, 993},
+ dictWord{7, 0, 515},
+ dictWord{137, 0, 91},
+ dictWord{4, 0, 131},
+ dictWord{8, 0, 200},
+ dictWord{5, 10, 484},
+ dictWord{5, 10, 510},
+ dictWord{6, 10, 434},
+ dictWord{7, 10, 1000},
+ dictWord{7, 10, 1098},
+ dictWord{136, 10, 2},
+ dictWord{152, 0, 10},
+ dictWord{4, 11, 62},
+ dictWord{5, 11, 83},
+ dictWord{6, 11, 399},
+ dictWord{6, 11, 579},
+ dictWord{7, 11, 692},
+ dictWord{7, 11, 846},
+ dictWord{
+ 7,
+ 11,
+ 1015,
+ },
+ dictWord{7, 11, 1799},
+ dictWord{8, 11, 403},
+ dictWord{9, 11, 394},
+ dictWord{10, 11, 133},
+ dictWord{12, 11, 4},
+ dictWord{12, 11, 297},
+ dictWord{
+ 12,
+ 11,
+ 452,
+ },
+ dictWord{16, 11, 81},
+ dictWord{18, 11, 19},
+ dictWord{18, 11, 25},
+ dictWord{21, 11, 14},
+ dictWord{22, 11, 12},
+ dictWord{151, 11, 18},
+ dictWord{
+ 140,
+ 11,
+ 459,
+ },
+ dictWord{132, 11, 177},
+ dictWord{7, 0, 1433},
+ dictWord{9, 0, 365},
+ dictWord{137, 11, 365},
+ dictWord{132, 10, 460},
+ dictWord{5, 0, 103},
+ dictWord{
+ 6,
+ 0,
+ 2004,
+ },
+ dictWord{7, 0, 921},
+ dictWord{8, 0, 580},
+ dictWord{8, 0, 593},
+ dictWord{8, 0, 630},
+ dictWord{10, 0, 28},
+ dictWord{5, 11, 411},
+ dictWord{
+ 135,
+ 11,
+ 653,
+ },
+ dictWord{4, 10, 932},
+ dictWord{133, 10, 891},
+ dictWord{4, 0, 911},
+ dictWord{5, 0, 867},
+ dictWord{5, 0, 1013},
+ dictWord{7, 0, 2034},
+ dictWord{8, 0, 798},
+ dictWord{136, 0, 813},
+ dictWord{7, 11, 439},
+ dictWord{10, 11, 727},
+ dictWord{11, 11, 260},
+ dictWord{139, 11, 684},
+ dictWord{136, 10, 625},
+ dictWord{
+ 5,
+ 11,
+ 208,
+ },
+ dictWord{7, 11, 753},
+ dictWord{135, 11, 1528},
+ dictWord{5, 0, 461},
+ dictWord{7, 0, 1925},
+ dictWord{12, 0, 39},
+ dictWord{13, 0, 265},
+ dictWord{
+ 13,
+ 0,
+ 439,
+ },
+ dictWord{134, 10, 76},
+ dictWord{6, 0, 853},
+ dictWord{8, 10, 92},
+ dictWord{137, 10, 221},
+ dictWord{5, 0, 135},
+ dictWord{6, 0, 519},
+ dictWord{7, 0, 1722},
+ dictWord{10, 0, 271},
+ dictWord{11, 0, 261},
+ dictWord{145, 0, 54},
+ dictWord{139, 11, 814},
+ dictWord{14, 0, 338},
+ dictWord{148, 0, 81},
+ dictWord{4, 0, 300},
+ dictWord{133, 0, 436},
+ dictWord{5, 0, 419},
+ dictWord{5, 0, 687},
+ dictWord{7, 0, 864},
+ dictWord{9, 0, 470},
+ dictWord{135, 11, 864},
+ dictWord{9, 0, 836},
+ dictWord{
+ 133,
+ 11,
+ 242,
+ },
+ dictWord{134, 0, 1937},
+ dictWord{4, 10, 763},
+ dictWord{133, 11, 953},
+ dictWord{132, 10, 622},
+ dictWord{132, 0, 393},
+ dictWord{
+ 133,
+ 10,
+ 253,
+ },
+ dictWord{8, 0, 357},
+ dictWord{10, 0, 745},
+ dictWord{14, 0, 426},
+ dictWord{17, 0, 94},
+ dictWord{19, 0, 57},
+ dictWord{135, 10, 546},
+ dictWord{5, 11, 615},
+ dictWord{146, 11, 37},
+ dictWord{9, 10, 73},
+ dictWord{10, 10, 110},
+ dictWord{14, 10, 185},
+ dictWord{145, 10, 119},
+ dictWord{11, 0, 703},
+ dictWord{7, 10, 624},
+ dictWord{7, 10, 916},
+ dictWord{10, 10, 256},
+ dictWord{139, 10, 87},
+ dictWord{133, 11, 290},
+ dictWord{5, 10, 212},
+ dictWord{12, 10, 35},
+ dictWord{
+ 141,
+ 10,
+ 382,
+ },
+ dictWord{132, 11, 380},
+ dictWord{5, 11, 52},
+ dictWord{7, 11, 277},
+ dictWord{9, 11, 368},
+ dictWord{139, 11, 791},
+ dictWord{133, 0, 387},
+ dictWord{
+ 10,
+ 11,
+ 138,
+ },
+ dictWord{139, 11, 476},
+ dictWord{4, 0, 6},
+ dictWord{5, 0, 708},
+ dictWord{136, 0, 75},
+ dictWord{7, 0, 1351},
+ dictWord{9, 0, 581},
+ dictWord{10, 0, 639},
+ dictWord{11, 0, 453},
+ dictWord{140, 0, 584},
+ dictWord{132, 0, 303},
+ dictWord{138, 0, 772},
+ dictWord{135, 10, 1175},
+ dictWord{4, 0, 749},
+ dictWord{
+ 5,
+ 10,
+ 816,
+ },
+ dictWord{6, 11, 256},
+ dictWord{7, 11, 307},
+ dictWord{7, 11, 999},
+ dictWord{7, 11, 1481},
+ dictWord{7, 11, 1732},
+ dictWord{7, 11, 1738},
+ dictWord{
+ 8,
+ 11,
+ 265,
+ },
+ dictWord{9, 11, 414},
+ dictWord{11, 11, 316},
+ dictWord{12, 11, 52},
+ dictWord{13, 11, 420},
+ dictWord{147, 11, 100},
+ dictWord{135, 11, 1296},
+ dictWord{
+ 6,
+ 0,
+ 1065,
+ },
+ dictWord{5, 10, 869},
+ dictWord{5, 10, 968},
+ dictWord{6, 10, 1626},
+ dictWord{8, 10, 734},
+ dictWord{136, 10, 784},
+ dictWord{4, 10, 542},
+ dictWord{
+ 6,
+ 10,
+ 1716,
+ },
+ dictWord{6, 10, 1727},
+ dictWord{7, 10, 1082},
+ dictWord{7, 10, 1545},
+ dictWord{8, 10, 56},
+ dictWord{8, 10, 118},
+ dictWord{8, 10, 412},
+ dictWord{
+ 8,
+ 10,
+ 564,
+ },
+ dictWord{9, 10, 888},
+ dictWord{9, 10, 908},
+ dictWord{10, 10, 50},
+ dictWord{10, 10, 423},
+ dictWord{11, 10, 685},
+ dictWord{11, 10, 697},
+ dictWord{11, 10, 933},
+ dictWord{12, 10, 299},
+ dictWord{13, 10, 126},
+ dictWord{13, 10, 136},
+ dictWord{13, 10, 170},
+ dictWord{141, 10, 190},
+ dictWord{
+ 134,
+ 0,
+ 226,
+ },
+ dictWord{4, 0, 106},
+ dictWord{7, 0, 310},
+ dictWord{11, 0, 717},
+ dictWord{133, 11, 723},
+ dictWord{5, 0, 890},
+ dictWord{5, 0, 988},
+ dictWord{4, 10, 232},
+ dictWord{9, 10, 202},
+ dictWord{10, 10, 474},
+ dictWord{140, 10, 433},
+ dictWord{6, 0, 626},
+ dictWord{142, 0, 431},
+ dictWord{10, 0, 706},
+ dictWord{150, 0, 44},
+ dictWord{13, 0, 51},
+ dictWord{6, 10, 108},
+ dictWord{7, 10, 1003},
+ dictWord{7, 10, 1181},
+ dictWord{8, 10, 111},
+ dictWord{136, 10, 343},
+ dictWord{132, 0, 698},
+ dictWord{5, 11, 109},
+ dictWord{6, 11, 1784},
+ dictWord{7, 11, 1895},
+ dictWord{12, 11, 296},
+ dictWord{140, 11, 302},
+ dictWord{134, 0, 828},
+ dictWord{
+ 134,
+ 10,
+ 1712,
+ },
+ dictWord{138, 0, 17},
+ dictWord{7, 0, 1929},
+ dictWord{4, 10, 133},
+ dictWord{5, 11, 216},
+ dictWord{7, 10, 711},
+ dictWord{7, 10, 1298},
+ dictWord{
+ 7,
+ 10,
+ 1585,
+ },
+ dictWord{7, 11, 1879},
+ dictWord{9, 11, 141},
+ dictWord{9, 11, 270},
+ dictWord{9, 11, 679},
+ dictWord{10, 11, 159},
+ dictWord{10, 11, 553},
+ dictWord{
+ 11,
+ 11,
+ 197,
+ },
+ dictWord{11, 11, 438},
+ dictWord{12, 11, 538},
+ dictWord{12, 11, 559},
+ dictWord{13, 11, 193},
+ dictWord{13, 11, 423},
+ dictWord{14, 11, 144},
+ dictWord{14, 11, 166},
+ dictWord{14, 11, 167},
+ dictWord{15, 11, 67},
+ dictWord{147, 11, 84},
+ dictWord{141, 11, 127},
+ dictWord{7, 11, 1872},
+ dictWord{
+ 137,
+ 11,
+ 81,
+ },
+ dictWord{6, 10, 99},
+ dictWord{7, 10, 1808},
+ dictWord{145, 10, 57},
+ dictWord{134, 11, 391},
+ dictWord{5, 0, 689},
+ dictWord{6, 0, 84},
+ dictWord{7, 0, 1250},
+ dictWord{6, 10, 574},
+ dictWord{7, 10, 428},
+ dictWord{10, 10, 669},
+ dictWord{11, 10, 485},
+ dictWord{11, 10, 840},
+ dictWord{12, 10, 300},
+ dictWord{
+ 142,
+ 10,
+ 250,
+ },
+ dictWord{7, 11, 322},
+ dictWord{136, 11, 249},
+ dictWord{7, 11, 432},
+ dictWord{135, 11, 1649},
+ dictWord{135, 10, 1871},
+ dictWord{137, 10, 252},
+ dictWord{6, 11, 155},
+ dictWord{140, 11, 234},
+ dictWord{7, 0, 871},
+ dictWord{19, 0, 27},
+ dictWord{147, 11, 27},
+ dictWord{140, 0, 498},
+ dictWord{5, 0, 986},
+ dictWord{6, 0, 130},
+ dictWord{138, 0, 823},
+ dictWord{6, 0, 1793},
+ dictWord{7, 0, 1582},
+ dictWord{8, 0, 458},
+ dictWord{10, 0, 101},
+ dictWord{10, 0, 318},
+ dictWord{
+ 10,
+ 0,
+ 945,
+ },
+ dictWord{12, 0, 734},
+ dictWord{16, 0, 104},
+ dictWord{18, 0, 177},
+ dictWord{6, 10, 323},
+ dictWord{135, 10, 1564},
+ dictWord{5, 11, 632},
+ dictWord{
+ 138,
+ 11,
+ 526,
+ },
+ dictWord{10, 0, 435},
+ dictWord{7, 10, 461},
+ dictWord{136, 10, 775},
+ dictWord{6, 11, 144},
+ dictWord{7, 11, 948},
+ dictWord{7, 11, 1042},
+ dictWord{
+ 7,
+ 11,
+ 1857,
+ },
+ dictWord{8, 11, 235},
+ dictWord{8, 11, 461},
+ dictWord{9, 11, 453},
+ dictWord{9, 11, 530},
+ dictWord{10, 11, 354},
+ dictWord{17, 11, 77},
+ dictWord{
+ 19,
+ 11,
+ 99,
+ },
+ dictWord{148, 11, 79},
+ dictWord{138, 0, 966},
+ dictWord{7, 0, 1644},
+ dictWord{137, 0, 129},
+ dictWord{135, 0, 997},
+ dictWord{136, 0, 502},
+ dictWord{
+ 5,
+ 11,
+ 196,
+ },
+ dictWord{6, 11, 486},
+ dictWord{7, 11, 212},
+ dictWord{8, 11, 309},
+ dictWord{136, 11, 346},
+ dictWord{7, 10, 727},
+ dictWord{146, 10, 73},
+ dictWord{132, 0, 823},
+ dictWord{132, 11, 686},
+ dictWord{135, 0, 1927},
+ dictWord{4, 0, 762},
+ dictWord{7, 0, 1756},
+ dictWord{137, 0, 98},
+ dictWord{136, 10, 577},
+ dictWord{24, 0, 8},
+ dictWord{4, 11, 30},
+ dictWord{5, 11, 43},
+ dictWord{152, 11, 8},
+ dictWord{7, 0, 1046},
+ dictWord{139, 0, 160},
+ dictWord{7, 0, 492},
+ dictWord{
+ 4,
+ 10,
+ 413,
+ },
+ dictWord{5, 10, 677},
+ dictWord{7, 11, 492},
+ dictWord{8, 10, 432},
+ dictWord{140, 10, 280},
+ dictWord{6, 0, 45},
+ dictWord{7, 0, 433},
+ dictWord{8, 0, 129},
+ dictWord{9, 0, 21},
+ dictWord{10, 0, 392},
+ dictWord{11, 0, 79},
+ dictWord{12, 0, 499},
+ dictWord{13, 0, 199},
+ dictWord{141, 0, 451},
+ dictWord{7, 0, 558},
+ dictWord{
+ 136,
+ 0,
+ 353,
+ },
+ dictWord{4, 11, 220},
+ dictWord{7, 11, 1535},
+ dictWord{9, 11, 93},
+ dictWord{139, 11, 474},
+ dictWord{7, 10, 646},
+ dictWord{7, 10, 1730},
+ dictWord{
+ 11,
+ 10,
+ 446,
+ },
+ dictWord{141, 10, 178},
+ dictWord{133, 0, 785},
+ dictWord{134, 0, 1145},
+ dictWord{8, 0, 81},
+ dictWord{9, 0, 189},
+ dictWord{9, 0, 201},
+ dictWord{
+ 11,
+ 0,
+ 478,
+ },
+ dictWord{11, 0, 712},
+ dictWord{141, 0, 338},
+ dictWord{5, 0, 353},
+ dictWord{151, 0, 26},
+ dictWord{11, 0, 762},
+ dictWord{132, 10, 395},
+ dictWord{
+ 134,
+ 0,
+ 2024,
+ },
+ dictWord{4, 0, 611},
+ dictWord{133, 0, 606},
+ dictWord{9, 10, 174},
+ dictWord{10, 10, 164},
+ dictWord{11, 10, 440},
+ dictWord{11, 10, 841},
+ dictWord{
+ 143,
+ 10,
+ 98,
+ },
+ dictWord{134, 10, 426},
+ dictWord{10, 10, 608},
+ dictWord{139, 10, 1002},
+ dictWord{138, 10, 250},
+ dictWord{6, 0, 25},
+ dictWord{7, 0, 855},
+ dictWord{7, 0, 1258},
+ dictWord{144, 0, 32},
+ dictWord{7, 11, 1725},
+ dictWord{138, 11, 393},
+ dictWord{5, 11, 263},
+ dictWord{134, 11, 414},
+ dictWord{6, 0, 2011},
+ dictWord{133, 10, 476},
+ dictWord{4, 0, 4},
+ dictWord{7, 0, 1118},
+ dictWord{7, 0, 1320},
+ dictWord{7, 0, 1706},
+ dictWord{8, 0, 277},
+ dictWord{9, 0, 622},
+ dictWord{
+ 10,
+ 0,
+ 9,
+ },
+ dictWord{11, 0, 724},
+ dictWord{12, 0, 350},
+ dictWord{12, 0, 397},
+ dictWord{13, 0, 28},
+ dictWord{13, 0, 159},
+ dictWord{15, 0, 89},
+ dictWord{18, 0, 5},
+ dictWord{
+ 19,
+ 0,
+ 9,
+ },
+ dictWord{20, 0, 34},
+ dictWord{22, 0, 47},
+ dictWord{6, 11, 178},
+ dictWord{6, 11, 1750},
+ dictWord{8, 11, 251},
+ dictWord{9, 11, 690},
+ dictWord{
+ 10,
+ 11,
+ 155,
+ },
+ dictWord{10, 11, 196},
+ dictWord{10, 11, 373},
+ dictWord{11, 11, 698},
+ dictWord{13, 11, 155},
+ dictWord{148, 11, 93},
+ dictWord{5, 11, 97},
+ dictWord{
+ 137,
+ 11,
+ 393,
+ },
+ dictWord{7, 0, 764},
+ dictWord{11, 0, 461},
+ dictWord{12, 0, 172},
+ dictWord{5, 10, 76},
+ dictWord{6, 10, 458},
+ dictWord{6, 10, 497},
+ dictWord{
+ 7,
+ 10,
+ 868,
+ },
+ dictWord{9, 10, 658},
+ dictWord{10, 10, 594},
+ dictWord{11, 10, 566},
+ dictWord{12, 10, 338},
+ dictWord{141, 10, 200},
+ dictWord{134, 0, 1449},
+ dictWord{138, 11, 40},
+ dictWord{134, 11, 1639},
+ dictWord{134, 0, 1445},
+ dictWord{6, 0, 1168},
+ dictWord{4, 10, 526},
+ dictWord{7, 10, 1029},
+ dictWord{
+ 135,
+ 10,
+ 1054,
+ },
+ dictWord{4, 11, 191},
+ dictWord{7, 11, 934},
+ dictWord{8, 11, 647},
+ dictWord{145, 11, 97},
+ dictWord{132, 10, 636},
+ dictWord{6, 0, 233},
+ dictWord{
+ 7,
+ 10,
+ 660,
+ },
+ dictWord{7, 10, 1124},
+ dictWord{17, 10, 31},
+ dictWord{19, 10, 22},
+ dictWord{151, 10, 14},
+ dictWord{6, 10, 1699},
+ dictWord{136, 11, 110},
+ dictWord{
+ 12,
+ 11,
+ 246,
+ },
+ dictWord{15, 11, 162},
+ dictWord{19, 11, 64},
+ dictWord{20, 11, 8},
+ dictWord{20, 11, 95},
+ dictWord{22, 11, 24},
+ dictWord{152, 11, 17},
+ dictWord{
+ 5,
+ 11,
+ 165,
+ },
+ dictWord{9, 11, 346},
+ dictWord{138, 11, 655},
+ dictWord{5, 11, 319},
+ dictWord{135, 11, 534},
+ dictWord{134, 0, 255},
+ dictWord{9, 0, 216},
+ dictWord{
+ 8,
+ 11,
+ 128,
+ },
+ dictWord{139, 11, 179},
+ dictWord{9, 0, 183},
+ dictWord{139, 0, 286},
+ dictWord{11, 0, 956},
+ dictWord{151, 0, 3},
+ dictWord{4, 0, 536},
+ dictWord{
+ 7,
+ 0,
+ 1141,
+ },
+ dictWord{10, 0, 723},
+ dictWord{139, 0, 371},
+ dictWord{4, 10, 279},
+ dictWord{7, 10, 301},
+ dictWord{137, 10, 362},
+ dictWord{7, 0, 285},
+ dictWord{
+ 5,
+ 11,
+ 57,
+ },
+ dictWord{6, 11, 101},
+ dictWord{6, 11, 1663},
+ dictWord{7, 11, 132},
+ dictWord{7, 11, 1048},
+ dictWord{7, 11, 1154},
+ dictWord{7, 11, 1415},
+ dictWord{
+ 7,
+ 11,
+ 1507,
+ },
+ dictWord{12, 11, 493},
+ dictWord{15, 11, 105},
+ dictWord{151, 11, 15},
+ dictWord{5, 11, 459},
+ dictWord{7, 11, 1073},
+ dictWord{7, 10, 1743},
+ dictWord{
+ 8,
+ 11,
+ 241,
+ },
+ dictWord{136, 11, 334},
+ dictWord{4, 10, 178},
+ dictWord{133, 10, 399},
+ dictWord{135, 0, 560},
+ dictWord{132, 0, 690},
+ dictWord{135, 0, 1246},
+ dictWord{18, 0, 157},
+ dictWord{147, 0, 63},
+ dictWord{10, 0, 599},
+ dictWord{11, 0, 33},
+ dictWord{12, 0, 571},
+ dictWord{149, 0, 1},
+ dictWord{6, 11, 324},
+ dictWord{
+ 6,
+ 11,
+ 520,
+ },
+ dictWord{7, 11, 338},
+ dictWord{7, 11, 1616},
+ dictWord{7, 11, 1729},
+ dictWord{8, 11, 228},
+ dictWord{9, 11, 69},
+ dictWord{139, 11, 750},
+ dictWord{
+ 7,
+ 0,
+ 1862,
+ },
+ dictWord{12, 0, 491},
+ dictWord{12, 0, 520},
+ dictWord{13, 0, 383},
+ dictWord{142, 0, 244},
+ dictWord{135, 11, 734},
+ dictWord{134, 10, 1692},
+ dictWord{10, 0, 448},
+ dictWord{11, 0, 630},
+ dictWord{17, 0, 117},
+ dictWord{6, 10, 202},
+ dictWord{7, 11, 705},
+ dictWord{12, 10, 360},
+ dictWord{17, 10, 118},
+ dictWord{18, 10, 27},
+ dictWord{148, 10, 67},
+ dictWord{4, 11, 73},
+ dictWord{6, 11, 612},
+ dictWord{7, 11, 927},
+ dictWord{7, 11, 1822},
+ dictWord{8, 11, 217},
+ dictWord{
+ 9,
+ 11,
+ 472,
+ },
+ dictWord{9, 11, 765},
+ dictWord{9, 11, 766},
+ dictWord{10, 11, 408},
+ dictWord{11, 11, 51},
+ dictWord{11, 11, 793},
+ dictWord{12, 11, 266},
+ dictWord{
+ 15,
+ 11,
+ 158,
+ },
+ dictWord{20, 11, 89},
+ dictWord{150, 11, 32},
+ dictWord{4, 0, 190},
+ dictWord{133, 0, 554},
+ dictWord{133, 0, 1001},
+ dictWord{5, 11, 389},
+ dictWord{
+ 8,
+ 11,
+ 636,
+ },
+ dictWord{137, 11, 229},
+ dictWord{5, 0, 446},
+ dictWord{7, 10, 872},
+ dictWord{10, 10, 516},
+ dictWord{139, 10, 167},
+ dictWord{137, 10, 313},
+ dictWord{132, 10, 224},
+ dictWord{134, 0, 1313},
+ dictWord{5, 10, 546},
+ dictWord{7, 10, 35},
+ dictWord{8, 10, 11},
+ dictWord{8, 10, 12},
+ dictWord{9, 10, 315},
+ dictWord{9, 10, 533},
+ dictWord{10, 10, 802},
+ dictWord{11, 10, 166},
+ dictWord{12, 10, 525},
+ dictWord{142, 10, 243},
+ dictWord{6, 0, 636},
+ dictWord{137, 0, 837},
+ dictWord{5, 10, 241},
+ dictWord{8, 10, 242},
+ dictWord{9, 10, 451},
+ dictWord{10, 10, 667},
+ dictWord{11, 10, 598},
+ dictWord{140, 10, 429},
+ dictWord{22, 10, 46},
+ dictWord{150, 11, 46},
+ dictWord{136, 11, 472},
+ dictWord{11, 0, 278},
+ dictWord{142, 0, 73},
+ dictWord{141, 11, 185},
+ dictWord{132, 0, 868},
+ dictWord{
+ 134,
+ 0,
+ 972,
+ },
+ dictWord{4, 10, 366},
+ dictWord{137, 10, 516},
+ dictWord{138, 0, 1010},
+ dictWord{5, 11, 189},
+ dictWord{6, 10, 1736},
+ dictWord{7, 11, 442},
+ dictWord{
+ 7,
+ 11,
+ 443,
+ },
+ dictWord{8, 11, 281},
+ dictWord{12, 11, 174},
+ dictWord{13, 11, 83},
+ dictWord{141, 11, 261},
+ dictWord{139, 11, 384},
+ dictWord{6, 11, 2},
+ dictWord{
+ 7,
+ 11,
+ 191,
+ },
+ dictWord{7, 11, 446},
+ dictWord{7, 11, 758},
+ dictWord{7, 11, 1262},
+ dictWord{7, 11, 1737},
+ dictWord{8, 11, 22},
+ dictWord{8, 11, 270},
+ dictWord{
+ 8,
+ 11,
+ 612,
+ },
+ dictWord{9, 11, 4},
+ dictWord{9, 11, 167},
+ dictWord{9, 11, 312},
+ dictWord{9, 11, 436},
+ dictWord{10, 11, 156},
+ dictWord{10, 11, 216},
+ dictWord{
+ 10,
+ 11,
+ 311,
+ },
+ dictWord{10, 11, 623},
+ dictWord{11, 11, 72},
+ dictWord{11, 11, 330},
+ dictWord{11, 11, 455},
+ dictWord{12, 11, 101},
+ dictWord{12, 11, 321},
+ dictWord{
+ 12,
+ 11,
+ 504,
+ },
+ dictWord{12, 11, 530},
+ dictWord{12, 11, 543},
+ dictWord{13, 11, 17},
+ dictWord{13, 11, 156},
+ dictWord{13, 11, 334},
+ dictWord{14, 11, 48},
+ dictWord{15, 11, 70},
+ dictWord{17, 11, 60},
+ dictWord{148, 11, 64},
+ dictWord{6, 10, 331},
+ dictWord{136, 10, 623},
+ dictWord{135, 0, 1231},
+ dictWord{132, 0, 304},
+ dictWord{6, 11, 60},
+ dictWord{7, 11, 670},
+ dictWord{7, 11, 1327},
+ dictWord{8, 11, 411},
+ dictWord{8, 11, 435},
+ dictWord{9, 11, 653},
+ dictWord{9, 11, 740},
+ dictWord{10, 11, 385},
+ dictWord{11, 11, 222},
+ dictWord{11, 11, 324},
+ dictWord{11, 11, 829},
+ dictWord{140, 11, 611},
+ dictWord{7, 0, 506},
+ dictWord{6, 11, 166},
+ dictWord{7, 11, 374},
+ dictWord{135, 11, 1174},
+ dictWord{14, 11, 43},
+ dictWord{146, 11, 21},
+ dictWord{135, 11, 1694},
+ dictWord{135, 10, 1888},
+ dictWord{
+ 5,
+ 11,
+ 206,
+ },
+ dictWord{134, 11, 398},
+ dictWord{135, 11, 50},
+ dictWord{150, 0, 26},
+ dictWord{6, 0, 53},
+ dictWord{6, 0, 199},
+ dictWord{7, 0, 1408},
+ dictWord{
+ 8,
+ 0,
+ 32,
+ },
+ dictWord{8, 0, 93},
+ dictWord{10, 0, 397},
+ dictWord{10, 0, 629},
+ dictWord{11, 0, 593},
+ dictWord{11, 0, 763},
+ dictWord{13, 0, 326},
+ dictWord{145, 0, 35},
+ dictWord{134, 0, 105},
+ dictWord{132, 10, 394},
+ dictWord{4, 0, 843},
+ dictWord{138, 0, 794},
+ dictWord{11, 0, 704},
+ dictWord{141, 0, 396},
+ dictWord{5, 0, 114},
+ dictWord{5, 0, 255},
+ dictWord{141, 0, 285},
+ dictWord{6, 0, 619},
+ dictWord{7, 0, 898},
+ dictWord{7, 0, 1092},
+ dictWord{8, 0, 485},
+ dictWord{18, 0, 28},
+ dictWord{
+ 19,
+ 0,
+ 116,
+ },
+ dictWord{135, 10, 1931},
+ dictWord{9, 0, 145},
+ dictWord{7, 10, 574},
+ dictWord{135, 10, 1719},
+ dictWord{7, 0, 2035},
+ dictWord{8, 0, 19},
+ dictWord{
+ 9,
+ 0,
+ 89,
+ },
+ dictWord{138, 0, 831},
+ dictWord{132, 10, 658},
+ dictWord{6, 11, 517},
+ dictWord{7, 11, 1159},
+ dictWord{10, 11, 621},
+ dictWord{139, 11, 192},
+ dictWord{
+ 7,
+ 0,
+ 1933,
+ },
+ dictWord{7, 11, 1933},
+ dictWord{9, 10, 781},
+ dictWord{10, 10, 144},
+ dictWord{11, 10, 385},
+ dictWord{13, 10, 161},
+ dictWord{13, 10, 228},
+ dictWord{13, 10, 268},
+ dictWord{148, 10, 107},
+ dictWord{136, 10, 374},
+ dictWord{10, 11, 223},
+ dictWord{139, 11, 645},
+ dictWord{135, 0, 1728},
+ dictWord{
+ 7,
+ 11,
+ 64,
+ },
+ dictWord{7, 11, 289},
+ dictWord{136, 11, 245},
+ dictWord{4, 10, 344},
+ dictWord{6, 10, 498},
+ dictWord{139, 10, 323},
+ dictWord{136, 0, 746},
+ dictWord{
+ 135,
+ 10,
+ 1063,
+ },
+ dictWord{137, 10, 155},
+ dictWord{4, 0, 987},
+ dictWord{6, 0, 1964},
+ dictWord{6, 0, 1974},
+ dictWord{6, 0, 1990},
+ dictWord{136, 0, 995},
+ dictWord{133, 11, 609},
+ dictWord{133, 10, 906},
+ dictWord{134, 0, 1550},
+ dictWord{134, 0, 874},
+ dictWord{5, 11, 129},
+ dictWord{6, 11, 61},
+ dictWord{
+ 135,
+ 11,
+ 947,
+ },
+ dictWord{4, 0, 1018},
+ dictWord{6, 0, 1938},
+ dictWord{6, 0, 2021},
+ dictWord{134, 0, 2039},
+ dictWord{132, 0, 814},
+ dictWord{11, 0, 126},
+ dictWord{
+ 139,
+ 0,
+ 287,
+ },
+ dictWord{134, 0, 1264},
+ dictWord{5, 0, 955},
+ dictWord{136, 0, 814},
+ dictWord{141, 11, 506},
+ dictWord{132, 11, 314},
+ dictWord{6, 0, 981},
+ dictWord{139, 11, 1000},
+ dictWord{5, 0, 56},
+ dictWord{8, 0, 892},
+ dictWord{8, 0, 915},
+ dictWord{140, 0, 776},
+ dictWord{148, 0, 100},
+ dictWord{10, 0, 4},
+ dictWord{
+ 10,
+ 0,
+ 13,
+ },
+ dictWord{11, 0, 638},
+ dictWord{148, 0, 57},
+ dictWord{148, 11, 74},
+ dictWord{5, 0, 738},
+ dictWord{132, 10, 616},
+ dictWord{133, 11, 637},
+ dictWord{
+ 136,
+ 10,
+ 692,
+ },
+ dictWord{133, 0, 758},
+ dictWord{132, 10, 305},
+ dictWord{137, 11, 590},
+ dictWord{5, 11, 280},
+ dictWord{135, 11, 1226},
+ dictWord{
+ 134,
+ 11,
+ 494,
+ },
+ dictWord{135, 0, 1112},
+ dictWord{133, 11, 281},
+ dictWord{13, 0, 44},
+ dictWord{14, 0, 214},
+ dictWord{5, 10, 214},
+ dictWord{7, 10, 603},
+ dictWord{
+ 8,
+ 10,
+ 611,
+ },
+ dictWord{9, 10, 686},
+ dictWord{10, 10, 88},
+ dictWord{11, 10, 459},
+ dictWord{11, 10, 496},
+ dictWord{12, 10, 463},
+ dictWord{140, 10, 590},
+ dictWord{
+ 139,
+ 0,
+ 328,
+ },
+ dictWord{135, 11, 1064},
+ dictWord{137, 0, 133},
+ dictWord{7, 0, 168},
+ dictWord{13, 0, 196},
+ dictWord{141, 0, 237},
+ dictWord{134, 10, 1703},
+ dictWord{134, 0, 1152},
+ dictWord{135, 0, 1245},
+ dictWord{5, 0, 110},
+ dictWord{6, 0, 169},
+ dictWord{6, 0, 1702},
+ dictWord{7, 0, 400},
+ dictWord{8, 0, 538},
+ dictWord{
+ 9,
+ 0,
+ 184,
+ },
+ dictWord{9, 0, 524},
+ dictWord{140, 0, 218},
+ dictWord{6, 0, 1816},
+ dictWord{10, 0, 871},
+ dictWord{12, 0, 769},
+ dictWord{140, 0, 785},
+ dictWord{
+ 132,
+ 11,
+ 630,
+ },
+ dictWord{7, 11, 33},
+ dictWord{7, 11, 120},
+ dictWord{8, 11, 489},
+ dictWord{9, 11, 319},
+ dictWord{10, 11, 820},
+ dictWord{11, 11, 1004},
+ dictWord{
+ 12,
+ 11,
+ 379,
+ },
+ dictWord{13, 11, 117},
+ dictWord{13, 11, 412},
+ dictWord{14, 11, 25},
+ dictWord{15, 11, 52},
+ dictWord{15, 11, 161},
+ dictWord{16, 11, 47},
+ dictWord{149, 11, 2},
+ dictWord{6, 0, 133},
+ dictWord{8, 0, 413},
+ dictWord{9, 0, 353},
+ dictWord{139, 0, 993},
+ dictWord{145, 10, 19},
+ dictWord{4, 11, 937},
+ dictWord{
+ 133,
+ 11,
+ 801,
+ },
+ dictWord{134, 0, 978},
+ dictWord{6, 0, 93},
+ dictWord{6, 0, 1508},
+ dictWord{7, 0, 1422},
+ dictWord{7, 0, 1851},
+ dictWord{8, 0, 673},
+ dictWord{9, 0, 529},
+ dictWord{140, 0, 43},
+ dictWord{6, 0, 317},
+ dictWord{10, 0, 512},
+ dictWord{4, 10, 737},
+ dictWord{11, 10, 294},
+ dictWord{12, 10, 60},
+ dictWord{12, 10, 437},
+ dictWord{13, 10, 64},
+ dictWord{13, 10, 380},
+ dictWord{142, 10, 430},
+ dictWord{9, 0, 371},
+ dictWord{7, 11, 1591},
+ dictWord{144, 11, 43},
+ dictWord{6, 10, 1758},
+ dictWord{8, 10, 520},
+ dictWord{9, 10, 345},
+ dictWord{9, 10, 403},
+ dictWord{142, 10, 350},
+ dictWord{5, 0, 526},
+ dictWord{10, 10, 242},
+ dictWord{
+ 138,
+ 10,
+ 579,
+ },
+ dictWord{9, 0, 25},
+ dictWord{10, 0, 467},
+ dictWord{138, 0, 559},
+ dictWord{5, 10, 139},
+ dictWord{7, 10, 1168},
+ dictWord{138, 10, 539},
+ dictWord{
+ 4,
+ 0,
+ 335,
+ },
+ dictWord{135, 0, 942},
+ dictWord{140, 0, 754},
+ dictWord{132, 11, 365},
+ dictWord{11, 0, 182},
+ dictWord{142, 0, 195},
+ dictWord{142, 11, 29},
+ dictWord{
+ 5,
+ 11,
+ 7,
+ },
+ dictWord{139, 11, 774},
+ dictWord{4, 11, 746},
+ dictWord{135, 11, 1090},
+ dictWord{8, 0, 39},
+ dictWord{10, 0, 773},
+ dictWord{11, 0, 84},
+ dictWord{
+ 12,
+ 0,
+ 205,
+ },
+ dictWord{142, 0, 1},
+ dictWord{5, 0, 601},
+ dictWord{5, 0, 870},
+ dictWord{5, 11, 360},
+ dictWord{136, 11, 237},
+ dictWord{132, 0, 181},
+ dictWord{
+ 136,
+ 0,
+ 370,
+ },
+ dictWord{134, 0, 1652},
+ dictWord{8, 0, 358},
+ dictWord{4, 10, 107},
+ dictWord{7, 10, 613},
+ dictWord{8, 10, 439},
+ dictWord{8, 10, 504},
+ dictWord{
+ 9,
+ 10,
+ 501,
+ },
+ dictWord{10, 10, 383},
+ dictWord{139, 10, 477},
+ dictWord{132, 10, 229},
+ dictWord{137, 11, 785},
+ dictWord{4, 0, 97},
+ dictWord{5, 0, 147},
+ dictWord{
+ 6,
+ 0,
+ 286,
+ },
+ dictWord{7, 0, 1362},
+ dictWord{141, 0, 176},
+ dictWord{6, 0, 537},
+ dictWord{7, 0, 788},
+ dictWord{7, 0, 1816},
+ dictWord{132, 10, 903},
+ dictWord{
+ 140,
+ 10,
+ 71,
+ },
+ dictWord{6, 0, 743},
+ dictWord{134, 0, 1223},
+ dictWord{6, 0, 375},
+ dictWord{7, 0, 169},
+ dictWord{7, 0, 254},
+ dictWord{8, 0, 780},
+ dictWord{135, 11, 1493},
+ dictWord{7, 0, 1714},
+ dictWord{4, 10, 47},
+ dictWord{6, 10, 373},
+ dictWord{7, 10, 452},
+ dictWord{7, 10, 543},
+ dictWord{7, 10, 1856},
+ dictWord{9, 10, 6},
+ dictWord{
+ 11,
+ 10,
+ 257,
+ },
+ dictWord{139, 10, 391},
+ dictWord{6, 0, 896},
+ dictWord{136, 0, 1003},
+ dictWord{135, 0, 1447},
+ dictWord{137, 11, 341},
+ dictWord{5, 10, 980},
+ dictWord{134, 10, 1754},
+ dictWord{145, 11, 22},
+ dictWord{4, 11, 277},
+ dictWord{5, 11, 608},
+ dictWord{6, 11, 493},
+ dictWord{7, 11, 457},
+ dictWord{
+ 140,
+ 11,
+ 384,
+ },
+ dictWord{7, 10, 536},
+ dictWord{7, 10, 1331},
+ dictWord{136, 10, 143},
+ dictWord{140, 0, 744},
+ dictWord{7, 11, 27},
+ dictWord{135, 11, 316},
+ dictWord{
+ 18,
+ 0,
+ 126,
+ },
+ dictWord{5, 10, 19},
+ dictWord{134, 10, 533},
+ dictWord{4, 0, 788},
+ dictWord{11, 0, 41},
+ dictWord{5, 11, 552},
+ dictWord{5, 11, 586},
+ dictWord{
+ 5,
+ 11,
+ 676,
+ },
+ dictWord{6, 11, 448},
+ dictWord{8, 11, 244},
+ dictWord{11, 11, 1},
+ dictWord{11, 11, 41},
+ dictWord{13, 11, 3},
+ dictWord{16, 11, 54},
+ dictWord{17, 11, 4},
+ dictWord{146, 11, 13},
+ dictWord{4, 0, 985},
+ dictWord{6, 0, 1801},
+ dictWord{4, 11, 401},
+ dictWord{137, 11, 264},
+ dictWord{5, 10, 395},
+ dictWord{5, 10, 951},
+ dictWord{134, 10, 1776},
+ dictWord{5, 0, 629},
+ dictWord{135, 0, 1549},
+ dictWord{11, 10, 663},
+ dictWord{12, 10, 210},
+ dictWord{13, 10, 166},
+ dictWord{
+ 13,
+ 10,
+ 310,
+ },
+ dictWord{14, 10, 373},
+ dictWord{147, 10, 43},
+ dictWord{9, 11, 543},
+ dictWord{10, 11, 524},
+ dictWord{11, 11, 30},
+ dictWord{12, 11, 524},
+ dictWord{
+ 14,
+ 11,
+ 315,
+ },
+ dictWord{16, 11, 18},
+ dictWord{20, 11, 26},
+ dictWord{148, 11, 65},
+ dictWord{4, 11, 205},
+ dictWord{5, 11, 623},
+ dictWord{7, 11, 104},
+ dictWord{
+ 136,
+ 11,
+ 519,
+ },
+ dictWord{5, 0, 293},
+ dictWord{134, 0, 601},
+ dictWord{7, 11, 579},
+ dictWord{9, 11, 41},
+ dictWord{9, 11, 244},
+ dictWord{9, 11, 669},
+ dictWord{
+ 10,
+ 11,
+ 5,
+ },
+ dictWord{11, 11, 861},
+ dictWord{11, 11, 951},
+ dictWord{139, 11, 980},
+ dictWord{132, 11, 717},
+ dictWord{132, 10, 695},
+ dictWord{7, 10, 497},
+ dictWord{
+ 9,
+ 10,
+ 387,
+ },
+ dictWord{147, 10, 81},
+ dictWord{132, 0, 420},
+ dictWord{142, 0, 37},
+ dictWord{6, 0, 1134},
+ dictWord{6, 0, 1900},
+ dictWord{12, 0, 830},
+ dictWord{
+ 12,
+ 0,
+ 878,
+ },
+ dictWord{12, 0, 894},
+ dictWord{15, 0, 221},
+ dictWord{143, 0, 245},
+ dictWord{132, 11, 489},
+ dictWord{7, 0, 1570},
+ dictWord{140, 0, 542},
+ dictWord{
+ 8,
+ 0,
+ 933,
+ },
+ dictWord{136, 0, 957},
+ dictWord{6, 0, 1371},
+ dictWord{7, 0, 31},
+ dictWord{8, 0, 373},
+ dictWord{5, 10, 284},
+ dictWord{6, 10, 49},
+ dictWord{6, 10, 350},
+ dictWord{7, 10, 377},
+ dictWord{7, 10, 1693},
+ dictWord{8, 10, 678},
+ dictWord{9, 10, 161},
+ dictWord{9, 10, 585},
+ dictWord{9, 10, 671},
+ dictWord{9, 10, 839},
+ dictWord{11, 10, 912},
+ dictWord{141, 10, 427},
+ dictWord{135, 11, 892},
+ dictWord{4, 0, 325},
+ dictWord{138, 0, 125},
+ dictWord{139, 11, 47},
+ dictWord{
+ 132,
+ 10,
+ 597,
+ },
+ dictWord{138, 0, 323},
+ dictWord{6, 0, 1547},
+ dictWord{7, 11, 1605},
+ dictWord{9, 11, 473},
+ dictWord{11, 11, 962},
+ dictWord{146, 11, 139},
+ dictWord{
+ 139,
+ 10,
+ 908,
+ },
+ dictWord{7, 11, 819},
+ dictWord{9, 11, 26},
+ dictWord{9, 11, 392},
+ dictWord{10, 11, 152},
+ dictWord{10, 11, 226},
+ dictWord{11, 11, 19},
+ dictWord{
+ 12,
+ 11,
+ 276,
+ },
+ dictWord{12, 11, 426},
+ dictWord{12, 11, 589},
+ dictWord{13, 11, 460},
+ dictWord{15, 11, 97},
+ dictWord{19, 11, 48},
+ dictWord{148, 11, 104},
+ dictWord{135, 11, 51},
+ dictWord{4, 0, 718},
+ dictWord{135, 0, 1216},
+ dictWord{6, 0, 1896},
+ dictWord{6, 0, 1905},
+ dictWord{6, 0, 1912},
+ dictWord{9, 0, 947},
+ dictWord{
+ 9,
+ 0,
+ 974,
+ },
+ dictWord{12, 0, 809},
+ dictWord{12, 0, 850},
+ dictWord{12, 0, 858},
+ dictWord{12, 0, 874},
+ dictWord{12, 0, 887},
+ dictWord{12, 0, 904},
+ dictWord{
+ 12,
+ 0,
+ 929,
+ },
+ dictWord{12, 0, 948},
+ dictWord{12, 0, 952},
+ dictWord{15, 0, 198},
+ dictWord{15, 0, 206},
+ dictWord{15, 0, 220},
+ dictWord{15, 0, 227},
+ dictWord{15, 0, 247},
+ dictWord{18, 0, 188},
+ dictWord{21, 0, 48},
+ dictWord{21, 0, 50},
+ dictWord{24, 0, 25},
+ dictWord{24, 0, 29},
+ dictWord{7, 11, 761},
+ dictWord{7, 11, 1051},
+ dictWord{
+ 137,
+ 11,
+ 545,
+ },
+ dictWord{5, 0, 124},
+ dictWord{5, 0, 144},
+ dictWord{6, 0, 548},
+ dictWord{7, 0, 15},
+ dictWord{7, 0, 153},
+ dictWord{137, 0, 629},
+ dictWord{
+ 135,
+ 11,
+ 606,
+ },
+ dictWord{135, 10, 2014},
+ dictWord{7, 10, 2007},
+ dictWord{9, 11, 46},
+ dictWord{9, 10, 101},
+ dictWord{9, 10, 450},
+ dictWord{10, 10, 66},
+ dictWord{
+ 10,
+ 10,
+ 842,
+ },
+ dictWord{11, 10, 536},
+ dictWord{140, 10, 587},
+ dictWord{6, 0, 75},
+ dictWord{7, 0, 1531},
+ dictWord{8, 0, 416},
+ dictWord{9, 0, 240},
+ dictWord{9, 0, 275},
+ dictWord{10, 0, 100},
+ dictWord{11, 0, 658},
+ dictWord{11, 0, 979},
+ dictWord{12, 0, 86},
+ dictWord{14, 0, 207},
+ dictWord{15, 0, 20},
+ dictWord{143, 0, 25},
+ dictWord{
+ 5,
+ 0,
+ 141,
+ },
+ dictWord{5, 0, 915},
+ dictWord{6, 0, 1783},
+ dictWord{7, 0, 211},
+ dictWord{7, 0, 698},
+ dictWord{7, 0, 1353},
+ dictWord{9, 0, 83},
+ dictWord{9, 0, 281},
+ dictWord{
+ 10,
+ 0,
+ 376,
+ },
+ dictWord{10, 0, 431},
+ dictWord{11, 0, 543},
+ dictWord{12, 0, 664},
+ dictWord{13, 0, 280},
+ dictWord{13, 0, 428},
+ dictWord{14, 0, 61},
+ dictWord{
+ 14,
+ 0,
+ 128,
+ },
+ dictWord{17, 0, 52},
+ dictWord{145, 0, 81},
+ dictWord{132, 11, 674},
+ dictWord{135, 0, 533},
+ dictWord{149, 0, 6},
+ dictWord{132, 11, 770},
+ dictWord{
+ 133,
+ 0,
+ 538,
+ },
+ dictWord{5, 11, 79},
+ dictWord{7, 11, 1027},
+ dictWord{7, 11, 1477},
+ dictWord{139, 11, 52},
+ dictWord{139, 10, 62},
+ dictWord{4, 0, 338},
+ dictWord{
+ 133,
+ 0,
+ 400,
+ },
+ dictWord{5, 11, 789},
+ dictWord{134, 11, 195},
+ dictWord{4, 11, 251},
+ dictWord{4, 11, 688},
+ dictWord{7, 11, 513},
+ dictWord{7, 11, 1284},
+ dictWord{
+ 9,
+ 11,
+ 87,
+ },
+ dictWord{138, 11, 365},
+ dictWord{134, 10, 1766},
+ dictWord{6, 0, 0},
+ dictWord{7, 0, 84},
+ dictWord{11, 0, 895},
+ dictWord{145, 0, 11},
+ dictWord{
+ 139,
+ 0,
+ 892,
+ },
+ dictWord{4, 0, 221},
+ dictWord{5, 0, 659},
+ dictWord{7, 0, 697},
+ dictWord{7, 0, 1211},
+ dictWord{138, 0, 284},
+ dictWord{133, 0, 989},
+ dictWord{
+ 133,
+ 11,
+ 889,
+ },
+ dictWord{4, 11, 160},
+ dictWord{5, 11, 330},
+ dictWord{7, 11, 1434},
+ dictWord{136, 11, 174},
+ dictWord{6, 10, 1665},
+ dictWord{7, 10, 256},
+ dictWord{
+ 7,
+ 10,
+ 1388,
+ },
+ dictWord{10, 10, 499},
+ dictWord{139, 10, 670},
+ dictWord{7, 0, 848},
+ dictWord{4, 10, 22},
+ dictWord{5, 10, 10},
+ dictWord{136, 10, 97},
+ dictWord{
+ 138,
+ 0,
+ 507,
+ },
+ dictWord{133, 10, 481},
+ dictWord{4, 0, 188},
+ dictWord{135, 0, 805},
+ dictWord{5, 0, 884},
+ dictWord{6, 0, 732},
+ dictWord{139, 0, 991},
+ dictWord{
+ 135,
+ 11,
+ 968,
+ },
+ dictWord{11, 11, 636},
+ dictWord{15, 11, 145},
+ dictWord{17, 11, 34},
+ dictWord{19, 11, 50},
+ dictWord{151, 11, 20},
+ dictWord{7, 0, 959},
+ dictWord{
+ 16,
+ 0,
+ 60,
+ },
+ dictWord{6, 10, 134},
+ dictWord{7, 10, 437},
+ dictWord{9, 10, 37},
+ dictWord{14, 10, 285},
+ dictWord{142, 10, 371},
+ dictWord{7, 10, 486},
+ dictWord{
+ 8,
+ 10,
+ 155,
+ },
+ dictWord{11, 10, 93},
+ dictWord{140, 10, 164},
+ dictWord{134, 0, 1653},
+ dictWord{7, 0, 337},
+ dictWord{133, 10, 591},
+ dictWord{6, 0, 1989},
+ dictWord{
+ 8,
+ 0,
+ 922,
+ },
+ dictWord{8, 0, 978},
+ dictWord{133, 11, 374},
+ dictWord{132, 0, 638},
+ dictWord{138, 0, 500},
+ dictWord{133, 11, 731},
+ dictWord{5, 10, 380},
+ dictWord{
+ 5,
+ 10,
+ 650,
+ },
+ dictWord{136, 10, 310},
+ dictWord{138, 11, 381},
+ dictWord{4, 10, 364},
+ dictWord{7, 10, 1156},
+ dictWord{7, 10, 1187},
+ dictWord{137, 10, 409},
+ dictWord{137, 11, 224},
+ dictWord{140, 0, 166},
+ dictWord{134, 10, 482},
+ dictWord{4, 11, 626},
+ dictWord{5, 11, 642},
+ dictWord{6, 11, 425},
+ dictWord{
+ 10,
+ 11,
+ 202,
+ },
+ dictWord{139, 11, 141},
+ dictWord{4, 10, 781},
+ dictWord{6, 10, 487},
+ dictWord{7, 10, 926},
+ dictWord{8, 10, 263},
+ dictWord{139, 10, 500},
+ dictWord{
+ 135,
+ 0,
+ 418,
+ },
+ dictWord{4, 10, 94},
+ dictWord{135, 10, 1265},
+ dictWord{136, 0, 760},
+ dictWord{132, 10, 417},
+ dictWord{136, 11, 835},
+ dictWord{5, 10, 348},
+ dictWord{134, 10, 522},
+ dictWord{6, 0, 1277},
+ dictWord{134, 0, 1538},
+ dictWord{139, 11, 541},
+ dictWord{135, 11, 1597},
+ dictWord{5, 11, 384},
+ dictWord{
+ 8,
+ 11,
+ 455,
+ },
+ dictWord{140, 11, 48},
+ dictWord{136, 0, 770},
+ dictWord{5, 11, 264},
+ dictWord{134, 11, 184},
+ dictWord{4, 0, 89},
+ dictWord{5, 0, 489},
+ dictWord{
+ 6,
+ 0,
+ 315,
+ },
+ dictWord{7, 0, 553},
+ dictWord{7, 0, 1745},
+ dictWord{138, 0, 243},
+ dictWord{4, 10, 408},
+ dictWord{4, 10, 741},
+ dictWord{135, 10, 500},
+ dictWord{
+ 134,
+ 0,
+ 1396,
+ },
+ dictWord{133, 0, 560},
+ dictWord{6, 0, 1658},
+ dictWord{9, 0, 3},
+ dictWord{10, 0, 154},
+ dictWord{11, 0, 641},
+ dictWord{13, 0, 85},
+ dictWord{13, 0, 201},
+ dictWord{141, 0, 346},
+ dictWord{135, 11, 1595},
+ dictWord{5, 11, 633},
+ dictWord{6, 11, 28},
+ dictWord{7, 11, 219},
+ dictWord{135, 11, 1323},
+ dictWord{
+ 9,
+ 11,
+ 769,
+ },
+ dictWord{140, 11, 185},
+ dictWord{135, 11, 785},
+ dictWord{7, 11, 359},
+ dictWord{8, 11, 243},
+ dictWord{140, 11, 175},
+ dictWord{138, 0, 586},
+ dictWord{
+ 7,
+ 0,
+ 1271,
+ },
+ dictWord{134, 10, 73},
+ dictWord{132, 11, 105},
+ dictWord{4, 0, 166},
+ dictWord{5, 0, 505},
+ dictWord{134, 0, 1670},
+ dictWord{133, 10, 576},
+ dictWord{4, 11, 324},
+ dictWord{138, 11, 104},
+ dictWord{142, 10, 231},
+ dictWord{6, 0, 637},
+ dictWord{7, 10, 1264},
+ dictWord{7, 10, 1678},
+ dictWord{
+ 11,
+ 10,
+ 945,
+ },
+ dictWord{12, 10, 341},
+ dictWord{12, 10, 471},
+ dictWord{12, 10, 569},
+ dictWord{23, 11, 21},
+ dictWord{151, 11, 23},
+ dictWord{8, 11, 559},
+ dictWord{
+ 141,
+ 11,
+ 109,
+ },
+ dictWord{134, 0, 1947},
+ dictWord{7, 0, 445},
+ dictWord{8, 0, 307},
+ dictWord{8, 0, 704},
+ dictWord{10, 0, 41},
+ dictWord{10, 0, 439},
+ dictWord{
+ 11,
+ 0,
+ 237,
+ },
+ dictWord{11, 0, 622},
+ dictWord{140, 0, 201},
+ dictWord{135, 11, 963},
+ dictWord{135, 0, 1977},
+ dictWord{4, 0, 189},
+ dictWord{5, 0, 713},
+ dictWord{
+ 136,
+ 0,
+ 57,
+ },
+ dictWord{138, 0, 371},
+ dictWord{135, 10, 538},
+ dictWord{132, 0, 552},
+ dictWord{6, 0, 883},
+ dictWord{133, 10, 413},
+ dictWord{6, 0, 923},
+ dictWord{
+ 132,
+ 11,
+ 758,
+ },
+ dictWord{138, 11, 215},
+ dictWord{136, 10, 495},
+ dictWord{7, 10, 54},
+ dictWord{8, 10, 312},
+ dictWord{10, 10, 191},
+ dictWord{10, 10, 614},
+ dictWord{140, 10, 567},
+ dictWord{7, 11, 351},
+ dictWord{139, 11, 128},
+ dictWord{7, 0, 875},
+ dictWord{6, 10, 468},
+ dictWord{7, 10, 1478},
+ dictWord{8, 10, 530},
+ dictWord{142, 10, 290},
+ dictWord{135, 0, 1788},
+ dictWord{17, 0, 49},
+ dictWord{133, 11, 918},
+ dictWord{12, 11, 398},
+ dictWord{20, 11, 39},
+ dictWord{
+ 21,
+ 11,
+ 11,
+ },
+ dictWord{150, 11, 41},
+ dictWord{10, 0, 661},
+ dictWord{6, 10, 484},
+ dictWord{135, 10, 822},
+ dictWord{135, 0, 1945},
+ dictWord{134, 0, 794},
+ dictWord{
+ 137,
+ 10,
+ 900,
+ },
+ dictWord{135, 10, 1335},
+ dictWord{6, 10, 1724},
+ dictWord{135, 10, 2022},
+ dictWord{132, 11, 340},
+ dictWord{134, 0, 1135},
+ dictWord{
+ 4,
+ 0,
+ 784,
+ },
+ dictWord{133, 0, 745},
+ dictWord{5, 0, 84},
+ dictWord{134, 0, 163},
+ dictWord{133, 0, 410},
+ dictWord{4, 0, 976},
+ dictWord{5, 11, 985},
+ dictWord{7, 11, 509},
+ dictWord{7, 11, 529},
+ dictWord{145, 11, 96},
+ dictWord{132, 10, 474},
+ dictWord{134, 0, 703},
+ dictWord{135, 11, 1919},
+ dictWord{5, 0, 322},
+ dictWord{
+ 8,
+ 0,
+ 186,
+ },
+ dictWord{9, 0, 262},
+ dictWord{10, 0, 187},
+ dictWord{142, 0, 208},
+ dictWord{135, 10, 1504},
+ dictWord{133, 0, 227},
+ dictWord{9, 0, 560},
+ dictWord{
+ 13,
+ 0,
+ 208,
+ },
+ dictWord{133, 10, 305},
+ dictWord{132, 11, 247},
+ dictWord{7, 0, 1395},
+ dictWord{8, 0, 486},
+ dictWord{9, 0, 236},
+ dictWord{9, 0, 878},
+ dictWord{
+ 10,
+ 0,
+ 218,
+ },
+ dictWord{11, 0, 95},
+ dictWord{19, 0, 17},
+ dictWord{147, 0, 31},
+ dictWord{7, 0, 2043},
+ dictWord{8, 0, 672},
+ dictWord{141, 0, 448},
+ dictWord{4, 11, 184},
+ dictWord{5, 11, 390},
+ dictWord{6, 11, 337},
+ dictWord{7, 11, 23},
+ dictWord{7, 11, 494},
+ dictWord{7, 11, 618},
+ dictWord{7, 11, 1456},
+ dictWord{8, 11, 27},
+ dictWord{
+ 8,
+ 11,
+ 599,
+ },
+ dictWord{10, 11, 153},
+ dictWord{139, 11, 710},
+ dictWord{135, 0, 466},
+ dictWord{135, 10, 1236},
+ dictWord{6, 0, 167},
+ dictWord{7, 0, 186},
+ dictWord{7, 0, 656},
+ dictWord{10, 0, 643},
+ dictWord{4, 10, 480},
+ dictWord{6, 10, 302},
+ dictWord{6, 10, 1642},
+ dictWord{7, 10, 837},
+ dictWord{7, 10, 1547},
+ dictWord{
+ 7,
+ 10,
+ 1657,
+ },
+ dictWord{8, 10, 429},
+ dictWord{9, 10, 228},
+ dictWord{13, 10, 289},
+ dictWord{13, 10, 343},
+ dictWord{147, 10, 101},
+ dictWord{134, 0, 1428},
+ dictWord{134, 0, 1440},
+ dictWord{5, 0, 412},
+ dictWord{7, 10, 278},
+ dictWord{10, 10, 739},
+ dictWord{11, 10, 708},
+ dictWord{141, 10, 348},
+ dictWord{
+ 134,
+ 0,
+ 1118,
+ },
+ dictWord{136, 0, 562},
+ dictWord{148, 11, 46},
+ dictWord{9, 0, 316},
+ dictWord{139, 0, 256},
+ dictWord{134, 0, 1771},
+ dictWord{135, 0, 1190},
+ dictWord{137, 0, 132},
+ dictWord{10, 11, 227},
+ dictWord{11, 11, 497},
+ dictWord{11, 11, 709},
+ dictWord{140, 11, 415},
+ dictWord{143, 0, 66},
+ dictWord{6, 11, 360},
+ dictWord{7, 11, 1664},
+ dictWord{136, 11, 478},
+ dictWord{144, 10, 28},
+ dictWord{4, 0, 317},
+ dictWord{135, 0, 1279},
+ dictWord{5, 0, 63},
+ dictWord{
+ 133,
+ 0,
+ 509,
+ },
+ dictWord{136, 11, 699},
+ dictWord{145, 10, 36},
+ dictWord{134, 0, 1475},
+ dictWord{11, 11, 343},
+ dictWord{142, 11, 127},
+ dictWord{132, 11, 739},
+ dictWord{132, 0, 288},
+ dictWord{135, 11, 1757},
+ dictWord{8, 0, 89},
+ dictWord{8, 0, 620},
+ dictWord{9, 0, 608},
+ dictWord{11, 0, 628},
+ dictWord{12, 0, 322},
+ dictWord{143, 0, 124},
+ dictWord{134, 0, 1225},
+ dictWord{7, 0, 1189},
+ dictWord{4, 11, 67},
+ dictWord{5, 11, 422},
+ dictWord{6, 10, 363},
+ dictWord{7, 11, 1037},
+ dictWord{7, 11, 1289},
+ dictWord{7, 11, 1555},
+ dictWord{7, 10, 1955},
+ dictWord{8, 10, 725},
+ dictWord{9, 11, 741},
+ dictWord{145, 11, 108},
+ dictWord{
+ 134,
+ 0,
+ 1468,
+ },
+ dictWord{6, 0, 689},
+ dictWord{134, 0, 1451},
+ dictWord{138, 0, 120},
+ dictWord{151, 0, 1},
+ dictWord{137, 10, 805},
+ dictWord{142, 0, 329},
+ dictWord{
+ 5,
+ 10,
+ 813,
+ },
+ dictWord{135, 10, 2046},
+ dictWord{135, 0, 226},
+ dictWord{138, 11, 96},
+ dictWord{7, 0, 1855},
+ dictWord{5, 10, 712},
+ dictWord{11, 10, 17},
+ dictWord{13, 10, 321},
+ dictWord{144, 10, 67},
+ dictWord{9, 0, 461},
+ dictWord{6, 10, 320},
+ dictWord{7, 10, 781},
+ dictWord{7, 10, 1921},
+ dictWord{9, 10, 55},
+ dictWord{
+ 10,
+ 10,
+ 186,
+ },
+ dictWord{10, 10, 273},
+ dictWord{10, 10, 664},
+ dictWord{10, 10, 801},
+ dictWord{11, 10, 996},
+ dictWord{11, 10, 997},
+ dictWord{13, 10, 157},
+ dictWord{142, 10, 170},
+ dictWord{8, 11, 203},
+ dictWord{8, 10, 271},
+ dictWord{11, 11, 823},
+ dictWord{11, 11, 846},
+ dictWord{12, 11, 482},
+ dictWord{
+ 13,
+ 11,
+ 133,
+ },
+ dictWord{13, 11, 277},
+ dictWord{13, 11, 302},
+ dictWord{13, 11, 464},
+ dictWord{14, 11, 205},
+ dictWord{142, 11, 221},
+ dictWord{135, 0, 1346},
+ dictWord{4, 11, 449},
+ dictWord{133, 11, 718},
+ dictWord{134, 0, 85},
+ dictWord{14, 0, 299},
+ dictWord{7, 10, 103},
+ dictWord{7, 10, 863},
+ dictWord{11, 10, 184},
+ dictWord{145, 10, 62},
+ dictWord{4, 11, 355},
+ dictWord{6, 11, 311},
+ dictWord{9, 11, 256},
+ dictWord{138, 11, 404},
+ dictWord{137, 10, 659},
+ dictWord{
+ 138,
+ 11,
+ 758,
+ },
+ dictWord{133, 11, 827},
+ dictWord{5, 11, 64},
+ dictWord{140, 11, 581},
+ dictWord{134, 0, 1171},
+ dictWord{4, 11, 442},
+ dictWord{7, 11, 1047},
+ dictWord{
+ 7,
+ 11,
+ 1352,
+ },
+ dictWord{135, 11, 1643},
+ dictWord{132, 0, 980},
+ dictWord{5, 11, 977},
+ dictWord{6, 11, 288},
+ dictWord{7, 11, 528},
+ dictWord{135, 11, 1065},
+ dictWord{5, 0, 279},
+ dictWord{6, 0, 235},
+ dictWord{7, 0, 468},
+ dictWord{8, 0, 446},
+ dictWord{9, 0, 637},
+ dictWord{10, 0, 717},
+ dictWord{11, 0, 738},
+ dictWord{
+ 140,
+ 0,
+ 514,
+ },
+ dictWord{132, 0, 293},
+ dictWord{11, 10, 337},
+ dictWord{142, 10, 303},
+ dictWord{136, 11, 285},
+ dictWord{5, 0, 17},
+ dictWord{6, 0, 371},
+ dictWord{
+ 9,
+ 0,
+ 528,
+ },
+ dictWord{12, 0, 364},
+ dictWord{132, 11, 254},
+ dictWord{5, 10, 77},
+ dictWord{7, 10, 1455},
+ dictWord{10, 10, 843},
+ dictWord{147, 10, 73},
+ dictWord{
+ 150,
+ 0,
+ 5,
+ },
+ dictWord{132, 10, 458},
+ dictWord{6, 11, 12},
+ dictWord{7, 11, 1219},
+ dictWord{145, 11, 73},
+ dictWord{135, 10, 1420},
+ dictWord{6, 10, 109},
+ dictWord{138, 10, 382},
+ dictWord{135, 11, 125},
+ dictWord{6, 10, 330},
+ dictWord{7, 10, 1084},
+ dictWord{139, 10, 142},
+ dictWord{6, 11, 369},
+ dictWord{
+ 6,
+ 11,
+ 502,
+ },
+ dictWord{7, 11, 1036},
+ dictWord{8, 11, 348},
+ dictWord{9, 11, 452},
+ dictWord{10, 11, 26},
+ dictWord{11, 11, 224},
+ dictWord{11, 11, 387},
+ dictWord{
+ 11,
+ 11,
+ 772,
+ },
+ dictWord{12, 11, 95},
+ dictWord{12, 11, 629},
+ dictWord{13, 11, 195},
+ dictWord{13, 11, 207},
+ dictWord{13, 11, 241},
+ dictWord{14, 11, 260},
+ dictWord{
+ 14,
+ 11,
+ 270,
+ },
+ dictWord{143, 11, 140},
+ dictWord{132, 11, 269},
+ dictWord{5, 11, 480},
+ dictWord{7, 11, 532},
+ dictWord{7, 11, 1197},
+ dictWord{7, 11, 1358},
+ dictWord{8, 11, 291},
+ dictWord{11, 11, 349},
+ dictWord{142, 11, 396},
+ dictWord{150, 0, 48},
+ dictWord{10, 0, 601},
+ dictWord{13, 0, 353},
+ dictWord{141, 0, 376},
+ dictWord{5, 0, 779},
+ dictWord{5, 0, 807},
+ dictWord{6, 0, 1655},
+ dictWord{134, 0, 1676},
+ dictWord{142, 11, 223},
+ dictWord{4, 0, 196},
+ dictWord{5, 0, 558},
+ dictWord{133, 0, 949},
+ dictWord{148, 11, 15},
+ dictWord{135, 11, 1764},
+ dictWord{134, 0, 1322},
+ dictWord{132, 0, 752},
+ dictWord{139, 0, 737},
+ dictWord{
+ 135,
+ 11,
+ 657,
+ },
+ dictWord{136, 11, 533},
+ dictWord{135, 0, 412},
+ dictWord{4, 0, 227},
+ dictWord{5, 0, 159},
+ dictWord{5, 0, 409},
+ dictWord{7, 0, 80},
+ dictWord{8, 0, 556},
+ dictWord{10, 0, 479},
+ dictWord{12, 0, 418},
+ dictWord{14, 0, 50},
+ dictWord{14, 0, 123},
+ dictWord{14, 0, 192},
+ dictWord{14, 0, 249},
+ dictWord{14, 0, 295},
+ dictWord{143, 0, 27},
+ dictWord{7, 0, 1470},
+ dictWord{8, 0, 66},
+ dictWord{8, 0, 137},
+ dictWord{8, 0, 761},
+ dictWord{9, 0, 638},
+ dictWord{11, 0, 80},
+ dictWord{11, 0, 212},
+ dictWord{11, 0, 368},
+ dictWord{11, 0, 418},
+ dictWord{12, 0, 8},
+ dictWord{13, 0, 15},
+ dictWord{16, 0, 61},
+ dictWord{17, 0, 59},
+ dictWord{19, 0, 28},
+ dictWord{
+ 148,
+ 0,
+ 84,
+ },
+ dictWord{135, 10, 1985},
+ dictWord{4, 11, 211},
+ dictWord{4, 11, 332},
+ dictWord{5, 11, 335},
+ dictWord{6, 11, 238},
+ dictWord{7, 11, 269},
+ dictWord{
+ 7,
+ 11,
+ 811,
+ },
+ dictWord{7, 11, 1797},
+ dictWord{8, 10, 122},
+ dictWord{8, 11, 836},
+ dictWord{9, 11, 507},
+ dictWord{141, 11, 242},
+ dictWord{6, 0, 683},
+ dictWord{
+ 134,
+ 0,
+ 1252,
+ },
+ dictWord{4, 0, 873},
+ dictWord{132, 10, 234},
+ dictWord{134, 0, 835},
+ dictWord{6, 0, 38},
+ dictWord{7, 0, 1220},
+ dictWord{8, 0, 185},
+ dictWord{8, 0, 256},
+ dictWord{9, 0, 22},
+ dictWord{9, 0, 331},
+ dictWord{10, 0, 738},
+ dictWord{11, 0, 205},
+ dictWord{11, 0, 540},
+ dictWord{11, 0, 746},
+ dictWord{13, 0, 465},
+ dictWord{
+ 14,
+ 0,
+ 88,
+ },
+ dictWord{142, 0, 194},
+ dictWord{138, 0, 986},
+ dictWord{5, 11, 1009},
+ dictWord{12, 11, 582},
+ dictWord{146, 11, 131},
+ dictWord{4, 0, 159},
+ dictWord{
+ 6,
+ 0,
+ 115,
+ },
+ dictWord{7, 0, 252},
+ dictWord{7, 0, 257},
+ dictWord{7, 0, 1928},
+ dictWord{8, 0, 69},
+ dictWord{9, 0, 384},
+ dictWord{10, 0, 91},
+ dictWord{10, 0, 615},
+ dictWord{
+ 12,
+ 0,
+ 375,
+ },
+ dictWord{14, 0, 235},
+ dictWord{18, 0, 117},
+ dictWord{147, 0, 123},
+ dictWord{133, 0, 911},
+ dictWord{136, 0, 278},
+ dictWord{5, 10, 430},
+ dictWord{
+ 5,
+ 10,
+ 932,
+ },
+ dictWord{6, 10, 131},
+ dictWord{7, 10, 417},
+ dictWord{9, 10, 522},
+ dictWord{11, 10, 314},
+ dictWord{141, 10, 390},
+ dictWord{14, 10, 149},
+ dictWord{14, 10, 399},
+ dictWord{143, 10, 57},
+ dictWord{4, 0, 151},
+ dictWord{7, 0, 1567},
+ dictWord{136, 0, 749},
+ dictWord{5, 11, 228},
+ dictWord{6, 11, 203},
+ dictWord{
+ 7,
+ 11,
+ 156,
+ },
+ dictWord{8, 11, 347},
+ dictWord{137, 11, 265},
+ dictWord{132, 10, 507},
+ dictWord{10, 0, 989},
+ dictWord{140, 0, 956},
+ dictWord{133, 0, 990},
+ dictWord{5, 0, 194},
+ dictWord{6, 0, 927},
+ dictWord{7, 0, 1662},
+ dictWord{9, 0, 90},
+ dictWord{140, 0, 564},
+ dictWord{4, 10, 343},
+ dictWord{133, 10, 511},
+ dictWord{133, 0, 425},
+ dictWord{7, 10, 455},
+ dictWord{138, 10, 591},
+ dictWord{4, 0, 774},
+ dictWord{7, 11, 476},
+ dictWord{7, 11, 1592},
+ dictWord{138, 11, 87},
+ dictWord{5, 0, 971},
+ dictWord{135, 10, 1381},
+ dictWord{5, 11, 318},
+ dictWord{147, 11, 121},
+ dictWord{5, 11, 291},
+ dictWord{7, 11, 765},
+ dictWord{9, 11, 389},
+ dictWord{140, 11, 548},
+ dictWord{134, 10, 575},
+ dictWord{4, 0, 827},
+ dictWord{12, 0, 646},
+ dictWord{12, 0, 705},
+ dictWord{12, 0, 712},
+ dictWord{140, 0, 714},
+ dictWord{139, 0, 752},
+ dictWord{137, 0, 662},
+ dictWord{5, 0, 72},
+ dictWord{6, 0, 264},
+ dictWord{7, 0, 21},
+ dictWord{7, 0, 46},
+ dictWord{7, 0, 2013},
+ dictWord{
+ 8,
+ 0,
+ 215,
+ },
+ dictWord{8, 0, 513},
+ dictWord{10, 0, 266},
+ dictWord{139, 0, 22},
+ dictWord{139, 11, 522},
+ dictWord{6, 0, 239},
+ dictWord{7, 0, 118},
+ dictWord{10, 0, 95},
+ dictWord{11, 0, 603},
+ dictWord{13, 0, 443},
+ dictWord{14, 0, 160},
+ dictWord{143, 0, 4},
+ dictWord{6, 0, 431},
+ dictWord{134, 0, 669},
+ dictWord{7, 10, 1127},
+ dictWord{
+ 7,
+ 10,
+ 1572,
+ },
+ dictWord{10, 10, 297},
+ dictWord{10, 10, 422},
+ dictWord{11, 10, 764},
+ dictWord{11, 10, 810},
+ dictWord{12, 10, 264},
+ dictWord{13, 10, 102},
+ dictWord{13, 10, 300},
+ dictWord{13, 10, 484},
+ dictWord{14, 10, 147},
+ dictWord{14, 10, 229},
+ dictWord{17, 10, 71},
+ dictWord{18, 10, 118},
+ dictWord{
+ 147,
+ 10,
+ 120,
+ },
+ dictWord{5, 0, 874},
+ dictWord{6, 0, 1677},
+ dictWord{15, 0, 0},
+ dictWord{10, 11, 525},
+ dictWord{139, 11, 82},
+ dictWord{6, 0, 65},
+ dictWord{7, 0, 939},
+ dictWord{
+ 7,
+ 0,
+ 1172,
+ },
+ dictWord{7, 0, 1671},
+ dictWord{9, 0, 540},
+ dictWord{10, 0, 696},
+ dictWord{11, 0, 265},
+ dictWord{11, 0, 732},
+ dictWord{11, 0, 928},
+ dictWord{
+ 11,
+ 0,
+ 937,
+ },
+ dictWord{141, 0, 438},
+ dictWord{134, 0, 1350},
+ dictWord{136, 11, 547},
+ dictWord{132, 11, 422},
+ dictWord{5, 11, 355},
+ dictWord{145, 11, 0},
+ dictWord{137, 11, 905},
+ dictWord{5, 0, 682},
+ dictWord{135, 0, 1887},
+ dictWord{132, 0, 809},
+ dictWord{4, 0, 696},
+ dictWord{133, 11, 865},
+ dictWord{6, 0, 1074},
+ dictWord{6, 0, 1472},
+ dictWord{14, 10, 35},
+ dictWord{142, 10, 191},
+ dictWord{5, 11, 914},
+ dictWord{134, 11, 1625},
+ dictWord{133, 11, 234},
+ dictWord{
+ 135,
+ 11,
+ 1383,
+ },
+ dictWord{137, 11, 780},
+ dictWord{132, 10, 125},
+ dictWord{4, 0, 726},
+ dictWord{133, 0, 630},
+ dictWord{8, 0, 802},
+ dictWord{136, 0, 838},
+ dictWord{132, 10, 721},
+ dictWord{6, 0, 1337},
+ dictWord{7, 0, 776},
+ dictWord{19, 0, 56},
+ dictWord{136, 10, 145},
+ dictWord{132, 0, 970},
+ dictWord{7, 10, 792},
+ dictWord{8, 10, 147},
+ dictWord{10, 10, 821},
+ dictWord{139, 10, 1021},
+ dictWord{139, 10, 970},
+ dictWord{8, 0, 940},
+ dictWord{137, 0, 797},
+ dictWord{
+ 135,
+ 11,
+ 1312,
+ },
+ dictWord{9, 0, 248},
+ dictWord{10, 0, 400},
+ dictWord{7, 11, 816},
+ dictWord{7, 11, 1241},
+ dictWord{7, 10, 1999},
+ dictWord{9, 11, 283},
+ dictWord{
+ 9,
+ 11,
+ 520,
+ },
+ dictWord{10, 11, 213},
+ dictWord{10, 11, 307},
+ dictWord{10, 11, 463},
+ dictWord{10, 11, 671},
+ dictWord{10, 11, 746},
+ dictWord{11, 11, 401},
+ dictWord{
+ 11,
+ 11,
+ 794,
+ },
+ dictWord{12, 11, 517},
+ dictWord{18, 11, 107},
+ dictWord{147, 11, 115},
+ dictWord{6, 0, 1951},
+ dictWord{134, 0, 2040},
+ dictWord{
+ 135,
+ 11,
+ 339,
+ },
+ dictWord{13, 0, 41},
+ dictWord{15, 0, 93},
+ dictWord{5, 10, 168},
+ dictWord{5, 10, 930},
+ dictWord{8, 10, 74},
+ dictWord{9, 10, 623},
+ dictWord{12, 10, 500},
+ dictWord{140, 10, 579},
+ dictWord{6, 0, 118},
+ dictWord{7, 0, 215},
+ dictWord{7, 0, 1521},
+ dictWord{140, 0, 11},
+ dictWord{6, 10, 220},
+ dictWord{7, 10, 1101},
+ dictWord{141, 10, 105},
+ dictWord{6, 11, 421},
+ dictWord{7, 11, 61},
+ dictWord{7, 11, 1540},
+ dictWord{10, 11, 11},
+ dictWord{138, 11, 501},
+ dictWord{7, 0, 615},
+ dictWord{138, 0, 251},
+ dictWord{140, 11, 631},
+ dictWord{135, 0, 1044},
+ dictWord{6, 10, 19},
+ dictWord{7, 10, 1413},
+ dictWord{139, 10, 428},
+ dictWord{
+ 133,
+ 0,
+ 225,
+ },
+ dictWord{7, 10, 96},
+ dictWord{8, 10, 401},
+ dictWord{8, 10, 703},
+ dictWord{137, 10, 896},
+ dictWord{145, 10, 116},
+ dictWord{6, 11, 102},
+ dictWord{
+ 7,
+ 11,
+ 72,
+ },
+ dictWord{15, 11, 142},
+ dictWord{147, 11, 67},
+ dictWord{7, 10, 1961},
+ dictWord{7, 10, 1965},
+ dictWord{8, 10, 702},
+ dictWord{136, 10, 750},
+ dictWord{
+ 7,
+ 10,
+ 2030,
+ },
+ dictWord{8, 10, 150},
+ dictWord{8, 10, 737},
+ dictWord{12, 10, 366},
+ dictWord{151, 11, 30},
+ dictWord{4, 0, 370},
+ dictWord{5, 0, 756},
+ dictWord{
+ 7,
+ 0,
+ 1326,
+ },
+ dictWord{135, 11, 823},
+ dictWord{8, 10, 800},
+ dictWord{9, 10, 148},
+ dictWord{9, 10, 872},
+ dictWord{9, 10, 890},
+ dictWord{11, 10, 309},
+ dictWord{
+ 11,
+ 10,
+ 1001,
+ },
+ dictWord{13, 10, 267},
+ dictWord{141, 10, 323},
+ dictWord{6, 0, 1662},
+ dictWord{7, 0, 48},
+ dictWord{8, 0, 771},
+ dictWord{10, 0, 116},
+ dictWord{
+ 13,
+ 0,
+ 104,
+ },
+ dictWord{14, 0, 105},
+ dictWord{14, 0, 184},
+ dictWord{15, 0, 168},
+ dictWord{19, 0, 92},
+ dictWord{148, 0, 68},
+ dictWord{10, 0, 209},
+ dictWord{
+ 135,
+ 11,
+ 1870,
+ },
+ dictWord{7, 11, 68},
+ dictWord{8, 11, 48},
+ dictWord{8, 11, 88},
+ dictWord{8, 11, 582},
+ dictWord{8, 11, 681},
+ dictWord{9, 11, 373},
+ dictWord{9, 11, 864},
+ dictWord{11, 11, 157},
+ dictWord{11, 11, 336},
+ dictWord{11, 11, 843},
+ dictWord{148, 11, 27},
+ dictWord{134, 0, 930},
+ dictWord{4, 11, 88},
+ dictWord{5, 11, 137},
+ dictWord{5, 11, 174},
+ dictWord{5, 11, 777},
+ dictWord{6, 11, 1664},
+ dictWord{6, 11, 1725},
+ dictWord{7, 11, 77},
+ dictWord{7, 11, 426},
+ dictWord{7, 11, 1317},
+ dictWord{7, 11, 1355},
+ dictWord{8, 11, 126},
+ dictWord{8, 11, 563},
+ dictWord{9, 11, 523},
+ dictWord{9, 11, 750},
+ dictWord{10, 11, 310},
+ dictWord{10, 11, 836},
+ dictWord{11, 11, 42},
+ dictWord{11, 11, 318},
+ dictWord{11, 11, 731},
+ dictWord{12, 11, 68},
+ dictWord{12, 11, 92},
+ dictWord{12, 11, 507},
+ dictWord{12, 11, 692},
+ dictWord{13, 11, 81},
+ dictWord{13, 11, 238},
+ dictWord{13, 11, 374},
+ dictWord{18, 11, 138},
+ dictWord{19, 11, 78},
+ dictWord{19, 11, 111},
+ dictWord{20, 11, 55},
+ dictWord{20, 11, 77},
+ dictWord{148, 11, 92},
+ dictWord{4, 11, 938},
+ dictWord{135, 11, 1831},
+ dictWord{5, 10, 547},
+ dictWord{7, 10, 424},
+ dictWord{
+ 8,
+ 11,
+ 617,
+ },
+ dictWord{138, 11, 351},
+ dictWord{6, 0, 1286},
+ dictWord{6, 11, 1668},
+ dictWord{7, 11, 1499},
+ dictWord{8, 11, 117},
+ dictWord{9, 11, 314},
+ dictWord{
+ 138,
+ 11,
+ 174,
+ },
+ dictWord{6, 0, 759},
+ dictWord{6, 0, 894},
+ dictWord{7, 11, 707},
+ dictWord{139, 11, 563},
+ dictWord{4, 0, 120},
+ dictWord{135, 0, 1894},
+ dictWord{
+ 9,
+ 0,
+ 385,
+ },
+ dictWord{149, 0, 17},
+ dictWord{138, 0, 429},
+ dictWord{133, 11, 403},
+ dictWord{5, 0, 820},
+ dictWord{135, 0, 931},
+ dictWord{10, 0, 199},
+ dictWord{
+ 133,
+ 10,
+ 133,
+ },
+ dictWord{6, 0, 151},
+ dictWord{6, 0, 1675},
+ dictWord{7, 0, 383},
+ dictWord{151, 0, 10},
+ dictWord{6, 0, 761},
+ dictWord{136, 10, 187},
+ dictWord{
+ 8,
+ 0,
+ 365,
+ },
+ dictWord{10, 10, 0},
+ dictWord{10, 10, 818},
+ dictWord{139, 10, 988},
+ dictWord{4, 11, 44},
+ dictWord{5, 11, 311},
+ dictWord{6, 11, 156},
+ dictWord{
+ 7,
+ 11,
+ 639,
+ },
+ dictWord{7, 11, 762},
+ dictWord{7, 11, 1827},
+ dictWord{9, 11, 8},
+ dictWord{9, 11, 462},
+ dictWord{148, 11, 83},
+ dictWord{4, 11, 346},
+ dictWord{7, 11, 115},
+ dictWord{9, 11, 180},
+ dictWord{9, 11, 456},
+ dictWord{138, 11, 363},
+ dictWord{136, 10, 685},
+ dictWord{7, 0, 1086},
+ dictWord{145, 0, 46},
+ dictWord{
+ 6,
+ 0,
+ 1624,
+ },
+ dictWord{11, 0, 11},
+ dictWord{12, 0, 422},
+ dictWord{13, 0, 444},
+ dictWord{142, 0, 360},
+ dictWord{6, 0, 1020},
+ dictWord{6, 0, 1260},
+ dictWord{
+ 134,
+ 0,
+ 1589,
+ },
+ dictWord{4, 0, 43},
+ dictWord{5, 0, 344},
+ dictWord{5, 0, 357},
+ dictWord{14, 0, 472},
+ dictWord{150, 0, 58},
+ dictWord{6, 0, 1864},
+ dictWord{6, 0, 1866},
+ dictWord{6, 0, 1868},
+ dictWord{6, 0, 1869},
+ dictWord{6, 0, 1874},
+ dictWord{6, 0, 1877},
+ dictWord{6, 0, 1903},
+ dictWord{6, 0, 1911},
+ dictWord{9, 0, 920},
+ dictWord{
+ 9,
+ 0,
+ 921,
+ },
+ dictWord{9, 0, 924},
+ dictWord{9, 0, 946},
+ dictWord{9, 0, 959},
+ dictWord{9, 0, 963},
+ dictWord{9, 0, 970},
+ dictWord{9, 0, 997},
+ dictWord{9, 0, 1008},
+ dictWord{
+ 9,
+ 0,
+ 1017,
+ },
+ dictWord{12, 0, 795},
+ dictWord{12, 0, 797},
+ dictWord{12, 0, 798},
+ dictWord{12, 0, 800},
+ dictWord{12, 0, 803},
+ dictWord{12, 0, 811},
+ dictWord{
+ 12,
+ 0,
+ 820,
+ },
+ dictWord{12, 0, 821},
+ dictWord{12, 0, 839},
+ dictWord{12, 0, 841},
+ dictWord{12, 0, 848},
+ dictWord{12, 0, 911},
+ dictWord{12, 0, 921},
+ dictWord{12, 0, 922},
+ dictWord{12, 0, 925},
+ dictWord{12, 0, 937},
+ dictWord{12, 0, 944},
+ dictWord{12, 0, 945},
+ dictWord{12, 0, 953},
+ dictWord{15, 0, 184},
+ dictWord{15, 0, 191},
+ dictWord{15, 0, 199},
+ dictWord{15, 0, 237},
+ dictWord{15, 0, 240},
+ dictWord{15, 0, 243},
+ dictWord{15, 0, 246},
+ dictWord{18, 0, 203},
+ dictWord{21, 0, 40},
+ dictWord{
+ 21,
+ 0,
+ 52,
+ },
+ dictWord{21, 0, 57},
+ dictWord{24, 0, 23},
+ dictWord{24, 0, 28},
+ dictWord{152, 0, 30},
+ dictWord{134, 0, 725},
+ dictWord{145, 11, 58},
+ dictWord{133, 0, 888},
+ dictWord{137, 10, 874},
+ dictWord{4, 0, 711},
+ dictWord{8, 10, 774},
+ dictWord{10, 10, 670},
+ dictWord{140, 10, 51},
+ dictWord{144, 11, 40},
+ dictWord{
+ 6,
+ 11,
+ 185,
+ },
+ dictWord{7, 11, 1899},
+ dictWord{139, 11, 673},
+ dictWord{137, 10, 701},
+ dictWord{137, 0, 440},
+ dictWord{4, 11, 327},
+ dictWord{5, 11, 478},
+ dictWord{
+ 7,
+ 11,
+ 1332,
+ },
+ dictWord{8, 11, 753},
+ dictWord{140, 11, 227},
+ dictWord{4, 10, 127},
+ dictWord{5, 10, 350},
+ dictWord{6, 10, 356},
+ dictWord{8, 10, 426},
+ dictWord{
+ 9,
+ 10,
+ 572,
+ },
+ dictWord{10, 10, 247},
+ dictWord{139, 10, 312},
+ dictWord{5, 11, 1020},
+ dictWord{133, 11, 1022},
+ dictWord{4, 11, 103},
+ dictWord{
+ 133,
+ 11,
+ 401,
+ },
+ dictWord{6, 0, 1913},
+ dictWord{6, 0, 1926},
+ dictWord{6, 0, 1959},
+ dictWord{9, 0, 914},
+ dictWord{9, 0, 939},
+ dictWord{9, 0, 952},
+ dictWord{9, 0, 979},
+ dictWord{
+ 9,
+ 0,
+ 990,
+ },
+ dictWord{9, 0, 998},
+ dictWord{9, 0, 1003},
+ dictWord{9, 0, 1023},
+ dictWord{12, 0, 827},
+ dictWord{12, 0, 834},
+ dictWord{12, 0, 845},
+ dictWord{
+ 12,
+ 0,
+ 912,
+ },
+ dictWord{12, 0, 935},
+ dictWord{12, 0, 951},
+ dictWord{15, 0, 172},
+ dictWord{15, 0, 174},
+ dictWord{18, 0, 198},
+ dictWord{149, 0, 63},
+ dictWord{5, 0, 958},
+ dictWord{5, 0, 987},
+ dictWord{4, 11, 499},
+ dictWord{135, 11, 1421},
+ dictWord{7, 0, 885},
+ dictWord{6, 10, 59},
+ dictWord{6, 10, 1762},
+ dictWord{9, 10, 603},
+ dictWord{141, 10, 397},
+ dictWord{10, 11, 62},
+ dictWord{141, 11, 164},
+ dictWord{4, 0, 847},
+ dictWord{135, 0, 326},
+ dictWord{11, 0, 276},
+ dictWord{142, 0, 293},
+ dictWord{4, 0, 65},
+ dictWord{5, 0, 479},
+ dictWord{5, 0, 1004},
+ dictWord{7, 0, 1913},
+ dictWord{8, 0, 317},
+ dictWord{9, 0, 302},
+ dictWord{10, 0, 612},
+ dictWord{
+ 13,
+ 0,
+ 22,
+ },
+ dictWord{132, 11, 96},
+ dictWord{4, 0, 261},
+ dictWord{135, 0, 510},
+ dictWord{135, 0, 1514},
+ dictWord{6, 10, 111},
+ dictWord{7, 10, 4},
+ dictWord{8, 10, 163},
+ dictWord{8, 10, 776},
+ dictWord{138, 10, 566},
+ dictWord{4, 0, 291},
+ dictWord{9, 0, 515},
+ dictWord{12, 0, 152},
+ dictWord{12, 0, 443},
+ dictWord{13, 0, 392},
+ dictWord{142, 0, 357},
+ dictWord{7, 11, 399},
+ dictWord{135, 11, 1492},
+ dictWord{4, 0, 589},
+ dictWord{139, 0, 282},
+ dictWord{6, 11, 563},
+ dictWord{
+ 135,
+ 10,
+ 1994,
+ },
+ dictWord{5, 10, 297},
+ dictWord{135, 10, 1038},
+ dictWord{4, 0, 130},
+ dictWord{7, 0, 843},
+ dictWord{135, 0, 1562},
+ dictWord{5, 0, 42},
+ dictWord{
+ 5,
+ 0,
+ 879,
+ },
+ dictWord{7, 0, 245},
+ dictWord{7, 0, 324},
+ dictWord{7, 0, 1532},
+ dictWord{11, 0, 463},
+ dictWord{11, 0, 472},
+ dictWord{13, 0, 363},
+ dictWord{144, 0, 52},
+ dictWord{4, 0, 134},
+ dictWord{133, 0, 372},
+ dictWord{133, 0, 680},
+ dictWord{136, 10, 363},
+ dictWord{6, 0, 1997},
+ dictWord{8, 0, 935},
+ dictWord{136, 0, 977},
+ dictWord{4, 0, 810},
+ dictWord{135, 0, 1634},
+ dictWord{135, 10, 1675},
+ dictWord{7, 0, 1390},
+ dictWord{4, 11, 910},
+ dictWord{133, 11, 832},
+ dictWord{
+ 7,
+ 10,
+ 808,
+ },
+ dictWord{8, 11, 266},
+ dictWord{139, 11, 578},
+ dictWord{132, 0, 644},
+ dictWord{4, 0, 982},
+ dictWord{138, 0, 867},
+ dictWord{132, 10, 280},
+ dictWord{
+ 135,
+ 0,
+ 540,
+ },
+ dictWord{140, 10, 54},
+ dictWord{135, 0, 123},
+ dictWord{134, 0, 1978},
+ dictWord{4, 10, 421},
+ dictWord{133, 10, 548},
+ dictWord{6, 0, 623},
+ dictWord{136, 0, 789},
+ dictWord{4, 0, 908},
+ dictWord{5, 0, 359},
+ dictWord{5, 0, 508},
+ dictWord{6, 0, 1723},
+ dictWord{7, 0, 343},
+ dictWord{7, 0, 1996},
+ dictWord{
+ 135,
+ 0,
+ 2026,
+ },
+ dictWord{134, 0, 1220},
+ dictWord{4, 0, 341},
+ dictWord{135, 0, 480},
+ dictWord{6, 10, 254},
+ dictWord{9, 10, 109},
+ dictWord{138, 10, 103},
+ dictWord{
+ 134,
+ 0,
+ 888,
+ },
+ dictWord{8, 11, 528},
+ dictWord{137, 11, 348},
+ dictWord{7, 0, 1995},
+ dictWord{8, 0, 299},
+ dictWord{11, 0, 890},
+ dictWord{12, 0, 674},
+ dictWord{
+ 4,
+ 11,
+ 20,
+ },
+ dictWord{133, 11, 616},
+ dictWord{135, 11, 1094},
+ dictWord{134, 10, 1630},
+ dictWord{4, 0, 238},
+ dictWord{5, 0, 503},
+ dictWord{6, 0, 179},
+ dictWord{
+ 7,
+ 0,
+ 2003,
+ },
+ dictWord{8, 0, 381},
+ dictWord{8, 0, 473},
+ dictWord{9, 0, 149},
+ dictWord{10, 0, 788},
+ dictWord{15, 0, 45},
+ dictWord{15, 0, 86},
+ dictWord{20, 0, 110},
+ dictWord{150, 0, 57},
+ dictWord{133, 10, 671},
+ dictWord{4, 11, 26},
+ dictWord{5, 11, 429},
+ dictWord{6, 11, 245},
+ dictWord{7, 11, 704},
+ dictWord{7, 11, 1379},
+ dictWord{135, 11, 1474},
+ dictWord{4, 0, 121},
+ dictWord{5, 0, 156},
+ dictWord{5, 0, 349},
+ dictWord{9, 0, 431},
+ dictWord{10, 0, 605},
+ dictWord{142, 0, 342},
+ dictWord{
+ 7,
+ 11,
+ 943,
+ },
+ dictWord{139, 11, 614},
+ dictWord{132, 10, 889},
+ dictWord{132, 11, 621},
+ dictWord{7, 10, 1382},
+ dictWord{7, 11, 1382},
+ dictWord{
+ 135,
+ 10,
+ 1910,
+ },
+ dictWord{132, 10, 627},
+ dictWord{133, 10, 775},
+ dictWord{133, 11, 542},
+ dictWord{133, 11, 868},
+ dictWord{136, 11, 433},
+ dictWord{6, 0, 1373},
+ dictWord{7, 0, 1011},
+ dictWord{11, 10, 362},
+ dictWord{11, 10, 948},
+ dictWord{140, 10, 388},
+ dictWord{6, 0, 80},
+ dictWord{7, 0, 173},
+ dictWord{9, 0, 547},
+ dictWord{10, 0, 730},
+ dictWord{14, 0, 18},
+ dictWord{22, 0, 39},
+ dictWord{135, 11, 1495},
+ dictWord{6, 0, 1694},
+ dictWord{135, 0, 1974},
+ dictWord{140, 0, 196},
+ dictWord{4, 0, 923},
+ dictWord{6, 0, 507},
+ dictWord{6, 0, 1711},
+ dictWord{7, 10, 451},
+ dictWord{8, 10, 389},
+ dictWord{12, 10, 490},
+ dictWord{13, 10, 16},
+ dictWord{
+ 13,
+ 10,
+ 215,
+ },
+ dictWord{13, 10, 351},
+ dictWord{18, 10, 132},
+ dictWord{147, 10, 125},
+ dictWord{6, 0, 646},
+ dictWord{134, 0, 1047},
+ dictWord{135, 10, 841},
+ dictWord{136, 10, 566},
+ dictWord{6, 0, 1611},
+ dictWord{135, 0, 1214},
+ dictWord{139, 0, 926},
+ dictWord{132, 11, 525},
+ dictWord{132, 0, 595},
+ dictWord{
+ 5,
+ 0,
+ 240,
+ },
+ dictWord{6, 0, 459},
+ dictWord{7, 0, 12},
+ dictWord{7, 0, 114},
+ dictWord{7, 0, 949},
+ dictWord{7, 0, 1753},
+ dictWord{7, 0, 1805},
+ dictWord{8, 0, 658},
+ dictWord{
+ 9,
+ 0,
+ 1,
+ },
+ dictWord{11, 0, 959},
+ dictWord{141, 0, 446},
+ dictWord{5, 10, 912},
+ dictWord{134, 10, 1695},
+ dictWord{132, 0, 446},
+ dictWord{7, 11, 62},
+ dictWord{
+ 12,
+ 11,
+ 45,
+ },
+ dictWord{147, 11, 112},
+ dictWord{5, 10, 236},
+ dictWord{6, 10, 572},
+ dictWord{8, 10, 492},
+ dictWord{11, 10, 618},
+ dictWord{144, 10, 56},
+ dictWord{
+ 5,
+ 10,
+ 190,
+ },
+ dictWord{136, 10, 318},
+ dictWord{135, 10, 1376},
+ dictWord{4, 11, 223},
+ dictWord{6, 11, 359},
+ dictWord{11, 11, 3},
+ dictWord{13, 11, 108},
+ dictWord{
+ 14,
+ 11,
+ 89,
+ },
+ dictWord{144, 11, 22},
+ dictWord{132, 11, 647},
+ dictWord{134, 0, 490},
+ dictWord{134, 0, 491},
+ dictWord{134, 0, 1584},
+ dictWord{
+ 135,
+ 11,
+ 685,
+ },
+ dictWord{138, 11, 220},
+ dictWord{7, 0, 250},
+ dictWord{136, 0, 507},
+ dictWord{132, 0, 158},
+ dictWord{4, 0, 140},
+ dictWord{7, 0, 362},
+ dictWord{8, 0, 209},
+ dictWord{9, 0, 10},
+ dictWord{9, 0, 160},
+ dictWord{9, 0, 503},
+ dictWord{9, 0, 614},
+ dictWord{10, 0, 689},
+ dictWord{11, 0, 327},
+ dictWord{11, 0, 553},
+ dictWord{
+ 11,
+ 0,
+ 725,
+ },
+ dictWord{11, 0, 767},
+ dictWord{12, 0, 252},
+ dictWord{12, 0, 583},
+ dictWord{13, 0, 192},
+ dictWord{14, 0, 269},
+ dictWord{14, 0, 356},
+ dictWord{148, 0, 50},
+ dictWord{19, 0, 1},
+ dictWord{19, 0, 26},
+ dictWord{150, 0, 9},
+ dictWord{132, 11, 109},
+ dictWord{6, 0, 228},
+ dictWord{7, 0, 1341},
+ dictWord{9, 0, 408},
+ dictWord{
+ 138,
+ 0,
+ 343,
+ },
+ dictWord{4, 0, 373},
+ dictWord{5, 0, 283},
+ dictWord{6, 0, 480},
+ dictWord{7, 0, 609},
+ dictWord{10, 0, 860},
+ dictWord{138, 0, 878},
+ dictWord{6, 0, 779},
+ dictWord{134, 0, 1209},
+ dictWord{4, 0, 557},
+ dictWord{7, 11, 263},
+ dictWord{7, 11, 628},
+ dictWord{136, 11, 349},
+ dictWord{132, 0, 548},
+ dictWord{7, 0, 197},
+ dictWord{8, 0, 142},
+ dictWord{8, 0, 325},
+ dictWord{9, 0, 150},
+ dictWord{9, 0, 596},
+ dictWord{10, 0, 350},
+ dictWord{10, 0, 353},
+ dictWord{11, 0, 74},
+ dictWord{
+ 11,
+ 0,
+ 315,
+ },
+ dictWord{12, 0, 662},
+ dictWord{12, 0, 681},
+ dictWord{14, 0, 423},
+ dictWord{143, 0, 141},
+ dictWord{4, 11, 40},
+ dictWord{10, 11, 67},
+ dictWord{
+ 11,
+ 11,
+ 117,
+ },
+ dictWord{11, 11, 768},
+ dictWord{139, 11, 935},
+ dictWord{7, 11, 992},
+ dictWord{8, 11, 301},
+ dictWord{9, 11, 722},
+ dictWord{12, 11, 63},
+ dictWord{
+ 13,
+ 11,
+ 29,
+ },
+ dictWord{14, 11, 161},
+ dictWord{143, 11, 18},
+ dictWord{6, 0, 1490},
+ dictWord{138, 11, 532},
+ dictWord{5, 0, 580},
+ dictWord{7, 0, 378},
+ dictWord{
+ 7,
+ 0,
+ 674,
+ },
+ dictWord{7, 0, 1424},
+ dictWord{15, 0, 83},
+ dictWord{16, 0, 11},
+ dictWord{15, 11, 83},
+ dictWord{144, 11, 11},
+ dictWord{6, 0, 1057},
+ dictWord{6, 0, 1335},
+ dictWord{10, 0, 316},
+ dictWord{7, 10, 85},
+ dictWord{7, 10, 247},
+ dictWord{8, 10, 585},
+ dictWord{138, 10, 163},
+ dictWord{4, 0, 169},
+ dictWord{5, 0, 83},
+ dictWord{
+ 6,
+ 0,
+ 399,
+ },
+ dictWord{6, 0, 579},
+ dictWord{6, 0, 1513},
+ dictWord{7, 0, 692},
+ dictWord{7, 0, 846},
+ dictWord{7, 0, 1015},
+ dictWord{7, 0, 1799},
+ dictWord{8, 0, 403},
+ dictWord{9, 0, 394},
+ dictWord{10, 0, 133},
+ dictWord{12, 0, 4},
+ dictWord{12, 0, 297},
+ dictWord{12, 0, 452},
+ dictWord{16, 0, 81},
+ dictWord{18, 0, 25},
+ dictWord{21, 0, 14},
+ dictWord{22, 0, 12},
+ dictWord{151, 0, 18},
+ dictWord{134, 0, 1106},
+ dictWord{7, 0, 1546},
+ dictWord{11, 0, 299},
+ dictWord{142, 0, 407},
+ dictWord{134, 0, 1192},
+ dictWord{132, 0, 177},
+ dictWord{5, 0, 411},
+ dictWord{135, 0, 653},
+ dictWord{7, 0, 439},
+ dictWord{10, 0, 727},
+ dictWord{11, 0, 260},
+ dictWord{139, 0, 684},
+ dictWord{138, 10, 145},
+ dictWord{147, 10, 83},
+ dictWord{5, 0, 208},
+ dictWord{7, 0, 753},
+ dictWord{135, 0, 1528},
+ dictWord{137, 11, 617},
+ dictWord{
+ 135,
+ 10,
+ 1922,
+ },
+ dictWord{135, 11, 825},
+ dictWord{11, 0, 422},
+ dictWord{13, 0, 389},
+ dictWord{4, 10, 124},
+ dictWord{10, 10, 457},
+ dictWord{11, 10, 121},
+ dictWord{
+ 11,
+ 10,
+ 169,
+ },
+ dictWord{11, 10, 870},
+ dictWord{12, 10, 214},
+ dictWord{14, 10, 187},
+ dictWord{143, 10, 77},
+ dictWord{11, 0, 615},
+ dictWord{15, 0, 58},
+ dictWord{
+ 11,
+ 11,
+ 615,
+ },
+ dictWord{143, 11, 58},
+ dictWord{9, 0, 618},
+ dictWord{138, 0, 482},
+ dictWord{6, 0, 1952},
+ dictWord{6, 0, 1970},
+ dictWord{142, 0, 505},
+ dictWord{
+ 7,
+ 10,
+ 1193,
+ },
+ dictWord{135, 11, 1838},
+ dictWord{133, 0, 242},
+ dictWord{135, 10, 1333},
+ dictWord{6, 10, 107},
+ dictWord{7, 10, 638},
+ dictWord{
+ 7,
+ 10,
+ 1632,
+ },
+ dictWord{137, 10, 396},
+ dictWord{133, 0, 953},
+ dictWord{5, 10, 370},
+ dictWord{134, 10, 1756},
+ dictWord{5, 11, 28},
+ dictWord{6, 11, 204},
+ dictWord{
+ 10,
+ 11,
+ 320,
+ },
+ dictWord{10, 11, 583},
+ dictWord{13, 11, 502},
+ dictWord{14, 11, 72},
+ dictWord{14, 11, 274},
+ dictWord{14, 11, 312},
+ dictWord{14, 11, 344},
+ dictWord{15, 11, 159},
+ dictWord{16, 11, 62},
+ dictWord{16, 11, 69},
+ dictWord{17, 11, 30},
+ dictWord{18, 11, 42},
+ dictWord{18, 11, 53},
+ dictWord{18, 11, 84},
+ dictWord{18, 11, 140},
+ dictWord{19, 11, 68},
+ dictWord{19, 11, 85},
+ dictWord{20, 11, 5},
+ dictWord{20, 11, 45},
+ dictWord{20, 11, 101},
+ dictWord{22, 11, 7},
+ dictWord{
+ 150,
+ 11,
+ 20,
+ },
+ dictWord{4, 11, 558},
+ dictWord{6, 11, 390},
+ dictWord{7, 11, 162},
+ dictWord{7, 11, 689},
+ dictWord{9, 11, 360},
+ dictWord{138, 11, 653},
+ dictWord{
+ 11,
+ 0,
+ 802,
+ },
+ dictWord{141, 0, 67},
+ dictWord{133, 10, 204},
+ dictWord{133, 0, 290},
+ dictWord{5, 10, 970},
+ dictWord{134, 10, 1706},
+ dictWord{132, 0, 380},
+ dictWord{5, 0, 52},
+ dictWord{7, 0, 277},
+ dictWord{9, 0, 368},
+ dictWord{139, 0, 791},
+ dictWord{5, 11, 856},
+ dictWord{6, 11, 1672},
+ dictWord{6, 11, 1757},
+ dictWord{
+ 6,
+ 11,
+ 1781,
+ },
+ dictWord{7, 11, 1150},
+ dictWord{7, 11, 1425},
+ dictWord{7, 11, 1453},
+ dictWord{140, 11, 513},
+ dictWord{5, 11, 92},
+ dictWord{7, 10, 3},
+ dictWord{
+ 10,
+ 11,
+ 736,
+ },
+ dictWord{140, 11, 102},
+ dictWord{4, 0, 112},
+ dictWord{5, 0, 653},
+ dictWord{5, 10, 483},
+ dictWord{5, 10, 685},
+ dictWord{6, 10, 489},
+ dictWord{
+ 7,
+ 10,
+ 1204,
+ },
+ dictWord{136, 10, 394},
+ dictWord{132, 10, 921},
+ dictWord{6, 0, 1028},
+ dictWord{133, 10, 1007},
+ dictWord{5, 11, 590},
+ dictWord{9, 11, 213},
+ dictWord{145, 11, 91},
+ dictWord{135, 10, 1696},
+ dictWord{10, 0, 138},
+ dictWord{139, 0, 476},
+ dictWord{5, 0, 725},
+ dictWord{5, 0, 727},
+ dictWord{135, 0, 1811},
+ dictWord{4, 0, 979},
+ dictWord{6, 0, 1821},
+ dictWord{6, 0, 1838},
+ dictWord{8, 0, 876},
+ dictWord{8, 0, 883},
+ dictWord{8, 0, 889},
+ dictWord{8, 0, 893},
+ dictWord{
+ 8,
+ 0,
+ 895,
+ },
+ dictWord{10, 0, 934},
+ dictWord{12, 0, 720},
+ dictWord{14, 0, 459},
+ dictWord{148, 0, 123},
+ dictWord{135, 11, 551},
+ dictWord{4, 0, 38},
+ dictWord{6, 0, 435},
+ dictWord{7, 0, 307},
+ dictWord{7, 0, 999},
+ dictWord{7, 0, 1481},
+ dictWord{7, 0, 1732},
+ dictWord{7, 0, 1738},
+ dictWord{8, 0, 371},
+ dictWord{9, 0, 414},
+ dictWord{
+ 11,
+ 0,
+ 316,
+ },
+ dictWord{12, 0, 52},
+ dictWord{13, 0, 420},
+ dictWord{147, 0, 100},
+ dictWord{135, 0, 1296},
+ dictWord{132, 10, 712},
+ dictWord{134, 10, 1629},
+ dictWord{133, 0, 723},
+ dictWord{134, 0, 651},
+ dictWord{136, 11, 191},
+ dictWord{9, 11, 791},
+ dictWord{10, 11, 93},
+ dictWord{11, 11, 301},
+ dictWord{16, 11, 13},
+ dictWord{17, 11, 23},
+ dictWord{18, 11, 135},
+ dictWord{19, 11, 12},
+ dictWord{20, 11, 1},
+ dictWord{20, 11, 12},
+ dictWord{148, 11, 14},
+ dictWord{136, 11, 503},
+ dictWord{6, 11, 466},
+ dictWord{135, 11, 671},
+ dictWord{6, 0, 1200},
+ dictWord{134, 0, 1330},
+ dictWord{135, 0, 1255},
+ dictWord{134, 0, 986},
+ dictWord{
+ 5,
+ 0,
+ 109,
+ },
+ dictWord{6, 0, 1784},
+ dictWord{7, 0, 1895},
+ dictWord{12, 0, 296},
+ dictWord{140, 0, 302},
+ dictWord{135, 11, 983},
+ dictWord{133, 10, 485},
+ dictWord{
+ 134,
+ 0,
+ 660,
+ },
+ dictWord{134, 0, 800},
+ dictWord{5, 0, 216},
+ dictWord{5, 0, 294},
+ dictWord{6, 0, 591},
+ dictWord{7, 0, 1879},
+ dictWord{9, 0, 141},
+ dictWord{9, 0, 270},
+ dictWord{9, 0, 679},
+ dictWord{10, 0, 159},
+ dictWord{11, 0, 197},
+ dictWord{11, 0, 438},
+ dictWord{12, 0, 538},
+ dictWord{12, 0, 559},
+ dictWord{14, 0, 144},
+ dictWord{
+ 14,
+ 0,
+ 167,
+ },
+ dictWord{15, 0, 67},
+ dictWord{4, 10, 285},
+ dictWord{5, 10, 317},
+ dictWord{6, 10, 301},
+ dictWord{7, 10, 7},
+ dictWord{8, 10, 153},
+ dictWord{
+ 10,
+ 10,
+ 766,
+ },
+ dictWord{11, 10, 468},
+ dictWord{12, 10, 467},
+ dictWord{141, 10, 143},
+ dictWord{136, 0, 945},
+ dictWord{134, 0, 1090},
+ dictWord{137, 0, 81},
+ dictWord{12, 11, 468},
+ dictWord{19, 11, 96},
+ dictWord{148, 11, 24},
+ dictWord{134, 0, 391},
+ dictWord{138, 11, 241},
+ dictWord{7, 0, 322},
+ dictWord{136, 0, 249},
+ dictWord{134, 0, 1412},
+ dictWord{135, 11, 795},
+ dictWord{5, 0, 632},
+ dictWord{138, 0, 526},
+ dictWord{136, 10, 819},
+ dictWord{6, 0, 144},
+ dictWord{7, 0, 948},
+ dictWord{7, 0, 1042},
+ dictWord{8, 0, 235},
+ dictWord{8, 0, 461},
+ dictWord{9, 0, 453},
+ dictWord{9, 0, 796},
+ dictWord{10, 0, 354},
+ dictWord{17, 0, 77},
+ dictWord{
+ 135,
+ 11,
+ 954,
+ },
+ dictWord{139, 10, 917},
+ dictWord{6, 0, 940},
+ dictWord{134, 0, 1228},
+ dictWord{4, 0, 362},
+ dictWord{7, 0, 52},
+ dictWord{135, 0, 303},
+ dictWord{
+ 6,
+ 11,
+ 549,
+ },
+ dictWord{8, 11, 34},
+ dictWord{8, 11, 283},
+ dictWord{9, 11, 165},
+ dictWord{138, 11, 475},
+ dictWord{7, 11, 370},
+ dictWord{7, 11, 1007},
+ dictWord{
+ 7,
+ 11,
+ 1177,
+ },
+ dictWord{135, 11, 1565},
+ dictWord{5, 11, 652},
+ dictWord{5, 11, 701},
+ dictWord{135, 11, 449},
+ dictWord{5, 0, 196},
+ dictWord{6, 0, 486},
+ dictWord{
+ 7,
+ 0,
+ 212,
+ },
+ dictWord{8, 0, 309},
+ dictWord{136, 0, 346},
+ dictWord{6, 10, 1719},
+ dictWord{6, 10, 1735},
+ dictWord{7, 10, 2016},
+ dictWord{7, 10, 2020},
+ dictWord{
+ 8,
+ 10,
+ 837,
+ },
+ dictWord{137, 10, 852},
+ dictWord{6, 11, 159},
+ dictWord{6, 11, 364},
+ dictWord{7, 11, 516},
+ dictWord{7, 11, 1439},
+ dictWord{137, 11, 518},
+ dictWord{135, 0, 1912},
+ dictWord{135, 0, 1290},
+ dictWord{132, 0, 686},
+ dictWord{141, 11, 151},
+ dictWord{138, 0, 625},
+ dictWord{136, 0, 706},
+ dictWord{
+ 138,
+ 10,
+ 568,
+ },
+ dictWord{139, 0, 412},
+ dictWord{4, 0, 30},
+ dictWord{133, 0, 43},
+ dictWord{8, 10, 67},
+ dictWord{138, 10, 419},
+ dictWord{7, 0, 967},
+ dictWord{
+ 141,
+ 0,
+ 11,
+ },
+ dictWord{12, 0, 758},
+ dictWord{14, 0, 441},
+ dictWord{142, 0, 462},
+ dictWord{10, 10, 657},
+ dictWord{14, 10, 297},
+ dictWord{142, 10, 361},
+ dictWord{
+ 139,
+ 10,
+ 729,
+ },
+ dictWord{4, 0, 220},
+ dictWord{135, 0, 1535},
+ dictWord{7, 11, 501},
+ dictWord{9, 11, 111},
+ dictWord{10, 11, 141},
+ dictWord{11, 11, 332},
+ dictWord{
+ 13,
+ 11,
+ 43,
+ },
+ dictWord{13, 11, 429},
+ dictWord{14, 11, 130},
+ dictWord{14, 11, 415},
+ dictWord{145, 11, 102},
+ dictWord{4, 0, 950},
+ dictWord{6, 0, 1859},
+ dictWord{
+ 7,
+ 0,
+ 11,
+ },
+ dictWord{8, 0, 873},
+ dictWord{12, 0, 710},
+ dictWord{12, 0, 718},
+ dictWord{12, 0, 748},
+ dictWord{12, 0, 765},
+ dictWord{148, 0, 124},
+ dictWord{
+ 5,
+ 11,
+ 149,
+ },
+ dictWord{5, 11, 935},
+ dictWord{136, 11, 233},
+ dictWord{142, 11, 291},
+ dictWord{134, 0, 1579},
+ dictWord{7, 0, 890},
+ dictWord{8, 10, 51},
+ dictWord{
+ 9,
+ 10,
+ 868,
+ },
+ dictWord{10, 10, 833},
+ dictWord{12, 10, 481},
+ dictWord{12, 10, 570},
+ dictWord{148, 10, 106},
+ dictWord{141, 0, 2},
+ dictWord{132, 10, 445},
+ dictWord{136, 11, 801},
+ dictWord{135, 0, 1774},
+ dictWord{7, 0, 1725},
+ dictWord{138, 0, 393},
+ dictWord{5, 0, 263},
+ dictWord{134, 0, 414},
+ dictWord{
+ 132,
+ 11,
+ 322,
+ },
+ dictWord{133, 10, 239},
+ dictWord{7, 0, 456},
+ dictWord{7, 10, 1990},
+ dictWord{8, 10, 130},
+ dictWord{139, 10, 720},
+ dictWord{137, 0, 818},
+ dictWord{
+ 5,
+ 10,
+ 123,
+ },
+ dictWord{6, 10, 530},
+ dictWord{7, 10, 348},
+ dictWord{135, 10, 1419},
+ dictWord{135, 10, 2024},
+ dictWord{6, 0, 178},
+ dictWord{6, 0, 1750},
+ dictWord{8, 0, 251},
+ dictWord{9, 0, 690},
+ dictWord{10, 0, 155},
+ dictWord{10, 0, 196},
+ dictWord{10, 0, 373},
+ dictWord{11, 0, 698},
+ dictWord{13, 0, 155},
+ dictWord{
+ 148,
+ 0,
+ 93,
+ },
+ dictWord{5, 0, 97},
+ dictWord{137, 0, 393},
+ dictWord{134, 0, 674},
+ dictWord{11, 0, 223},
+ dictWord{140, 0, 168},
+ dictWord{132, 10, 210},
+ dictWord{
+ 139,
+ 11,
+ 464,
+ },
+ dictWord{6, 0, 1639},
+ dictWord{146, 0, 159},
+ dictWord{139, 11, 2},
+ dictWord{7, 0, 934},
+ dictWord{8, 0, 647},
+ dictWord{17, 0, 97},
+ dictWord{19, 0, 59},
+ dictWord{150, 0, 2},
+ dictWord{132, 0, 191},
+ dictWord{5, 0, 165},
+ dictWord{9, 0, 346},
+ dictWord{10, 0, 655},
+ dictWord{11, 0, 885},
+ dictWord{4, 10, 430},
+ dictWord{135, 11, 357},
+ dictWord{133, 0, 877},
+ dictWord{5, 10, 213},
+ dictWord{133, 11, 406},
+ dictWord{8, 0, 128},
+ dictWord{139, 0, 179},
+ dictWord{6, 11, 69},
+ dictWord{135, 11, 117},
+ dictWord{135, 0, 1297},
+ dictWord{11, 11, 43},
+ dictWord{13, 11, 72},
+ dictWord{141, 11, 142},
+ dictWord{135, 11, 1830},
+ dictWord{
+ 142,
+ 0,
+ 164,
+ },
+ dictWord{5, 0, 57},
+ dictWord{6, 0, 101},
+ dictWord{6, 0, 586},
+ dictWord{6, 0, 1663},
+ dictWord{7, 0, 132},
+ dictWord{7, 0, 1154},
+ dictWord{7, 0, 1415},
+ dictWord{7, 0, 1507},
+ dictWord{12, 0, 493},
+ dictWord{15, 0, 105},
+ dictWord{151, 0, 15},
+ dictWord{5, 0, 459},
+ dictWord{7, 0, 1073},
+ dictWord{8, 0, 241},
+ dictWord{
+ 136,
+ 0,
+ 334,
+ },
+ dictWord{133, 11, 826},
+ dictWord{133, 10, 108},
+ dictWord{5, 10, 219},
+ dictWord{10, 11, 132},
+ dictWord{11, 11, 191},
+ dictWord{11, 11, 358},
+ dictWord{139, 11, 460},
+ dictWord{6, 0, 324},
+ dictWord{6, 0, 520},
+ dictWord{7, 0, 338},
+ dictWord{7, 0, 1729},
+ dictWord{8, 0, 228},
+ dictWord{139, 0, 750},
+ dictWord{
+ 21,
+ 0,
+ 30,
+ },
+ dictWord{22, 0, 53},
+ dictWord{4, 10, 193},
+ dictWord{5, 10, 916},
+ dictWord{7, 10, 364},
+ dictWord{10, 10, 398},
+ dictWord{10, 10, 726},
+ dictWord{
+ 11,
+ 10,
+ 317,
+ },
+ dictWord{11, 10, 626},
+ dictWord{12, 10, 142},
+ dictWord{12, 10, 288},
+ dictWord{12, 10, 678},
+ dictWord{13, 10, 313},
+ dictWord{15, 10, 113},
+ dictWord{146, 10, 114},
+ dictWord{6, 11, 110},
+ dictWord{135, 11, 1681},
+ dictWord{135, 0, 910},
+ dictWord{6, 10, 241},
+ dictWord{7, 10, 907},
+ dictWord{8, 10, 832},
+ dictWord{9, 10, 342},
+ dictWord{10, 10, 729},
+ dictWord{11, 10, 284},
+ dictWord{11, 10, 445},
+ dictWord{11, 10, 651},
+ dictWord{11, 10, 863},
+ dictWord{
+ 13,
+ 10,
+ 398,
+ },
+ dictWord{146, 10, 99},
+ dictWord{7, 0, 705},
+ dictWord{9, 0, 734},
+ dictWord{5, 11, 1000},
+ dictWord{7, 11, 733},
+ dictWord{137, 11, 583},
+ dictWord{4, 0, 73},
+ dictWord{6, 0, 612},
+ dictWord{7, 0, 927},
+ dictWord{7, 0, 1822},
+ dictWord{8, 0, 217},
+ dictWord{9, 0, 765},
+ dictWord{9, 0, 766},
+ dictWord{10, 0, 408},
+ dictWord{
+ 11,
+ 0,
+ 51,
+ },
+ dictWord{11, 0, 793},
+ dictWord{12, 0, 266},
+ dictWord{15, 0, 158},
+ dictWord{20, 0, 89},
+ dictWord{150, 0, 32},
+ dictWord{7, 0, 1330},
+ dictWord{4, 11, 297},
+ dictWord{6, 11, 529},
+ dictWord{7, 11, 152},
+ dictWord{7, 11, 713},
+ dictWord{7, 11, 1845},
+ dictWord{8, 11, 710},
+ dictWord{8, 11, 717},
+ dictWord{140, 11, 639},
+ dictWord{5, 0, 389},
+ dictWord{136, 0, 636},
+ dictWord{134, 0, 1409},
+ dictWord{4, 10, 562},
+ dictWord{9, 10, 254},
+ dictWord{139, 10, 879},
+ dictWord{134, 0, 893},
+ dictWord{132, 10, 786},
+ dictWord{4, 11, 520},
+ dictWord{135, 11, 575},
+ dictWord{136, 0, 21},
+ dictWord{140, 0, 721},
+ dictWord{136, 0, 959},
+ dictWord{
+ 7,
+ 11,
+ 1428,
+ },
+ dictWord{7, 11, 1640},
+ dictWord{9, 11, 169},
+ dictWord{9, 11, 182},
+ dictWord{9, 11, 367},
+ dictWord{9, 11, 478},
+ dictWord{9, 11, 506},
+ dictWord{
+ 9,
+ 11,
+ 551,
+ },
+ dictWord{9, 11, 648},
+ dictWord{9, 11, 651},
+ dictWord{9, 11, 697},
+ dictWord{9, 11, 705},
+ dictWord{9, 11, 725},
+ dictWord{9, 11, 787},
+ dictWord{9, 11, 794},
+ dictWord{10, 11, 198},
+ dictWord{10, 11, 214},
+ dictWord{10, 11, 267},
+ dictWord{10, 11, 275},
+ dictWord{10, 11, 456},
+ dictWord{10, 11, 551},
+ dictWord{
+ 10,
+ 11,
+ 561,
+ },
+ dictWord{10, 11, 613},
+ dictWord{10, 11, 627},
+ dictWord{10, 11, 668},
+ dictWord{10, 11, 675},
+ dictWord{10, 11, 691},
+ dictWord{10, 11, 695},
+ dictWord{10, 11, 707},
+ dictWord{10, 11, 715},
+ dictWord{11, 11, 183},
+ dictWord{11, 11, 201},
+ dictWord{11, 11, 244},
+ dictWord{11, 11, 262},
+ dictWord{
+ 11,
+ 11,
+ 352,
+ },
+ dictWord{11, 11, 439},
+ dictWord{11, 11, 493},
+ dictWord{11, 11, 572},
+ dictWord{11, 11, 591},
+ dictWord{11, 11, 608},
+ dictWord{11, 11, 611},
+ dictWord{
+ 11,
+ 11,
+ 646,
+ },
+ dictWord{11, 11, 674},
+ dictWord{11, 11, 711},
+ dictWord{11, 11, 751},
+ dictWord{11, 11, 761},
+ dictWord{11, 11, 776},
+ dictWord{11, 11, 785},
+ dictWord{11, 11, 850},
+ dictWord{11, 11, 853},
+ dictWord{11, 11, 862},
+ dictWord{11, 11, 865},
+ dictWord{11, 11, 868},
+ dictWord{11, 11, 898},
+ dictWord{
+ 11,
+ 11,
+ 902,
+ },
+ dictWord{11, 11, 903},
+ dictWord{11, 11, 910},
+ dictWord{11, 11, 932},
+ dictWord{11, 11, 942},
+ dictWord{11, 11, 957},
+ dictWord{11, 11, 967},
+ dictWord{
+ 11,
+ 11,
+ 972,
+ },
+ dictWord{12, 11, 148},
+ dictWord{12, 11, 195},
+ dictWord{12, 11, 220},
+ dictWord{12, 11, 237},
+ dictWord{12, 11, 318},
+ dictWord{12, 11, 339},
+ dictWord{12, 11, 393},
+ dictWord{12, 11, 445},
+ dictWord{12, 11, 450},
+ dictWord{12, 11, 474},
+ dictWord{12, 11, 509},
+ dictWord{12, 11, 533},
+ dictWord{
+ 12,
+ 11,
+ 591,
+ },
+ dictWord{12, 11, 594},
+ dictWord{12, 11, 597},
+ dictWord{12, 11, 621},
+ dictWord{12, 11, 633},
+ dictWord{12, 11, 642},
+ dictWord{13, 11, 59},
+ dictWord{
+ 13,
+ 11,
+ 60,
+ },
+ dictWord{13, 11, 145},
+ dictWord{13, 11, 239},
+ dictWord{13, 11, 250},
+ dictWord{13, 11, 273},
+ dictWord{13, 11, 329},
+ dictWord{13, 11, 344},
+ dictWord{13, 11, 365},
+ dictWord{13, 11, 372},
+ dictWord{13, 11, 387},
+ dictWord{13, 11, 403},
+ dictWord{13, 11, 414},
+ dictWord{13, 11, 456},
+ dictWord{
+ 13,
+ 11,
+ 478,
+ },
+ dictWord{13, 11, 483},
+ dictWord{13, 11, 489},
+ dictWord{14, 11, 55},
+ dictWord{14, 11, 57},
+ dictWord{14, 11, 81},
+ dictWord{14, 11, 90},
+ dictWord{
+ 14,
+ 11,
+ 148,
+ },
+ dictWord{14, 11, 239},
+ dictWord{14, 11, 266},
+ dictWord{14, 11, 321},
+ dictWord{14, 11, 326},
+ dictWord{14, 11, 327},
+ dictWord{14, 11, 330},
+ dictWord{
+ 14,
+ 11,
+ 347,
+ },
+ dictWord{14, 11, 355},
+ dictWord{14, 11, 401},
+ dictWord{14, 11, 411},
+ dictWord{14, 11, 414},
+ dictWord{14, 11, 416},
+ dictWord{14, 11, 420},
+ dictWord{15, 11, 61},
+ dictWord{15, 11, 74},
+ dictWord{15, 11, 87},
+ dictWord{15, 11, 88},
+ dictWord{15, 11, 94},
+ dictWord{15, 11, 96},
+ dictWord{15, 11, 116},
+ dictWord{15, 11, 149},
+ dictWord{15, 11, 154},
+ dictWord{16, 11, 50},
+ dictWord{16, 11, 63},
+ dictWord{16, 11, 73},
+ dictWord{17, 11, 2},
+ dictWord{17, 11, 66},
+ dictWord{
+ 17,
+ 11,
+ 92,
+ },
+ dictWord{17, 11, 103},
+ dictWord{17, 11, 112},
+ dictWord{18, 11, 50},
+ dictWord{18, 11, 54},
+ dictWord{18, 11, 82},
+ dictWord{18, 11, 86},
+ dictWord{
+ 18,
+ 11,
+ 90,
+ },
+ dictWord{18, 11, 111},
+ dictWord{18, 11, 115},
+ dictWord{18, 11, 156},
+ dictWord{19, 11, 40},
+ dictWord{19, 11, 79},
+ dictWord{20, 11, 78},
+ dictWord{
+ 149,
+ 11,
+ 22,
+ },
+ dictWord{137, 11, 170},
+ dictWord{134, 0, 1433},
+ dictWord{135, 11, 1307},
+ dictWord{139, 11, 411},
+ dictWord{5, 0, 189},
+ dictWord{7, 0, 442},
+ dictWord{7, 0, 443},
+ dictWord{8, 0, 281},
+ dictWord{12, 0, 174},
+ dictWord{141, 0, 261},
+ dictWord{6, 10, 216},
+ dictWord{7, 10, 901},
+ dictWord{7, 10, 1343},
+ dictWord{136, 10, 493},
+ dictWord{5, 11, 397},
+ dictWord{6, 11, 154},
+ dictWord{7, 10, 341},
+ dictWord{7, 11, 676},
+ dictWord{8, 11, 443},
+ dictWord{8, 11, 609},
+ dictWord{
+ 9,
+ 11,
+ 24,
+ },
+ dictWord{9, 11, 325},
+ dictWord{10, 11, 35},
+ dictWord{11, 10, 219},
+ dictWord{11, 11, 535},
+ dictWord{11, 11, 672},
+ dictWord{11, 11, 1018},
+ dictWord{12, 11, 637},
+ dictWord{144, 11, 30},
+ dictWord{6, 0, 2},
+ dictWord{7, 0, 191},
+ dictWord{7, 0, 446},
+ dictWord{7, 0, 1262},
+ dictWord{7, 0, 1737},
+ dictWord{8, 0, 22},
+ dictWord{8, 0, 270},
+ dictWord{8, 0, 612},
+ dictWord{9, 0, 4},
+ dictWord{9, 0, 312},
+ dictWord{9, 0, 436},
+ dictWord{9, 0, 626},
+ dictWord{10, 0, 216},
+ dictWord{10, 0, 311},
+ dictWord{10, 0, 521},
+ dictWord{10, 0, 623},
+ dictWord{11, 0, 72},
+ dictWord{11, 0, 330},
+ dictWord{11, 0, 455},
+ dictWord{12, 0, 321},
+ dictWord{12, 0, 504},
+ dictWord{12, 0, 530},
+ dictWord{12, 0, 543},
+ dictWord{13, 0, 17},
+ dictWord{13, 0, 156},
+ dictWord{13, 0, 334},
+ dictWord{14, 0, 131},
+ dictWord{17, 0, 60},
+ dictWord{
+ 148,
+ 0,
+ 64,
+ },
+ dictWord{7, 0, 354},
+ dictWord{10, 0, 410},
+ dictWord{139, 0, 815},
+ dictWord{139, 10, 130},
+ dictWord{7, 10, 1734},
+ dictWord{137, 11, 631},
+ dictWord{
+ 12,
+ 0,
+ 425,
+ },
+ dictWord{15, 0, 112},
+ dictWord{10, 10, 115},
+ dictWord{11, 10, 420},
+ dictWord{13, 10, 404},
+ dictWord{14, 10, 346},
+ dictWord{143, 10, 54},
+ dictWord{
+ 6,
+ 0,
+ 60,
+ },
+ dictWord{6, 0, 166},
+ dictWord{7, 0, 374},
+ dictWord{7, 0, 670},
+ dictWord{7, 0, 1327},
+ dictWord{8, 0, 411},
+ dictWord{8, 0, 435},
+ dictWord{9, 0, 653},
+ dictWord{
+ 9,
+ 0,
+ 740,
+ },
+ dictWord{10, 0, 385},
+ dictWord{11, 0, 222},
+ dictWord{11, 0, 324},
+ dictWord{11, 0, 829},
+ dictWord{140, 0, 611},
+ dictWord{7, 0, 1611},
+ dictWord{
+ 13,
+ 0,
+ 14,
+ },
+ dictWord{15, 0, 44},
+ dictWord{19, 0, 13},
+ dictWord{148, 0, 76},
+ dictWord{133, 11, 981},
+ dictWord{4, 11, 56},
+ dictWord{7, 11, 1791},
+ dictWord{8, 11, 607},
+ dictWord{8, 11, 651},
+ dictWord{11, 11, 465},
+ dictWord{11, 11, 835},
+ dictWord{12, 11, 337},
+ dictWord{141, 11, 480},
+ dictWord{6, 0, 1478},
+ dictWord{
+ 5,
+ 10,
+ 1011,
+ },
+ dictWord{136, 10, 701},
+ dictWord{139, 0, 596},
+ dictWord{5, 0, 206},
+ dictWord{134, 0, 398},
+ dictWord{4, 10, 54},
+ dictWord{5, 10, 666},
+ dictWord{
+ 7,
+ 10,
+ 1039,
+ },
+ dictWord{7, 10, 1130},
+ dictWord{9, 10, 195},
+ dictWord{138, 10, 302},
+ dictWord{7, 0, 50},
+ dictWord{9, 11, 158},
+ dictWord{138, 11, 411},
+ dictWord{
+ 135,
+ 11,
+ 1120,
+ },
+ dictWord{6, 0, 517},
+ dictWord{7, 0, 1159},
+ dictWord{10, 0, 621},
+ dictWord{11, 0, 192},
+ dictWord{134, 10, 1669},
+ dictWord{4, 0, 592},
+ dictWord{
+ 6,
+ 0,
+ 600,
+ },
+ dictWord{135, 0, 1653},
+ dictWord{10, 0, 223},
+ dictWord{139, 0, 645},
+ dictWord{136, 11, 139},
+ dictWord{7, 0, 64},
+ dictWord{136, 0, 245},
+ dictWord{
+ 142,
+ 0,
+ 278,
+ },
+ dictWord{6, 11, 622},
+ dictWord{135, 11, 1030},
+ dictWord{136, 0, 604},
+ dictWord{134, 0, 1502},
+ dictWord{138, 0, 265},
+ dictWord{
+ 141,
+ 11,
+ 168,
+ },
+ dictWord{7, 0, 1763},
+ dictWord{140, 0, 310},
+ dictWord{7, 10, 798},
+ dictWord{139, 11, 719},
+ dictWord{7, 11, 160},
+ dictWord{10, 11, 624},
+ dictWord{
+ 142,
+ 11,
+ 279,
+ },
+ dictWord{132, 11, 363},
+ dictWord{7, 10, 122},
+ dictWord{9, 10, 259},
+ dictWord{10, 10, 84},
+ dictWord{11, 10, 470},
+ dictWord{12, 10, 541},
+ dictWord{141, 10, 379},
+ dictWord{5, 0, 129},
+ dictWord{6, 0, 61},
+ dictWord{135, 0, 947},
+ dictWord{134, 0, 1356},
+ dictWord{135, 11, 1191},
+ dictWord{13, 0, 505},
+ dictWord{141, 0, 506},
+ dictWord{11, 0, 1000},
+ dictWord{5, 10, 82},
+ dictWord{5, 10, 131},
+ dictWord{7, 10, 1755},
+ dictWord{8, 10, 31},
+ dictWord{9, 10, 168},
+ dictWord{9, 10, 764},
+ dictWord{139, 10, 869},
+ dictWord{134, 0, 966},
+ dictWord{134, 10, 605},
+ dictWord{134, 11, 292},
+ dictWord{5, 11, 177},
+ dictWord{
+ 6,
+ 11,
+ 616,
+ },
+ dictWord{7, 11, 827},
+ dictWord{9, 11, 525},
+ dictWord{138, 11, 656},
+ dictWord{135, 11, 1486},
+ dictWord{138, 11, 31},
+ dictWord{5, 10, 278},
+ dictWord{137, 10, 68},
+ dictWord{4, 10, 163},
+ dictWord{5, 10, 201},
+ dictWord{5, 10, 307},
+ dictWord{5, 10, 310},
+ dictWord{6, 10, 335},
+ dictWord{7, 10, 284},
+ dictWord{136, 10, 165},
+ dictWord{6, 0, 839},
+ dictWord{135, 10, 1660},
+ dictWord{136, 10, 781},
+ dictWord{6, 10, 33},
+ dictWord{135, 10, 1244},
+ dictWord{
+ 133,
+ 0,
+ 637,
+ },
+ dictWord{4, 11, 161},
+ dictWord{133, 11, 631},
+ dictWord{137, 0, 590},
+ dictWord{7, 10, 1953},
+ dictWord{136, 10, 720},
+ dictWord{5, 0, 280},
+ dictWord{
+ 7,
+ 0,
+ 1226,
+ },
+ dictWord{138, 10, 203},
+ dictWord{134, 0, 1386},
+ dictWord{5, 0, 281},
+ dictWord{6, 0, 1026},
+ dictWord{6, 10, 326},
+ dictWord{7, 10, 677},
+ dictWord{
+ 137,
+ 10,
+ 425,
+ },
+ dictWord{7, 11, 1557},
+ dictWord{135, 11, 1684},
+ dictWord{135, 0, 1064},
+ dictWord{9, 11, 469},
+ dictWord{9, 11, 709},
+ dictWord{12, 11, 512},
+ dictWord{14, 11, 65},
+ dictWord{145, 11, 12},
+ dictWord{134, 0, 917},
+ dictWord{10, 11, 229},
+ dictWord{11, 11, 73},
+ dictWord{11, 11, 376},
+ dictWord{
+ 139,
+ 11,
+ 433,
+ },
+ dictWord{7, 0, 555},
+ dictWord{9, 0, 192},
+ dictWord{13, 0, 30},
+ dictWord{13, 0, 49},
+ dictWord{15, 0, 150},
+ dictWord{16, 0, 76},
+ dictWord{20, 0, 52},
+ dictWord{
+ 7,
+ 10,
+ 1316,
+ },
+ dictWord{7, 10, 1412},
+ dictWord{7, 10, 1839},
+ dictWord{9, 10, 589},
+ dictWord{11, 10, 241},
+ dictWord{11, 10, 676},
+ dictWord{11, 10, 811},
+ dictWord{11, 10, 891},
+ dictWord{12, 10, 140},
+ dictWord{12, 10, 346},
+ dictWord{12, 10, 479},
+ dictWord{13, 10, 381},
+ dictWord{14, 10, 188},
+ dictWord{
+ 146,
+ 10,
+ 30,
+ },
+ dictWord{149, 0, 15},
+ dictWord{6, 0, 1882},
+ dictWord{6, 0, 1883},
+ dictWord{6, 0, 1897},
+ dictWord{9, 0, 945},
+ dictWord{9, 0, 1014},
+ dictWord{9, 0, 1020},
+ dictWord{12, 0, 823},
+ dictWord{12, 0, 842},
+ dictWord{12, 0, 866},
+ dictWord{12, 0, 934},
+ dictWord{15, 0, 242},
+ dictWord{146, 0, 208},
+ dictWord{6, 0, 965},
+ dictWord{134, 0, 1499},
+ dictWord{7, 0, 33},
+ dictWord{7, 0, 120},
+ dictWord{8, 0, 489},
+ dictWord{9, 0, 319},
+ dictWord{10, 0, 820},
+ dictWord{11, 0, 1004},
+ dictWord{
+ 12,
+ 0,
+ 379,
+ },
+ dictWord{12, 0, 679},
+ dictWord{13, 0, 117},
+ dictWord{13, 0, 412},
+ dictWord{14, 0, 25},
+ dictWord{15, 0, 52},
+ dictWord{15, 0, 161},
+ dictWord{16, 0, 47},
+ dictWord{149, 0, 2},
+ dictWord{6, 11, 558},
+ dictWord{7, 11, 651},
+ dictWord{8, 11, 421},
+ dictWord{9, 11, 0},
+ dictWord{138, 11, 34},
+ dictWord{4, 0, 937},
+ dictWord{
+ 5,
+ 0,
+ 801,
+ },
+ dictWord{7, 0, 473},
+ dictWord{5, 10, 358},
+ dictWord{7, 10, 1184},
+ dictWord{10, 10, 662},
+ dictWord{13, 10, 212},
+ dictWord{13, 10, 304},
+ dictWord{
+ 13,
+ 10,
+ 333,
+ },
+ dictWord{145, 10, 98},
+ dictWord{132, 0, 877},
+ dictWord{6, 0, 693},
+ dictWord{134, 0, 824},
+ dictWord{132, 0, 365},
+ dictWord{7, 11, 1832},
+ dictWord{
+ 138,
+ 11,
+ 374,
+ },
+ dictWord{5, 0, 7},
+ dictWord{139, 0, 774},
+ dictWord{4, 0, 734},
+ dictWord{5, 0, 662},
+ dictWord{134, 0, 430},
+ dictWord{4, 0, 746},
+ dictWord{
+ 135,
+ 0,
+ 1090,
+ },
+ dictWord{5, 0, 360},
+ dictWord{8, 0, 237},
+ dictWord{10, 0, 231},
+ dictWord{147, 0, 124},
+ dictWord{138, 11, 348},
+ dictWord{6, 11, 6},
+ dictWord{7, 11, 81},
+ dictWord{7, 11, 771},
+ dictWord{7, 11, 1731},
+ dictWord{9, 11, 405},
+ dictWord{138, 11, 421},
+ dictWord{6, 0, 740},
+ dictWord{137, 0, 822},
+ dictWord{
+ 133,
+ 10,
+ 946,
+ },
+ dictWord{7, 0, 1485},
+ dictWord{136, 0, 929},
+ dictWord{7, 10, 411},
+ dictWord{8, 10, 631},
+ dictWord{9, 10, 323},
+ dictWord{10, 10, 355},
+ dictWord{
+ 11,
+ 10,
+ 491,
+ },
+ dictWord{12, 10, 143},
+ dictWord{12, 10, 402},
+ dictWord{13, 10, 73},
+ dictWord{14, 10, 408},
+ dictWord{15, 10, 107},
+ dictWord{146, 10, 71},
+ dictWord{
+ 135,
+ 10,
+ 590,
+ },
+ dictWord{5, 11, 881},
+ dictWord{133, 11, 885},
+ dictWord{150, 11, 25},
+ dictWord{4, 0, 852},
+ dictWord{5, 11, 142},
+ dictWord{134, 11, 546},
+ dictWord{7, 10, 1467},
+ dictWord{8, 10, 328},
+ dictWord{10, 10, 544},
+ dictWord{11, 10, 955},
+ dictWord{13, 10, 320},
+ dictWord{145, 10, 83},
+ dictWord{9, 0, 17},
+ dictWord{10, 0, 291},
+ dictWord{11, 10, 511},
+ dictWord{13, 10, 394},
+ dictWord{14, 10, 298},
+ dictWord{14, 10, 318},
+ dictWord{146, 10, 103},
+ dictWord{5, 11, 466},
+ dictWord{11, 11, 571},
+ dictWord{12, 11, 198},
+ dictWord{13, 11, 283},
+ dictWord{14, 11, 186},
+ dictWord{15, 11, 21},
+ dictWord{143, 11, 103},
+ dictWord{
+ 134,
+ 0,
+ 1001,
+ },
+ dictWord{4, 11, 185},
+ dictWord{5, 11, 257},
+ dictWord{5, 11, 839},
+ dictWord{5, 11, 936},
+ dictWord{7, 11, 171},
+ dictWord{9, 11, 399},
+ dictWord{
+ 10,
+ 11,
+ 258,
+ },
+ dictWord{10, 11, 395},
+ dictWord{10, 11, 734},
+ dictWord{11, 11, 1014},
+ dictWord{12, 11, 23},
+ dictWord{13, 11, 350},
+ dictWord{14, 11, 150},
+ dictWord{147, 11, 6},
+ dictWord{143, 0, 35},
+ dictWord{132, 0, 831},
+ dictWord{5, 10, 835},
+ dictWord{134, 10, 483},
+ dictWord{4, 0, 277},
+ dictWord{5, 0, 608},
+ dictWord{
+ 6,
+ 0,
+ 493,
+ },
+ dictWord{7, 0, 457},
+ dictWord{12, 0, 384},
+ dictWord{7, 11, 404},
+ dictWord{7, 11, 1377},
+ dictWord{7, 11, 1430},
+ dictWord{7, 11, 2017},
+ dictWord{
+ 8,
+ 11,
+ 149,
+ },
+ dictWord{8, 11, 239},
+ dictWord{8, 11, 512},
+ dictWord{8, 11, 793},
+ dictWord{8, 11, 818},
+ dictWord{9, 11, 474},
+ dictWord{9, 11, 595},
+ dictWord{
+ 10,
+ 11,
+ 122,
+ },
+ dictWord{10, 11, 565},
+ dictWord{10, 11, 649},
+ dictWord{10, 11, 783},
+ dictWord{11, 11, 239},
+ dictWord{11, 11, 295},
+ dictWord{11, 11, 447},
+ dictWord{
+ 11,
+ 11,
+ 528,
+ },
+ dictWord{11, 11, 639},
+ dictWord{11, 11, 800},
+ dictWord{11, 11, 936},
+ dictWord{12, 11, 25},
+ dictWord{12, 11, 73},
+ dictWord{12, 11, 77},
+ dictWord{12, 11, 157},
+ dictWord{12, 11, 316},
+ dictWord{12, 11, 390},
+ dictWord{12, 11, 391},
+ dictWord{12, 11, 394},
+ dictWord{12, 11, 395},
+ dictWord{
+ 12,
+ 11,
+ 478,
+ },
+ dictWord{12, 11, 503},
+ dictWord{12, 11, 592},
+ dictWord{12, 11, 680},
+ dictWord{13, 11, 50},
+ dictWord{13, 11, 53},
+ dictWord{13, 11, 132},
+ dictWord{
+ 13,
+ 11,
+ 198,
+ },
+ dictWord{13, 11, 275},
+ dictWord{13, 11, 322},
+ dictWord{13, 11, 415},
+ dictWord{14, 11, 71},
+ dictWord{14, 11, 257},
+ dictWord{14, 11, 395},
+ dictWord{15, 11, 71},
+ dictWord{15, 11, 136},
+ dictWord{17, 11, 123},
+ dictWord{18, 11, 93},
+ dictWord{147, 11, 58},
+ dictWord{134, 0, 1351},
+ dictWord{7, 0, 27},
+ dictWord{135, 0, 316},
+ dictWord{136, 11, 712},
+ dictWord{136, 0, 984},
+ dictWord{133, 0, 552},
+ dictWord{137, 0, 264},
+ dictWord{132, 0, 401},
+ dictWord{6, 0, 710},
+ dictWord{6, 0, 1111},
+ dictWord{134, 0, 1343},
+ dictWord{134, 0, 1211},
+ dictWord{9, 0, 543},
+ dictWord{10, 0, 524},
+ dictWord{11, 0, 108},
+ dictWord{11, 0, 653},
+ dictWord{12, 0, 524},
+ dictWord{13, 0, 123},
+ dictWord{14, 0, 252},
+ dictWord{16, 0, 18},
+ dictWord{19, 0, 38},
+ dictWord{20, 0, 26},
+ dictWord{20, 0, 65},
+ dictWord{
+ 21,
+ 0,
+ 3,
+ },
+ dictWord{151, 0, 11},
+ dictWord{4, 0, 205},
+ dictWord{5, 0, 623},
+ dictWord{7, 0, 104},
+ dictWord{8, 0, 519},
+ dictWord{137, 0, 716},
+ dictWord{132, 10, 677},
+ dictWord{4, 11, 377},
+ dictWord{152, 11, 13},
+ dictWord{135, 11, 1673},
+ dictWord{7, 0, 579},
+ dictWord{9, 0, 41},
+ dictWord{9, 0, 244},
+ dictWord{9, 0, 669},
+ dictWord{
+ 10,
+ 0,
+ 5,
+ },
+ dictWord{11, 0, 861},
+ dictWord{11, 0, 951},
+ dictWord{139, 0, 980},
+ dictWord{132, 0, 717},
+ dictWord{136, 0, 1011},
+ dictWord{132, 0, 805},
+ dictWord{
+ 4,
+ 11,
+ 180,
+ },
+ dictWord{135, 11, 1906},
+ dictWord{132, 10, 777},
+ dictWord{132, 10, 331},
+ dictWord{132, 0, 489},
+ dictWord{6, 0, 1024},
+ dictWord{4, 11, 491},
+ dictWord{133, 10, 747},
+ dictWord{135, 11, 1182},
+ dictWord{4, 11, 171},
+ dictWord{138, 11, 234},
+ dictWord{4, 11, 586},
+ dictWord{7, 11, 1186},
+ dictWord{
+ 138,
+ 11,
+ 631,
+ },
+ dictWord{135, 0, 892},
+ dictWord{135, 11, 336},
+ dictWord{9, 11, 931},
+ dictWord{10, 11, 334},
+ dictWord{148, 11, 71},
+ dictWord{137, 0, 473},
+ dictWord{6, 0, 864},
+ dictWord{12, 0, 659},
+ dictWord{139, 11, 926},
+ dictWord{7, 0, 819},
+ dictWord{9, 0, 26},
+ dictWord{9, 0, 392},
+ dictWord{10, 0, 152},
+ dictWord{
+ 10,
+ 0,
+ 226,
+ },
+ dictWord{11, 0, 19},
+ dictWord{12, 0, 276},
+ dictWord{12, 0, 426},
+ dictWord{12, 0, 589},
+ dictWord{13, 0, 460},
+ dictWord{15, 0, 97},
+ dictWord{19, 0, 48},
+ dictWord{148, 0, 104},
+ dictWord{135, 0, 51},
+ dictWord{133, 10, 326},
+ dictWord{4, 10, 691},
+ dictWord{146, 10, 16},
+ dictWord{9, 0, 130},
+ dictWord{11, 0, 765},
+ dictWord{10, 10, 680},
+ dictWord{10, 10, 793},
+ dictWord{141, 10, 357},
+ dictWord{133, 11, 765},
+ dictWord{8, 0, 229},
+ dictWord{6, 10, 32},
+ dictWord{7, 10, 385},
+ dictWord{7, 10, 757},
+ dictWord{7, 10, 1916},
+ dictWord{8, 10, 94},
+ dictWord{8, 10, 711},
+ dictWord{9, 10, 541},
+ dictWord{10, 10, 162},
+ dictWord{10, 10, 795},
+ dictWord{11, 10, 989},
+ dictWord{11, 10, 1010},
+ dictWord{12, 10, 14},
+ dictWord{142, 10, 308},
+ dictWord{7, 11, 474},
+ dictWord{137, 11, 578},
+ dictWord{
+ 132,
+ 0,
+ 674,
+ },
+ dictWord{132, 0, 770},
+ dictWord{5, 0, 79},
+ dictWord{7, 0, 1027},
+ dictWord{7, 0, 1477},
+ dictWord{139, 0, 52},
+ dictWord{133, 11, 424},
+ dictWord{
+ 134,
+ 0,
+ 1666,
+ },
+ dictWord{6, 0, 409},
+ dictWord{6, 10, 349},
+ dictWord{6, 10, 1682},
+ dictWord{7, 10, 1252},
+ dictWord{8, 10, 112},
+ dictWord{8, 11, 714},
+ dictWord{
+ 9,
+ 10,
+ 435,
+ },
+ dictWord{9, 10, 668},
+ dictWord{10, 10, 290},
+ dictWord{10, 10, 319},
+ dictWord{10, 10, 815},
+ dictWord{11, 10, 180},
+ dictWord{11, 10, 837},
+ dictWord{
+ 12,
+ 10,
+ 240,
+ },
+ dictWord{13, 10, 152},
+ dictWord{13, 10, 219},
+ dictWord{142, 10, 158},
+ dictWord{5, 0, 789},
+ dictWord{134, 0, 195},
+ dictWord{4, 0, 251},
+ dictWord{
+ 4,
+ 0,
+ 688,
+ },
+ dictWord{7, 0, 513},
+ dictWord{135, 0, 1284},
+ dictWord{132, 10, 581},
+ dictWord{9, 11, 420},
+ dictWord{10, 11, 269},
+ dictWord{10, 11, 285},
+ dictWord{10, 11, 576},
+ dictWord{11, 11, 397},
+ dictWord{13, 11, 175},
+ dictWord{145, 11, 90},
+ dictWord{6, 10, 126},
+ dictWord{7, 10, 573},
+ dictWord{8, 10, 397},
+ dictWord{142, 10, 44},
+ dictWord{132, 11, 429},
+ dictWord{133, 0, 889},
+ dictWord{4, 0, 160},
+ dictWord{5, 0, 330},
+ dictWord{7, 0, 1434},
+ dictWord{136, 0, 174},
+ dictWord{7, 11, 18},
+ dictWord{7, 11, 699},
+ dictWord{7, 11, 1966},
+ dictWord{8, 11, 752},
+ dictWord{9, 11, 273},
+ dictWord{9, 11, 412},
+ dictWord{9, 11, 703},
+ dictWord{
+ 10,
+ 11,
+ 71,
+ },
+ dictWord{10, 11, 427},
+ dictWord{10, 11, 508},
+ dictWord{146, 11, 97},
+ dictWord{6, 0, 872},
+ dictWord{134, 0, 899},
+ dictWord{133, 10, 926},
+ dictWord{134, 0, 1126},
+ dictWord{134, 0, 918},
+ dictWord{4, 11, 53},
+ dictWord{5, 11, 186},
+ dictWord{135, 11, 752},
+ dictWord{7, 0, 268},
+ dictWord{136, 0, 569},
+ dictWord{134, 0, 1224},
+ dictWord{6, 0, 1361},
+ dictWord{7, 10, 1232},
+ dictWord{137, 10, 531},
+ dictWord{8, 11, 575},
+ dictWord{10, 11, 289},
+ dictWord{
+ 139,
+ 11,
+ 319,
+ },
+ dictWord{133, 10, 670},
+ dictWord{132, 11, 675},
+ dictWord{133, 0, 374},
+ dictWord{135, 10, 1957},
+ dictWord{133, 0, 731},
+ dictWord{11, 0, 190},
+ dictWord{15, 0, 49},
+ dictWord{11, 11, 190},
+ dictWord{143, 11, 49},
+ dictWord{4, 0, 626},
+ dictWord{5, 0, 506},
+ dictWord{5, 0, 642},
+ dictWord{6, 0, 425},
+ dictWord{
+ 10,
+ 0,
+ 202,
+ },
+ dictWord{139, 0, 141},
+ dictWord{137, 0, 444},
+ dictWord{7, 10, 242},
+ dictWord{135, 10, 1942},
+ dictWord{6, 11, 209},
+ dictWord{8, 11, 468},
+ dictWord{
+ 9,
+ 11,
+ 210,
+ },
+ dictWord{11, 11, 36},
+ dictWord{12, 11, 28},
+ dictWord{12, 11, 630},
+ dictWord{13, 11, 21},
+ dictWord{13, 11, 349},
+ dictWord{14, 11, 7},
+ dictWord{
+ 145,
+ 11,
+ 13,
+ },
+ dictWord{4, 11, 342},
+ dictWord{135, 11, 1179},
+ dictWord{5, 10, 834},
+ dictWord{7, 10, 1202},
+ dictWord{8, 10, 14},
+ dictWord{9, 10, 481},
+ dictWord{
+ 137,
+ 10,
+ 880,
+ },
+ dictWord{4, 11, 928},
+ dictWord{133, 11, 910},
+ dictWord{4, 11, 318},
+ dictWord{4, 11, 496},
+ dictWord{7, 11, 856},
+ dictWord{139, 11, 654},
+ dictWord{136, 0, 835},
+ dictWord{7, 0, 1526},
+ dictWord{138, 10, 465},
+ dictWord{151, 0, 17},
+ dictWord{135, 0, 477},
+ dictWord{4, 10, 357},
+ dictWord{6, 10, 172},
+ dictWord{7, 10, 143},
+ dictWord{137, 10, 413},
+ dictWord{6, 0, 1374},
+ dictWord{138, 0, 994},
+ dictWord{18, 0, 76},
+ dictWord{132, 10, 590},
+ dictWord{7, 0, 287},
+ dictWord{8, 0, 355},
+ dictWord{9, 0, 293},
+ dictWord{137, 0, 743},
+ dictWord{134, 0, 1389},
+ dictWord{7, 11, 915},
+ dictWord{8, 11, 247},
+ dictWord{147, 11, 0},
+ dictWord{
+ 4,
+ 11,
+ 202,
+ },
+ dictWord{5, 11, 382},
+ dictWord{6, 11, 454},
+ dictWord{7, 11, 936},
+ dictWord{7, 11, 1803},
+ dictWord{8, 11, 758},
+ dictWord{9, 11, 375},
+ dictWord{
+ 9,
+ 11,
+ 895,
+ },
+ dictWord{10, 11, 743},
+ dictWord{10, 11, 792},
+ dictWord{11, 11, 978},
+ dictWord{11, 11, 1012},
+ dictWord{142, 11, 109},
+ dictWord{5, 0, 384},
+ dictWord{8, 0, 455},
+ dictWord{140, 0, 48},
+ dictWord{132, 11, 390},
+ dictWord{5, 10, 169},
+ dictWord{7, 10, 333},
+ dictWord{136, 10, 45},
+ dictWord{5, 0, 264},
+ dictWord{134, 0, 184},
+ dictWord{138, 11, 791},
+ dictWord{133, 11, 717},
+ dictWord{132, 10, 198},
+ dictWord{6, 11, 445},
+ dictWord{7, 11, 332},
+ dictWord{
+ 137,
+ 11,
+ 909,
+ },
+ dictWord{136, 0, 1001},
+ dictWord{4, 10, 24},
+ dictWord{5, 10, 140},
+ dictWord{5, 10, 185},
+ dictWord{7, 10, 1500},
+ dictWord{11, 10, 565},
+ dictWord{
+ 139,
+ 10,
+ 838,
+ },
+ dictWord{134, 11, 578},
+ dictWord{5, 0, 633},
+ dictWord{6, 0, 28},
+ dictWord{135, 0, 1323},
+ dictWord{132, 0, 851},
+ dictWord{136, 11, 267},
+ dictWord{
+ 7,
+ 0,
+ 359,
+ },
+ dictWord{8, 0, 243},
+ dictWord{140, 0, 175},
+ dictWord{4, 10, 334},
+ dictWord{133, 10, 593},
+ dictWord{141, 11, 87},
+ dictWord{136, 11, 766},
+ dictWord{10, 0, 287},
+ dictWord{12, 0, 138},
+ dictWord{10, 11, 287},
+ dictWord{140, 11, 138},
+ dictWord{4, 0, 105},
+ dictWord{132, 0, 740},
+ dictWord{140, 10, 116},
+ dictWord{134, 0, 857},
+ dictWord{135, 11, 1841},
+ dictWord{6, 0, 1402},
+ dictWord{137, 0, 819},
+ dictWord{132, 11, 584},
+ dictWord{132, 10, 709},
+ dictWord{
+ 133,
+ 10,
+ 897,
+ },
+ dictWord{5, 0, 224},
+ dictWord{13, 0, 174},
+ dictWord{146, 0, 52},
+ dictWord{135, 10, 1840},
+ dictWord{4, 10, 608},
+ dictWord{133, 10, 497},
+ dictWord{139, 11, 60},
+ dictWord{4, 0, 758},
+ dictWord{135, 0, 1649},
+ dictWord{4, 11, 226},
+ dictWord{4, 11, 326},
+ dictWord{135, 11, 1770},
+ dictWord{5, 11, 426},
+ dictWord{8, 11, 30},
+ dictWord{9, 11, 2},
+ dictWord{11, 11, 549},
+ dictWord{147, 11, 122},
+ dictWord{135, 10, 2039},
+ dictWord{6, 10, 540},
+ dictWord{
+ 136,
+ 10,
+ 136,
+ },
+ dictWord{4, 0, 573},
+ dictWord{8, 0, 655},
+ dictWord{4, 10, 897},
+ dictWord{133, 10, 786},
+ dictWord{7, 0, 351},
+ dictWord{139, 0, 128},
+ dictWord{
+ 133,
+ 10,
+ 999,
+ },
+ dictWord{4, 10, 299},
+ dictWord{135, 10, 1004},
+ dictWord{133, 0, 918},
+ dictWord{132, 11, 345},
+ dictWord{4, 11, 385},
+ dictWord{7, 11, 265},
+ dictWord{135, 11, 587},
+ dictWord{133, 10, 456},
+ dictWord{136, 10, 180},
+ dictWord{6, 0, 687},
+ dictWord{134, 0, 1537},
+ dictWord{4, 11, 347},
+ dictWord{
+ 5,
+ 11,
+ 423,
+ },
+ dictWord{5, 11, 996},
+ dictWord{135, 11, 1329},
+ dictWord{132, 10, 755},
+ dictWord{7, 11, 1259},
+ dictWord{9, 11, 125},
+ dictWord{11, 11, 65},
+ dictWord{140, 11, 285},
+ dictWord{5, 11, 136},
+ dictWord{6, 11, 136},
+ dictWord{136, 11, 644},
+ dictWord{134, 0, 1525},
+ dictWord{4, 0, 1009},
+ dictWord{
+ 135,
+ 0,
+ 1139,
+ },
+ dictWord{139, 10, 338},
+ dictWord{132, 0, 340},
+ dictWord{135, 10, 1464},
+ dictWord{8, 0, 847},
+ dictWord{10, 0, 861},
+ dictWord{10, 0, 876},
+ dictWord{
+ 10,
+ 0,
+ 889,
+ },
+ dictWord{10, 0, 922},
+ dictWord{10, 0, 929},
+ dictWord{10, 0, 933},
+ dictWord{12, 0, 784},
+ dictWord{140, 0, 791},
+ dictWord{139, 0, 176},
+ dictWord{
+ 9,
+ 11,
+ 134,
+ },
+ dictWord{10, 11, 2},
+ dictWord{10, 11, 27},
+ dictWord{10, 11, 333},
+ dictWord{11, 11, 722},
+ dictWord{143, 11, 1},
+ dictWord{4, 11, 433},
+ dictWord{
+ 133,
+ 11,
+ 719,
+ },
+ dictWord{5, 0, 985},
+ dictWord{7, 0, 509},
+ dictWord{7, 0, 529},
+ dictWord{145, 0, 96},
+ dictWord{132, 0, 615},
+ dictWord{4, 10, 890},
+ dictWord{
+ 5,
+ 10,
+ 805,
+ },
+ dictWord{5, 10, 819},
+ dictWord{5, 10, 961},
+ dictWord{6, 10, 396},
+ dictWord{6, 10, 1631},
+ dictWord{6, 10, 1678},
+ dictWord{7, 10, 1967},
+ dictWord{
+ 7,
+ 10,
+ 2041,
+ },
+ dictWord{9, 10, 630},
+ dictWord{11, 10, 8},
+ dictWord{11, 10, 1019},
+ dictWord{12, 10, 176},
+ dictWord{13, 10, 225},
+ dictWord{14, 10, 292},
+ dictWord{
+ 149,
+ 10,
+ 24,
+ },
+ dictWord{135, 0, 1919},
+ dictWord{134, 0, 1131},
+ dictWord{144, 11, 21},
+ dictWord{144, 11, 51},
+ dictWord{135, 10, 1815},
+ dictWord{4, 0, 247},
+ dictWord{7, 10, 1505},
+ dictWord{10, 10, 190},
+ dictWord{10, 10, 634},
+ dictWord{11, 10, 792},
+ dictWord{12, 10, 358},
+ dictWord{140, 10, 447},
+ dictWord{
+ 5,
+ 10,
+ 0,
+ },
+ dictWord{6, 10, 536},
+ dictWord{7, 10, 604},
+ dictWord{13, 10, 445},
+ dictWord{145, 10, 126},
+ dictWord{4, 0, 184},
+ dictWord{5, 0, 390},
+ dictWord{6, 0, 337},
+ dictWord{7, 0, 23},
+ dictWord{7, 0, 494},
+ dictWord{7, 0, 618},
+ dictWord{7, 0, 1456},
+ dictWord{8, 0, 27},
+ dictWord{8, 0, 599},
+ dictWord{10, 0, 153},
+ dictWord{
+ 139,
+ 0,
+ 710,
+ },
+ dictWord{6, 10, 232},
+ dictWord{6, 10, 412},
+ dictWord{7, 10, 1074},
+ dictWord{8, 10, 9},
+ dictWord{8, 10, 157},
+ dictWord{8, 10, 786},
+ dictWord{9, 10, 196},
+ dictWord{9, 10, 352},
+ dictWord{9, 10, 457},
+ dictWord{10, 10, 337},
+ dictWord{11, 10, 232},
+ dictWord{11, 10, 877},
+ dictWord{12, 10, 480},
+ dictWord{
+ 140,
+ 10,
+ 546,
+ },
+ dictWord{13, 0, 38},
+ dictWord{135, 10, 958},
+ dictWord{4, 10, 382},
+ dictWord{136, 10, 579},
+ dictWord{4, 10, 212},
+ dictWord{135, 10, 1206},
+ dictWord{
+ 4,
+ 11,
+ 555,
+ },
+ dictWord{8, 11, 536},
+ dictWord{138, 11, 288},
+ dictWord{11, 11, 139},
+ dictWord{139, 11, 171},
+ dictWord{9, 11, 370},
+ dictWord{138, 11, 90},
+ dictWord{132, 0, 1015},
+ dictWord{134, 0, 1088},
+ dictWord{5, 10, 655},
+ dictWord{135, 11, 977},
+ dictWord{134, 0, 1585},
+ dictWord{17, 10, 67},
+ dictWord{
+ 147,
+ 10,
+ 74,
+ },
+ dictWord{10, 0, 227},
+ dictWord{11, 0, 497},
+ dictWord{11, 0, 709},
+ dictWord{140, 0, 415},
+ dictWord{6, 0, 360},
+ dictWord{7, 0, 1664},
+ dictWord{
+ 136,
+ 0,
+ 478,
+ },
+ dictWord{7, 0, 95},
+ dictWord{6, 10, 231},
+ dictWord{136, 10, 423},
+ dictWord{140, 11, 65},
+ dictWord{4, 11, 257},
+ dictWord{135, 11, 2031},
+ dictWord{
+ 135,
+ 11,
+ 1768,
+ },
+ dictWord{133, 10, 300},
+ dictWord{139, 11, 211},
+ dictWord{136, 0, 699},
+ dictWord{6, 10, 237},
+ dictWord{7, 10, 611},
+ dictWord{8, 10, 100},
+ dictWord{9, 10, 416},
+ dictWord{11, 10, 335},
+ dictWord{12, 10, 173},
+ dictWord{146, 10, 101},
+ dictWord{14, 0, 26},
+ dictWord{146, 0, 150},
+ dictWord{6, 0, 581},
+ dictWord{135, 0, 1119},
+ dictWord{135, 10, 1208},
+ dictWord{132, 0, 739},
+ dictWord{6, 11, 83},
+ dictWord{6, 11, 1733},
+ dictWord{135, 11, 1389},
+ dictWord{
+ 137,
+ 0,
+ 869,
+ },
+ dictWord{4, 0, 67},
+ dictWord{5, 0, 422},
+ dictWord{7, 0, 1037},
+ dictWord{7, 0, 1289},
+ dictWord{7, 0, 1555},
+ dictWord{9, 0, 741},
+ dictWord{145, 0, 108},
+ dictWord{133, 10, 199},
+ dictWord{12, 10, 427},
+ dictWord{146, 10, 38},
+ dictWord{136, 0, 464},
+ dictWord{142, 0, 42},
+ dictWord{10, 0, 96},
+ dictWord{8, 11, 501},
+ dictWord{137, 11, 696},
+ dictWord{134, 11, 592},
+ dictWord{4, 0, 512},
+ dictWord{4, 0, 966},
+ dictWord{5, 0, 342},
+ dictWord{6, 0, 1855},
+ dictWord{8, 0, 869},
+ dictWord{8, 0, 875},
+ dictWord{8, 0, 901},
+ dictWord{144, 0, 26},
+ dictWord{8, 0, 203},
+ dictWord{11, 0, 823},
+ dictWord{11, 0, 846},
+ dictWord{12, 0, 482},
+ dictWord{
+ 13,
+ 0,
+ 277,
+ },
+ dictWord{13, 0, 302},
+ dictWord{13, 0, 464},
+ dictWord{14, 0, 205},
+ dictWord{142, 0, 221},
+ dictWord{4, 0, 449},
+ dictWord{133, 0, 718},
+ dictWord{
+ 7,
+ 11,
+ 1718,
+ },
+ dictWord{9, 11, 95},
+ dictWord{9, 11, 274},
+ dictWord{10, 11, 279},
+ dictWord{10, 11, 317},
+ dictWord{10, 11, 420},
+ dictWord{11, 11, 303},
+ dictWord{
+ 11,
+ 11,
+ 808,
+ },
+ dictWord{12, 11, 134},
+ dictWord{12, 11, 367},
+ dictWord{13, 11, 149},
+ dictWord{13, 11, 347},
+ dictWord{14, 11, 349},
+ dictWord{14, 11, 406},
+ dictWord{18, 11, 22},
+ dictWord{18, 11, 89},
+ dictWord{18, 11, 122},
+ dictWord{147, 11, 47},
+ dictWord{133, 11, 26},
+ dictWord{4, 0, 355},
+ dictWord{6, 0, 311},
+ dictWord{
+ 9,
+ 0,
+ 256,
+ },
+ dictWord{138, 0, 404},
+ dictWord{132, 11, 550},
+ dictWord{10, 0, 758},
+ dictWord{6, 10, 312},
+ dictWord{6, 10, 1715},
+ dictWord{10, 10, 584},
+ dictWord{11, 10, 546},
+ dictWord{11, 10, 692},
+ dictWord{12, 10, 259},
+ dictWord{12, 10, 295},
+ dictWord{13, 10, 46},
+ dictWord{141, 10, 154},
+ dictWord{
+ 136,
+ 11,
+ 822,
+ },
+ dictWord{5, 0, 827},
+ dictWord{4, 11, 902},
+ dictWord{5, 11, 809},
+ dictWord{6, 11, 122},
+ dictWord{135, 11, 896},
+ dictWord{5, 0, 64},
+ dictWord{140, 0, 581},
+ dictWord{4, 0, 442},
+ dictWord{6, 0, 739},
+ dictWord{7, 0, 1047},
+ dictWord{7, 0, 1352},
+ dictWord{7, 0, 1643},
+ dictWord{7, 11, 1911},
+ dictWord{9, 11, 449},
+ dictWord{10, 11, 192},
+ dictWord{138, 11, 740},
+ dictWord{135, 11, 262},
+ dictWord{132, 10, 588},
+ dictWord{133, 11, 620},
+ dictWord{5, 0, 977},
+ dictWord{
+ 6,
+ 0,
+ 288,
+ },
+ dictWord{7, 0, 528},
+ dictWord{4, 11, 34},
+ dictWord{5, 11, 574},
+ dictWord{7, 11, 279},
+ dictWord{7, 11, 1624},
+ dictWord{136, 11, 601},
+ dictWord{
+ 6,
+ 0,
+ 1375,
+ },
+ dictWord{4, 10, 231},
+ dictWord{5, 10, 61},
+ dictWord{6, 10, 104},
+ dictWord{7, 10, 729},
+ dictWord{7, 10, 964},
+ dictWord{7, 10, 1658},
+ dictWord{
+ 140,
+ 10,
+ 414,
+ },
+ dictWord{6, 10, 263},
+ dictWord{138, 10, 757},
+ dictWord{132, 10, 320},
+ dictWord{4, 0, 254},
+ dictWord{7, 0, 1309},
+ dictWord{5, 11, 332},
+ dictWord{
+ 135,
+ 11,
+ 1309,
+ },
+ dictWord{6, 11, 261},
+ dictWord{8, 11, 182},
+ dictWord{139, 11, 943},
+ dictWord{132, 10, 225},
+ dictWord{6, 0, 12},
+ dictWord{135, 0, 1219},
+ dictWord{4, 0, 275},
+ dictWord{12, 0, 376},
+ dictWord{6, 11, 1721},
+ dictWord{141, 11, 490},
+ dictWord{4, 11, 933},
+ dictWord{133, 11, 880},
+ dictWord{6, 0, 951},
+ dictWord{6, 0, 1109},
+ dictWord{6, 0, 1181},
+ dictWord{7, 0, 154},
+ dictWord{4, 10, 405},
+ dictWord{7, 10, 817},
+ dictWord{14, 10, 58},
+ dictWord{17, 10, 37},
+ dictWord{
+ 146,
+ 10,
+ 124,
+ },
+ dictWord{6, 0, 1520},
+ dictWord{133, 10, 974},
+ dictWord{134, 0, 1753},
+ dictWord{6, 0, 369},
+ dictWord{6, 0, 502},
+ dictWord{7, 0, 1036},
+ dictWord{
+ 8,
+ 0,
+ 348,
+ },
+ dictWord{9, 0, 452},
+ dictWord{10, 0, 26},
+ dictWord{11, 0, 224},
+ dictWord{11, 0, 387},
+ dictWord{11, 0, 772},
+ dictWord{12, 0, 95},
+ dictWord{12, 0, 629},
+ dictWord{13, 0, 195},
+ dictWord{13, 0, 207},
+ dictWord{13, 0, 241},
+ dictWord{14, 0, 260},
+ dictWord{14, 0, 270},
+ dictWord{143, 0, 140},
+ dictWord{132, 0, 269},
+ dictWord{5, 0, 480},
+ dictWord{7, 0, 532},
+ dictWord{7, 0, 1197},
+ dictWord{7, 0, 1358},
+ dictWord{8, 0, 291},
+ dictWord{11, 0, 349},
+ dictWord{142, 0, 396},
+ dictWord{
+ 5,
+ 10,
+ 235,
+ },
+ dictWord{7, 10, 1239},
+ dictWord{11, 10, 131},
+ dictWord{140, 10, 370},
+ dictWord{7, 10, 956},
+ dictWord{7, 10, 1157},
+ dictWord{7, 10, 1506},
+ dictWord{
+ 7,
+ 10,
+ 1606,
+ },
+ dictWord{7, 10, 1615},
+ dictWord{7, 10, 1619},
+ dictWord{7, 10, 1736},
+ dictWord{7, 10, 1775},
+ dictWord{8, 10, 590},
+ dictWord{9, 10, 324},
+ dictWord{9, 10, 736},
+ dictWord{9, 10, 774},
+ dictWord{9, 10, 776},
+ dictWord{9, 10, 784},
+ dictWord{10, 10, 567},
+ dictWord{10, 10, 708},
+ dictWord{11, 10, 518},
+ dictWord{11, 10, 613},
+ dictWord{11, 10, 695},
+ dictWord{11, 10, 716},
+ dictWord{11, 10, 739},
+ dictWord{11, 10, 770},
+ dictWord{11, 10, 771},
+ dictWord{
+ 11,
+ 10,
+ 848,
+ },
+ dictWord{11, 10, 857},
+ dictWord{11, 10, 931},
+ dictWord{11, 10, 947},
+ dictWord{12, 10, 326},
+ dictWord{12, 10, 387},
+ dictWord{12, 10, 484},
+ dictWord{
+ 12,
+ 10,
+ 528,
+ },
+ dictWord{12, 10, 552},
+ dictWord{12, 10, 613},
+ dictWord{13, 10, 189},
+ dictWord{13, 10, 256},
+ dictWord{13, 10, 340},
+ dictWord{13, 10, 432},
+ dictWord{13, 10, 436},
+ dictWord{13, 10, 440},
+ dictWord{13, 10, 454},
+ dictWord{14, 10, 174},
+ dictWord{14, 10, 220},
+ dictWord{14, 10, 284},
+ dictWord{
+ 14,
+ 10,
+ 390,
+ },
+ dictWord{145, 10, 121},
+ dictWord{8, 11, 598},
+ dictWord{9, 11, 664},
+ dictWord{138, 11, 441},
+ dictWord{9, 10, 137},
+ dictWord{138, 10, 221},
+ dictWord{133, 11, 812},
+ dictWord{148, 0, 15},
+ dictWord{134, 0, 1341},
+ dictWord{6, 0, 1017},
+ dictWord{4, 11, 137},
+ dictWord{7, 11, 1178},
+ dictWord{
+ 135,
+ 11,
+ 1520,
+ },
+ dictWord{7, 10, 390},
+ dictWord{138, 10, 140},
+ dictWord{7, 11, 1260},
+ dictWord{135, 11, 1790},
+ dictWord{137, 11, 191},
+ dictWord{
+ 135,
+ 10,
+ 1144,
+ },
+ dictWord{6, 0, 1810},
+ dictWord{7, 0, 657},
+ dictWord{8, 0, 886},
+ dictWord{10, 0, 857},
+ dictWord{14, 0, 440},
+ dictWord{144, 0, 96},
+ dictWord{8, 0, 533},
+ dictWord{6, 11, 1661},
+ dictWord{7, 11, 1975},
+ dictWord{7, 11, 2009},
+ dictWord{135, 11, 2011},
+ dictWord{6, 0, 1453},
+ dictWord{134, 10, 464},
+ dictWord{
+ 132,
+ 11,
+ 715,
+ },
+ dictWord{5, 10, 407},
+ dictWord{11, 10, 204},
+ dictWord{11, 10, 243},
+ dictWord{11, 10, 489},
+ dictWord{12, 10, 293},
+ dictWord{19, 10, 37},
+ dictWord{20, 10, 73},
+ dictWord{150, 10, 38},
+ dictWord{133, 11, 703},
+ dictWord{4, 0, 211},
+ dictWord{7, 0, 1483},
+ dictWord{5, 10, 325},
+ dictWord{8, 10, 5},
+ dictWord{
+ 8,
+ 10,
+ 227,
+ },
+ dictWord{9, 10, 105},
+ dictWord{10, 10, 585},
+ dictWord{140, 10, 614},
+ dictWord{4, 0, 332},
+ dictWord{5, 0, 335},
+ dictWord{6, 0, 238},
+ dictWord{
+ 7,
+ 0,
+ 269,
+ },
+ dictWord{7, 0, 811},
+ dictWord{7, 0, 1797},
+ dictWord{8, 0, 836},
+ dictWord{9, 0, 507},
+ dictWord{141, 0, 242},
+ dictWord{5, 11, 89},
+ dictWord{7, 11, 1915},
+ dictWord{9, 11, 185},
+ dictWord{9, 11, 235},
+ dictWord{9, 11, 496},
+ dictWord{10, 11, 64},
+ dictWord{10, 11, 270},
+ dictWord{10, 11, 403},
+ dictWord{10, 11, 469},
+ dictWord{10, 11, 529},
+ dictWord{10, 11, 590},
+ dictWord{11, 11, 140},
+ dictWord{11, 11, 860},
+ dictWord{13, 11, 1},
+ dictWord{13, 11, 422},
+ dictWord{14, 11, 341},
+ dictWord{14, 11, 364},
+ dictWord{17, 11, 93},
+ dictWord{18, 11, 113},
+ dictWord{19, 11, 97},
+ dictWord{147, 11, 113},
+ dictWord{133, 11, 695},
+ dictWord{
+ 16,
+ 0,
+ 19,
+ },
+ dictWord{5, 11, 6},
+ dictWord{6, 11, 183},
+ dictWord{6, 10, 621},
+ dictWord{7, 11, 680},
+ dictWord{7, 11, 978},
+ dictWord{7, 11, 1013},
+ dictWord{7, 11, 1055},
+ dictWord{12, 11, 230},
+ dictWord{13, 11, 172},
+ dictWord{13, 10, 504},
+ dictWord{146, 11, 29},
+ dictWord{136, 0, 156},
+ dictWord{133, 0, 1009},
+ dictWord{
+ 6,
+ 11,
+ 29,
+ },
+ dictWord{139, 11, 63},
+ dictWord{134, 0, 820},
+ dictWord{134, 10, 218},
+ dictWord{7, 10, 454},
+ dictWord{7, 10, 782},
+ dictWord{8, 10, 768},
+ dictWord{
+ 140,
+ 10,
+ 686,
+ },
+ dictWord{5, 0, 228},
+ dictWord{6, 0, 203},
+ dictWord{7, 0, 156},
+ dictWord{8, 0, 347},
+ dictWord{9, 0, 265},
+ dictWord{18, 0, 39},
+ dictWord{20, 0, 54},
+ dictWord{21, 0, 31},
+ dictWord{22, 0, 3},
+ dictWord{23, 0, 0},
+ dictWord{15, 11, 8},
+ dictWord{18, 11, 39},
+ dictWord{20, 11, 54},
+ dictWord{21, 11, 31},
+ dictWord{22, 11, 3},
+ dictWord{151, 11, 0},
+ dictWord{7, 0, 1131},
+ dictWord{135, 0, 1468},
+ dictWord{144, 10, 0},
+ dictWord{134, 0, 1276},
+ dictWord{10, 10, 676},
+ dictWord{
+ 140,
+ 10,
+ 462,
+ },
+ dictWord{132, 11, 311},
+ dictWord{134, 11, 1740},
+ dictWord{7, 11, 170},
+ dictWord{8, 11, 90},
+ dictWord{8, 11, 177},
+ dictWord{8, 11, 415},
+ dictWord{
+ 11,
+ 11,
+ 714,
+ },
+ dictWord{142, 11, 281},
+ dictWord{134, 10, 164},
+ dictWord{6, 0, 1792},
+ dictWord{138, 0, 849},
+ dictWord{150, 10, 50},
+ dictWord{5, 0, 291},
+ dictWord{5, 0, 318},
+ dictWord{7, 0, 765},
+ dictWord{9, 0, 389},
+ dictWord{12, 0, 548},
+ dictWord{8, 11, 522},
+ dictWord{142, 11, 328},
+ dictWord{11, 11, 91},
+ dictWord{
+ 13,
+ 11,
+ 129,
+ },
+ dictWord{15, 11, 101},
+ dictWord{145, 11, 125},
+ dictWord{4, 11, 494},
+ dictWord{6, 11, 74},
+ dictWord{7, 11, 44},
+ dictWord{7, 11, 407},
+ dictWord{
+ 8,
+ 11,
+ 551,
+ },
+ dictWord{12, 11, 17},
+ dictWord{15, 11, 5},
+ dictWord{148, 11, 11},
+ dictWord{4, 11, 276},
+ dictWord{133, 11, 296},
+ dictWord{6, 10, 343},
+ dictWord{
+ 7,
+ 10,
+ 195,
+ },
+ dictWord{7, 11, 1777},
+ dictWord{9, 10, 226},
+ dictWord{10, 10, 197},
+ dictWord{10, 10, 575},
+ dictWord{11, 10, 502},
+ dictWord{139, 10, 899},
+ dictWord{
+ 10,
+ 0,
+ 525,
+ },
+ dictWord{139, 0, 82},
+ dictWord{14, 0, 453},
+ dictWord{4, 11, 7},
+ dictWord{5, 11, 90},
+ dictWord{5, 11, 158},
+ dictWord{6, 11, 542},
+ dictWord{7, 11, 221},
+ dictWord{7, 11, 1574},
+ dictWord{9, 11, 490},
+ dictWord{10, 11, 540},
+ dictWord{11, 11, 443},
+ dictWord{139, 11, 757},
+ dictWord{135, 0, 666},
+ dictWord{
+ 22,
+ 10,
+ 29,
+ },
+ dictWord{150, 11, 29},
+ dictWord{4, 0, 422},
+ dictWord{147, 10, 8},
+ dictWord{5, 0, 355},
+ dictWord{145, 0, 0},
+ dictWord{6, 0, 1873},
+ dictWord{9, 0, 918},
+ dictWord{7, 11, 588},
+ dictWord{9, 11, 175},
+ dictWord{138, 11, 530},
+ dictWord{143, 11, 31},
+ dictWord{11, 0, 165},
+ dictWord{7, 10, 1125},
+ dictWord{9, 10, 143},
+ dictWord{14, 10, 405},
+ dictWord{150, 10, 21},
+ dictWord{9, 0, 260},
+ dictWord{137, 0, 905},
+ dictWord{5, 11, 872},
+ dictWord{6, 11, 57},
+ dictWord{6, 11, 479},
+ dictWord{
+ 6,
+ 11,
+ 562,
+ },
+ dictWord{7, 11, 471},
+ dictWord{7, 11, 1060},
+ dictWord{9, 11, 447},
+ dictWord{9, 11, 454},
+ dictWord{141, 11, 6},
+ dictWord{138, 11, 704},
+ dictWord{133, 0, 865},
+ dictWord{5, 0, 914},
+ dictWord{134, 0, 1625},
+ dictWord{133, 0, 234},
+ dictWord{7, 0, 1383},
+ dictWord{5, 11, 31},
+ dictWord{6, 11, 614},
+ dictWord{145, 11, 61},
+ dictWord{7, 11, 1200},
+ dictWord{138, 11, 460},
+ dictWord{6, 11, 424},
+ dictWord{135, 11, 1866},
+ dictWord{136, 0, 306},
+ dictWord{
+ 5,
+ 10,
+ 959,
+ },
+ dictWord{12, 11, 30},
+ dictWord{13, 11, 148},
+ dictWord{14, 11, 87},
+ dictWord{14, 11, 182},
+ dictWord{16, 11, 42},
+ dictWord{18, 11, 92},
+ dictWord{
+ 148,
+ 11,
+ 70,
+ },
+ dictWord{6, 0, 1919},
+ dictWord{6, 0, 1921},
+ dictWord{9, 0, 923},
+ dictWord{9, 0, 930},
+ dictWord{9, 0, 941},
+ dictWord{9, 0, 949},
+ dictWord{9, 0, 987},
+ dictWord{
+ 9,
+ 0,
+ 988,
+ },
+ dictWord{9, 0, 992},
+ dictWord{12, 0, 802},
+ dictWord{12, 0, 815},
+ dictWord{12, 0, 856},
+ dictWord{12, 0, 885},
+ dictWord{12, 0, 893},
+ dictWord{
+ 12,
+ 0,
+ 898,
+ },
+ dictWord{12, 0, 919},
+ dictWord{12, 0, 920},
+ dictWord{12, 0, 941},
+ dictWord{12, 0, 947},
+ dictWord{15, 0, 183},
+ dictWord{15, 0, 185},
+ dictWord{15, 0, 189},
+ dictWord{15, 0, 197},
+ dictWord{15, 0, 202},
+ dictWord{15, 0, 233},
+ dictWord{18, 0, 218},
+ dictWord{18, 0, 219},
+ dictWord{18, 0, 233},
+ dictWord{143, 11, 156},
+ dictWord{135, 10, 1759},
+ dictWord{136, 10, 173},
+ dictWord{13, 0, 163},
+ dictWord{13, 0, 180},
+ dictWord{18, 0, 78},
+ dictWord{20, 0, 35},
+ dictWord{5, 11, 13},
+ dictWord{134, 11, 142},
+ dictWord{134, 10, 266},
+ dictWord{6, 11, 97},
+ dictWord{7, 11, 116},
+ dictWord{8, 11, 322},
+ dictWord{8, 11, 755},
+ dictWord{9, 11, 548},
+ dictWord{10, 11, 714},
+ dictWord{11, 11, 884},
+ dictWord{141, 11, 324},
+ dictWord{135, 0, 1312},
+ dictWord{9, 0, 814},
+ dictWord{137, 11, 676},
+ dictWord{
+ 133,
+ 0,
+ 707,
+ },
+ dictWord{135, 0, 1493},
+ dictWord{6, 0, 421},
+ dictWord{7, 0, 61},
+ dictWord{7, 0, 1540},
+ dictWord{10, 0, 11},
+ dictWord{138, 0, 501},
+ dictWord{12, 0, 733},
+ dictWord{12, 0, 766},
+ dictWord{7, 11, 866},
+ dictWord{135, 11, 1163},
+ dictWord{137, 0, 341},
+ dictWord{142, 0, 98},
+ dictWord{145, 11, 115},
+ dictWord{
+ 135,
+ 11,
+ 1111,
+ },
+ dictWord{136, 10, 300},
+ dictWord{136, 0, 1014},
+ dictWord{8, 11, 1},
+ dictWord{9, 11, 112},
+ dictWord{138, 11, 326},
+ dictWord{132, 11, 730},
+ dictWord{5, 11, 488},
+ dictWord{6, 11, 527},
+ dictWord{7, 11, 489},
+ dictWord{7, 11, 1636},
+ dictWord{8, 11, 121},
+ dictWord{8, 11, 144},
+ dictWord{8, 11, 359},
+ dictWord{
+ 9,
+ 11,
+ 193,
+ },
+ dictWord{9, 11, 241},
+ dictWord{9, 11, 336},
+ dictWord{9, 11, 882},
+ dictWord{11, 11, 266},
+ dictWord{11, 11, 372},
+ dictWord{11, 11, 944},
+ dictWord{
+ 12,
+ 11,
+ 401,
+ },
+ dictWord{140, 11, 641},
+ dictWord{6, 0, 971},
+ dictWord{134, 0, 1121},
+ dictWord{6, 0, 102},
+ dictWord{7, 0, 72},
+ dictWord{15, 0, 142},
+ dictWord{
+ 147,
+ 0,
+ 67,
+ },
+ dictWord{151, 0, 30},
+ dictWord{135, 0, 823},
+ dictWord{134, 0, 1045},
+ dictWord{5, 10, 427},
+ dictWord{5, 10, 734},
+ dictWord{7, 10, 478},
+ dictWord{
+ 136,
+ 10,
+ 52,
+ },
+ dictWord{7, 0, 1930},
+ dictWord{11, 10, 217},
+ dictWord{142, 10, 165},
+ dictWord{6, 0, 1512},
+ dictWord{135, 0, 1870},
+ dictWord{9, 11, 31},
+ dictWord{
+ 10,
+ 11,
+ 244,
+ },
+ dictWord{10, 11, 699},
+ dictWord{12, 11, 149},
+ dictWord{141, 11, 497},
+ dictWord{133, 11, 377},
+ dictWord{145, 11, 101},
+ dictWord{
+ 10,
+ 11,
+ 158,
+ },
+ dictWord{13, 11, 13},
+ dictWord{13, 11, 137},
+ dictWord{13, 11, 258},
+ dictWord{14, 11, 111},
+ dictWord{14, 11, 225},
+ dictWord{14, 11, 253},
+ dictWord{
+ 14,
+ 11,
+ 304,
+ },
+ dictWord{14, 11, 339},
+ dictWord{14, 11, 417},
+ dictWord{146, 11, 33},
+ dictWord{6, 0, 87},
+ dictWord{6, 10, 1734},
+ dictWord{7, 10, 20},
+ dictWord{
+ 7,
+ 10,
+ 1056,
+ },
+ dictWord{8, 10, 732},
+ dictWord{9, 10, 406},
+ dictWord{9, 10, 911},
+ dictWord{138, 10, 694},
+ dictWord{134, 0, 1243},
+ dictWord{137, 0, 245},
+ dictWord{
+ 7,
+ 0,
+ 68,
+ },
+ dictWord{8, 0, 48},
+ dictWord{8, 0, 88},
+ dictWord{8, 0, 582},
+ dictWord{8, 0, 681},
+ dictWord{9, 0, 373},
+ dictWord{9, 0, 864},
+ dictWord{11, 0, 157},
+ dictWord{
+ 11,
+ 0,
+ 336,
+ },
+ dictWord{11, 0, 843},
+ dictWord{148, 0, 27},
+ dictWord{8, 11, 663},
+ dictWord{144, 11, 8},
+ dictWord{133, 10, 613},
+ dictWord{4, 0, 88},
+ dictWord{
+ 5,
+ 0,
+ 137,
+ },
+ dictWord{5, 0, 174},
+ dictWord{5, 0, 777},
+ dictWord{6, 0, 1664},
+ dictWord{6, 0, 1725},
+ dictWord{7, 0, 77},
+ dictWord{7, 0, 426},
+ dictWord{7, 0, 1317},
+ dictWord{
+ 7,
+ 0,
+ 1355,
+ },
+ dictWord{8, 0, 126},
+ dictWord{8, 0, 563},
+ dictWord{9, 0, 523},
+ dictWord{9, 0, 750},
+ dictWord{10, 0, 310},
+ dictWord{10, 0, 836},
+ dictWord{11, 0, 42},
+ dictWord{11, 0, 318},
+ dictWord{11, 0, 731},
+ dictWord{12, 0, 68},
+ dictWord{12, 0, 92},
+ dictWord{12, 0, 507},
+ dictWord{12, 0, 692},
+ dictWord{13, 0, 81},
+ dictWord{
+ 13,
+ 0,
+ 238,
+ },
+ dictWord{13, 0, 374},
+ dictWord{14, 0, 436},
+ dictWord{18, 0, 138},
+ dictWord{19, 0, 78},
+ dictWord{19, 0, 111},
+ dictWord{20, 0, 55},
+ dictWord{20, 0, 77},
+ dictWord{148, 0, 92},
+ dictWord{141, 0, 418},
+ dictWord{4, 0, 938},
+ dictWord{137, 0, 625},
+ dictWord{138, 0, 351},
+ dictWord{5, 11, 843},
+ dictWord{7, 10, 32},
+ dictWord{
+ 7,
+ 10,
+ 984,
+ },
+ dictWord{8, 10, 85},
+ dictWord{8, 10, 709},
+ dictWord{9, 10, 579},
+ dictWord{9, 10, 847},
+ dictWord{9, 10, 856},
+ dictWord{10, 10, 799},
+ dictWord{
+ 11,
+ 10,
+ 258,
+ },
+ dictWord{11, 10, 1007},
+ dictWord{12, 10, 331},
+ dictWord{12, 10, 615},
+ dictWord{13, 10, 188},
+ dictWord{13, 10, 435},
+ dictWord{14, 10, 8},
+ dictWord{
+ 15,
+ 10,
+ 165,
+ },
+ dictWord{16, 10, 27},
+ dictWord{148, 10, 40},
+ dictWord{6, 0, 1668},
+ dictWord{7, 0, 1499},
+ dictWord{8, 0, 117},
+ dictWord{9, 0, 314},
+ dictWord{
+ 138,
+ 0,
+ 174,
+ },
+ dictWord{135, 0, 707},
+ dictWord{132, 11, 554},
+ dictWord{133, 11, 536},
+ dictWord{5, 0, 403},
+ dictWord{5, 11, 207},
+ dictWord{9, 11, 79},
+ dictWord{
+ 11,
+ 11,
+ 625,
+ },
+ dictWord{145, 11, 7},
+ dictWord{132, 11, 424},
+ dictWord{136, 11, 785},
+ dictWord{4, 10, 167},
+ dictWord{135, 10, 82},
+ dictWord{9, 0, 7},
+ dictWord{
+ 23,
+ 0,
+ 6,
+ },
+ dictWord{9, 11, 7},
+ dictWord{151, 11, 6},
+ dictWord{6, 0, 282},
+ dictWord{5, 10, 62},
+ dictWord{6, 10, 534},
+ dictWord{7, 10, 74},
+ dictWord{7, 10, 678},
+ dictWord{
+ 7,
+ 10,
+ 684,
+ },
+ dictWord{7, 10, 1043},
+ dictWord{7, 10, 1072},
+ dictWord{8, 10, 280},
+ dictWord{8, 10, 541},
+ dictWord{8, 10, 686},
+ dictWord{9, 10, 258},
+ dictWord{
+ 10,
+ 10,
+ 519,
+ },
+ dictWord{11, 10, 252},
+ dictWord{140, 10, 282},
+ dictWord{138, 10, 33},
+ dictWord{132, 10, 359},
+ dictWord{4, 0, 44},
+ dictWord{5, 0, 311},
+ dictWord{
+ 6,
+ 0,
+ 156,
+ },
+ dictWord{7, 0, 639},
+ dictWord{7, 0, 762},
+ dictWord{7, 0, 1827},
+ dictWord{9, 0, 8},
+ dictWord{9, 0, 462},
+ dictWord{148, 0, 83},
+ dictWord{7, 11, 769},
+ dictWord{
+ 9,
+ 11,
+ 18,
+ },
+ dictWord{138, 11, 358},
+ dictWord{4, 0, 346},
+ dictWord{7, 0, 115},
+ dictWord{9, 0, 180},
+ dictWord{9, 0, 456},
+ dictWord{10, 0, 363},
+ dictWord{
+ 4,
+ 11,
+ 896,
+ },
+ dictWord{134, 11, 1777},
+ dictWord{133, 10, 211},
+ dictWord{7, 0, 761},
+ dictWord{7, 0, 1051},
+ dictWord{137, 0, 545},
+ dictWord{6, 10, 145},
+ dictWord{
+ 141,
+ 10,
+ 336,
+ },
+ dictWord{7, 11, 750},
+ dictWord{9, 11, 223},
+ dictWord{11, 11, 27},
+ dictWord{11, 11, 466},
+ dictWord{12, 11, 624},
+ dictWord{14, 11, 265},
+ dictWord{146, 11, 61},
+ dictWord{6, 0, 752},
+ dictWord{6, 0, 768},
+ dictWord{6, 0, 1195},
+ dictWord{6, 0, 1254},
+ dictWord{6, 0, 1619},
+ dictWord{137, 0, 835},
+ dictWord{
+ 6,
+ 0,
+ 1936,
+ },
+ dictWord{8, 0, 930},
+ dictWord{136, 0, 960},
+ dictWord{132, 10, 263},
+ dictWord{132, 11, 249},
+ dictWord{12, 0, 653},
+ dictWord{132, 10, 916},
+ dictWord{4, 11, 603},
+ dictWord{133, 11, 661},
+ dictWord{8, 0, 344},
+ dictWord{4, 11, 11},
+ dictWord{6, 11, 128},
+ dictWord{7, 11, 231},
+ dictWord{7, 11, 1533},
+ dictWord{138, 11, 725},
+ dictWord{134, 0, 1483},
+ dictWord{134, 0, 875},
+ dictWord{6, 0, 185},
+ dictWord{7, 0, 1899},
+ dictWord{9, 0, 875},
+ dictWord{139, 0, 673},
+ dictWord{15, 10, 155},
+ dictWord{144, 10, 79},
+ dictWord{7, 0, 93},
+ dictWord{7, 0, 210},
+ dictWord{7, 0, 1223},
+ dictWord{8, 0, 451},
+ dictWord{8, 0, 460},
+ dictWord{
+ 11,
+ 0,
+ 353,
+ },
+ dictWord{11, 0, 475},
+ dictWord{4, 10, 599},
+ dictWord{6, 10, 1634},
+ dictWord{7, 10, 67},
+ dictWord{7, 10, 691},
+ dictWord{7, 10, 979},
+ dictWord{
+ 7,
+ 10,
+ 1697,
+ },
+ dictWord{8, 10, 207},
+ dictWord{8, 10, 214},
+ dictWord{8, 10, 231},
+ dictWord{8, 10, 294},
+ dictWord{8, 10, 336},
+ dictWord{8, 10, 428},
+ dictWord{
+ 8,
+ 10,
+ 471,
+ },
+ dictWord{8, 10, 622},
+ dictWord{8, 10, 626},
+ dictWord{8, 10, 679},
+ dictWord{8, 10, 759},
+ dictWord{8, 10, 829},
+ dictWord{9, 10, 11},
+ dictWord{9, 10, 246},
+ dictWord{9, 10, 484},
+ dictWord{9, 10, 573},
+ dictWord{9, 10, 706},
+ dictWord{9, 10, 762},
+ dictWord{9, 10, 798},
+ dictWord{9, 10, 855},
+ dictWord{9, 10, 870},
+ dictWord{
+ 9,
+ 10,
+ 912,
+ },
+ dictWord{10, 10, 303},
+ dictWord{10, 10, 335},
+ dictWord{10, 10, 424},
+ dictWord{10, 10, 461},
+ dictWord{10, 10, 543},
+ dictWord{10, 10, 759},
+ dictWord{10, 10, 814},
+ dictWord{11, 10, 59},
+ dictWord{11, 10, 235},
+ dictWord{11, 10, 590},
+ dictWord{11, 10, 929},
+ dictWord{11, 10, 963},
+ dictWord{
+ 11,
+ 10,
+ 987,
+ },
+ dictWord{12, 10, 114},
+ dictWord{12, 10, 182},
+ dictWord{12, 10, 226},
+ dictWord{12, 10, 332},
+ dictWord{12, 10, 439},
+ dictWord{12, 10, 575},
+ dictWord{
+ 12,
+ 10,
+ 598,
+ },
+ dictWord{12, 10, 675},
+ dictWord{13, 10, 8},
+ dictWord{13, 10, 125},
+ dictWord{13, 10, 194},
+ dictWord{13, 10, 287},
+ dictWord{14, 10, 197},
+ dictWord{14, 10, 383},
+ dictWord{15, 10, 53},
+ dictWord{17, 10, 63},
+ dictWord{19, 10, 46},
+ dictWord{19, 10, 98},
+ dictWord{19, 10, 106},
+ dictWord{148, 10, 85},
+ dictWord{132, 11, 476},
+ dictWord{4, 0, 327},
+ dictWord{5, 0, 478},
+ dictWord{7, 0, 1332},
+ dictWord{136, 0, 753},
+ dictWord{5, 0, 1020},
+ dictWord{133, 0, 1022},
+ dictWord{135, 11, 1807},
+ dictWord{4, 0, 103},
+ dictWord{133, 0, 401},
+ dictWord{4, 0, 499},
+ dictWord{135, 0, 1421},
+ dictWord{10, 0, 207},
+ dictWord{13, 0, 164},
+ dictWord{147, 10, 126},
+ dictWord{9, 11, 20},
+ dictWord{10, 11, 324},
+ dictWord{139, 11, 488},
+ dictWord{132, 0, 96},
+ dictWord{9, 11, 280},
+ dictWord{
+ 138,
+ 11,
+ 134,
+ },
+ dictWord{135, 0, 968},
+ dictWord{133, 10, 187},
+ dictWord{135, 10, 1286},
+ dictWord{5, 11, 112},
+ dictWord{6, 11, 103},
+ dictWord{134, 11, 150},
+ dictWord{8, 0, 914},
+ dictWord{10, 0, 3},
+ dictWord{4, 10, 215},
+ dictWord{9, 10, 38},
+ dictWord{11, 10, 23},
+ dictWord{11, 10, 127},
+ dictWord{139, 10, 796},
+ dictWord{
+ 135,
+ 0,
+ 399,
+ },
+ dictWord{6, 0, 563},
+ dictWord{137, 0, 224},
+ dictWord{6, 0, 704},
+ dictWord{134, 0, 1214},
+ dictWord{4, 11, 708},
+ dictWord{8, 11, 15},
+ dictWord{
+ 9,
+ 11,
+ 50,
+ },
+ dictWord{9, 11, 386},
+ dictWord{11, 11, 18},
+ dictWord{11, 11, 529},
+ dictWord{140, 11, 228},
+ dictWord{4, 11, 563},
+ dictWord{7, 11, 109},
+ dictWord{
+ 7,
+ 11,
+ 592,
+ },
+ dictWord{7, 11, 637},
+ dictWord{7, 11, 770},
+ dictWord{7, 11, 1701},
+ dictWord{8, 11, 436},
+ dictWord{8, 11, 463},
+ dictWord{9, 11, 60},
+ dictWord{9, 11, 335},
+ dictWord{9, 11, 904},
+ dictWord{10, 11, 73},
+ dictWord{11, 11, 434},
+ dictWord{12, 11, 585},
+ dictWord{13, 11, 331},
+ dictWord{18, 11, 110},
+ dictWord{
+ 148,
+ 11,
+ 60,
+ },
+ dictWord{134, 0, 1559},
+ dictWord{132, 11, 502},
+ dictWord{6, 11, 347},
+ dictWord{138, 11, 161},
+ dictWord{4, 11, 33},
+ dictWord{5, 11, 102},
+ dictWord{
+ 5,
+ 11,
+ 500,
+ },
+ dictWord{6, 11, 284},
+ dictWord{7, 11, 1079},
+ dictWord{7, 11, 1423},
+ dictWord{7, 11, 1702},
+ dictWord{8, 11, 470},
+ dictWord{9, 11, 554},
+ dictWord{
+ 9,
+ 11,
+ 723,
+ },
+ dictWord{139, 11, 333},
+ dictWord{7, 11, 246},
+ dictWord{135, 11, 840},
+ dictWord{6, 11, 10},
+ dictWord{8, 11, 571},
+ dictWord{9, 11, 739},
+ dictWord{
+ 143,
+ 11,
+ 91,
+ },
+ dictWord{8, 0, 861},
+ dictWord{10, 0, 905},
+ dictWord{12, 0, 730},
+ dictWord{12, 0, 789},
+ dictWord{133, 11, 626},
+ dictWord{134, 0, 946},
+ dictWord{
+ 5,
+ 0,
+ 746,
+ },
+ dictWord{12, 0, 333},
+ dictWord{14, 0, 332},
+ dictWord{12, 11, 333},
+ dictWord{142, 11, 332},
+ dictWord{5, 11, 18},
+ dictWord{6, 11, 526},
+ dictWord{
+ 13,
+ 11,
+ 24,
+ },
+ dictWord{13, 11, 110},
+ dictWord{19, 11, 5},
+ dictWord{147, 11, 44},
+ dictWord{4, 0, 910},
+ dictWord{5, 0, 832},
+ dictWord{135, 10, 2002},
+ dictWord{
+ 10,
+ 11,
+ 768,
+ },
+ dictWord{139, 11, 787},
+ dictWord{4, 11, 309},
+ dictWord{5, 11, 462},
+ dictWord{7, 11, 970},
+ dictWord{135, 11, 1097},
+ dictWord{4, 10, 28},
+ dictWord{
+ 5,
+ 10,
+ 440,
+ },
+ dictWord{7, 10, 248},
+ dictWord{11, 10, 833},
+ dictWord{140, 10, 344},
+ dictWord{134, 10, 1654},
+ dictWord{6, 0, 632},
+ dictWord{6, 0, 652},
+ dictWord{
+ 6,
+ 0,
+ 1272,
+ },
+ dictWord{6, 0, 1384},
+ dictWord{134, 0, 1560},
+ dictWord{134, 11, 1704},
+ dictWord{6, 0, 1393},
+ dictWord{133, 10, 853},
+ dictWord{6, 10, 249},
+ dictWord{7, 10, 1234},
+ dictWord{139, 10, 573},
+ dictWord{5, 11, 86},
+ dictWord{7, 11, 743},
+ dictWord{9, 11, 85},
+ dictWord{10, 11, 281},
+ dictWord{10, 11, 432},
+ dictWord{11, 11, 490},
+ dictWord{12, 11, 251},
+ dictWord{13, 11, 118},
+ dictWord{14, 11, 378},
+ dictWord{146, 11, 143},
+ dictWord{5, 11, 524},
+ dictWord{
+ 133,
+ 11,
+ 744,
+ },
+ dictWord{134, 0, 1514},
+ dictWord{10, 0, 201},
+ dictWord{142, 0, 319},
+ dictWord{7, 0, 717},
+ dictWord{10, 0, 510},
+ dictWord{7, 10, 392},
+ dictWord{
+ 8,
+ 10,
+ 20,
+ },
+ dictWord{8, 10, 172},
+ dictWord{8, 10, 690},
+ dictWord{9, 10, 383},
+ dictWord{9, 10, 845},
+ dictWord{11, 10, 293},
+ dictWord{11, 10, 832},
+ dictWord{
+ 11,
+ 10,
+ 920,
+ },
+ dictWord{11, 10, 984},
+ dictWord{141, 10, 221},
+ dictWord{134, 0, 1381},
+ dictWord{5, 10, 858},
+ dictWord{133, 10, 992},
+ dictWord{8, 0, 528},
+ dictWord{137, 0, 348},
+ dictWord{10, 11, 107},
+ dictWord{140, 11, 436},
+ dictWord{4, 0, 20},
+ dictWord{133, 0, 616},
+ dictWord{134, 0, 1251},
+ dictWord{
+ 132,
+ 11,
+ 927,
+ },
+ dictWord{10, 11, 123},
+ dictWord{12, 11, 670},
+ dictWord{13, 11, 371},
+ dictWord{14, 11, 142},
+ dictWord{146, 11, 94},
+ dictWord{134, 0, 1163},
+ dictWord{
+ 7,
+ 11,
+ 1149,
+ },
+ dictWord{137, 11, 156},
+ dictWord{134, 0, 307},
+ dictWord{133, 11, 778},
+ dictWord{7, 0, 1091},
+ dictWord{135, 0, 1765},
+ dictWord{
+ 5,
+ 11,
+ 502,
+ },
+ dictWord{6, 10, 268},
+ dictWord{137, 10, 62},
+ dictWord{8, 11, 196},
+ dictWord{10, 11, 283},
+ dictWord{139, 11, 406},
+ dictWord{4, 0, 26},
+ dictWord{
+ 5,
+ 0,
+ 429,
+ },
+ dictWord{6, 0, 245},
+ dictWord{7, 0, 704},
+ dictWord{7, 0, 1379},
+ dictWord{135, 0, 1474},
+ dictWord{133, 11, 855},
+ dictWord{132, 0, 881},
+ dictWord{
+ 4,
+ 0,
+ 621,
+ },
+ dictWord{135, 11, 1596},
+ dictWord{7, 11, 1400},
+ dictWord{9, 11, 446},
+ dictWord{138, 11, 45},
+ dictWord{6, 0, 736},
+ dictWord{138, 10, 106},
+ dictWord{133, 0, 542},
+ dictWord{134, 0, 348},
+ dictWord{133, 0, 868},
+ dictWord{136, 0, 433},
+ dictWord{135, 0, 1495},
+ dictWord{138, 0, 771},
+ dictWord{
+ 6,
+ 10,
+ 613,
+ },
+ dictWord{136, 10, 223},
+ dictWord{138, 0, 215},
+ dictWord{141, 0, 124},
+ dictWord{136, 11, 391},
+ dictWord{135, 11, 172},
+ dictWord{132, 10, 670},
+ dictWord{140, 0, 55},
+ dictWord{9, 10, 40},
+ dictWord{139, 10, 136},
+ dictWord{7, 0, 62},
+ dictWord{147, 0, 112},
+ dictWord{132, 0, 856},
+ dictWord{132, 11, 568},
+ dictWord{12, 0, 270},
+ dictWord{139, 10, 259},
+ dictWord{8, 0, 572},
+ dictWord{137, 0, 698},
+ dictWord{4, 11, 732},
+ dictWord{9, 10, 310},
+ dictWord{137, 10, 682},
+ dictWord{142, 10, 296},
+ dictWord{134, 0, 939},
+ dictWord{136, 11, 733},
+ dictWord{135, 11, 1435},
+ dictWord{7, 10, 1401},
+ dictWord{135, 10, 1476},
+ dictWord{6, 0, 352},
+ dictWord{4, 10, 296},
+ dictWord{7, 10, 401},
+ dictWord{7, 10, 1410},
+ dictWord{7, 10, 1594},
+ dictWord{7, 10, 1674},
+ dictWord{8, 10, 63},
+ dictWord{
+ 8,
+ 10,
+ 660,
+ },
+ dictWord{137, 10, 74},
+ dictWord{4, 11, 428},
+ dictWord{133, 11, 668},
+ dictWord{4, 10, 139},
+ dictWord{4, 10, 388},
+ dictWord{140, 10, 188},
+ dictWord{7, 11, 2015},
+ dictWord{140, 11, 665},
+ dictWord{132, 0, 647},
+ dictWord{146, 0, 10},
+ dictWord{138, 0, 220},
+ dictWord{142, 0, 464},
+ dictWord{
+ 132,
+ 0,
+ 109,
+ },
+ dictWord{134, 0, 1746},
+ dictWord{6, 0, 515},
+ dictWord{4, 10, 747},
+ dictWord{6, 11, 1623},
+ dictWord{6, 11, 1681},
+ dictWord{7, 10, 649},
+ dictWord{
+ 7,
+ 10,
+ 1479,
+ },
+ dictWord{135, 10, 1583},
+ dictWord{133, 10, 232},
+ dictWord{135, 0, 566},
+ dictWord{137, 10, 887},
+ dictWord{4, 0, 40},
+ dictWord{10, 0, 67},
+ dictWord{
+ 11,
+ 0,
+ 117,
+ },
+ dictWord{11, 0, 768},
+ dictWord{139, 0, 935},
+ dictWord{132, 0, 801},
+ dictWord{7, 0, 992},
+ dictWord{8, 0, 301},
+ dictWord{9, 0, 722},
+ dictWord{
+ 12,
+ 0,
+ 63,
+ },
+ dictWord{13, 0, 29},
+ dictWord{14, 0, 161},
+ dictWord{143, 0, 18},
+ dictWord{139, 0, 923},
+ dictWord{6, 11, 1748},
+ dictWord{8, 11, 715},
+ dictWord{9, 11, 802},
+ dictWord{10, 11, 46},
+ dictWord{10, 11, 819},
+ dictWord{13, 11, 308},
+ dictWord{14, 11, 351},
+ dictWord{14, 11, 363},
+ dictWord{146, 11, 67},
+ dictWord{
+ 137,
+ 11,
+ 745,
+ },
+ dictWord{7, 0, 1145},
+ dictWord{4, 10, 14},
+ dictWord{7, 10, 1801},
+ dictWord{10, 10, 748},
+ dictWord{141, 10, 458},
+ dictWord{4, 11, 63},
+ dictWord{
+ 5,
+ 11,
+ 347,
+ },
+ dictWord{134, 11, 474},
+ dictWord{135, 0, 568},
+ dictWord{4, 10, 425},
+ dictWord{7, 11, 577},
+ dictWord{7, 11, 1432},
+ dictWord{9, 11, 475},
+ dictWord{
+ 9,
+ 11,
+ 505,
+ },
+ dictWord{9, 11, 526},
+ dictWord{9, 11, 609},
+ dictWord{9, 11, 689},
+ dictWord{9, 11, 726},
+ dictWord{9, 11, 735},
+ dictWord{9, 11, 738},
+ dictWord{
+ 10,
+ 11,
+ 556,
+ },
+ dictWord{10, 11, 674},
+ dictWord{10, 11, 684},
+ dictWord{11, 11, 89},
+ dictWord{11, 11, 202},
+ dictWord{11, 11, 272},
+ dictWord{11, 11, 380},
+ dictWord{
+ 11,
+ 11,
+ 415,
+ },
+ dictWord{11, 11, 505},
+ dictWord{11, 11, 537},
+ dictWord{11, 11, 550},
+ dictWord{11, 11, 562},
+ dictWord{11, 11, 640},
+ dictWord{11, 11, 667},
+ dictWord{11, 11, 688},
+ dictWord{11, 11, 847},
+ dictWord{11, 11, 927},
+ dictWord{11, 11, 930},
+ dictWord{11, 11, 940},
+ dictWord{12, 11, 144},
+ dictWord{
+ 12,
+ 11,
+ 325,
+ },
+ dictWord{12, 11, 329},
+ dictWord{12, 11, 389},
+ dictWord{12, 11, 403},
+ dictWord{12, 11, 451},
+ dictWord{12, 11, 515},
+ dictWord{12, 11, 604},
+ dictWord{
+ 12,
+ 11,
+ 616,
+ },
+ dictWord{12, 11, 626},
+ dictWord{13, 11, 66},
+ dictWord{13, 11, 131},
+ dictWord{13, 11, 167},
+ dictWord{13, 11, 236},
+ dictWord{13, 11, 368},
+ dictWord{13, 11, 411},
+ dictWord{13, 11, 434},
+ dictWord{13, 11, 453},
+ dictWord{13, 11, 461},
+ dictWord{13, 11, 474},
+ dictWord{14, 11, 59},
+ dictWord{14, 11, 60},
+ dictWord{14, 11, 139},
+ dictWord{14, 11, 152},
+ dictWord{14, 11, 276},
+ dictWord{14, 11, 353},
+ dictWord{14, 11, 402},
+ dictWord{15, 11, 28},
+ dictWord{
+ 15,
+ 11,
+ 81,
+ },
+ dictWord{15, 11, 123},
+ dictWord{15, 11, 152},
+ dictWord{18, 11, 136},
+ dictWord{148, 11, 88},
+ dictWord{137, 0, 247},
+ dictWord{135, 11, 1622},
+ dictWord{
+ 9,
+ 11,
+ 544,
+ },
+ dictWord{11, 11, 413},
+ dictWord{144, 11, 25},
+ dictWord{4, 0, 645},
+ dictWord{7, 0, 825},
+ dictWord{6, 10, 1768},
+ dictWord{135, 11, 89},
+ dictWord{140, 0, 328},
+ dictWord{5, 10, 943},
+ dictWord{134, 10, 1779},
+ dictWord{134, 0, 1363},
+ dictWord{5, 10, 245},
+ dictWord{6, 10, 576},
+ dictWord{7, 10, 582},
+ dictWord{136, 10, 225},
+ dictWord{134, 0, 1280},
+ dictWord{5, 11, 824},
+ dictWord{133, 11, 941},
+ dictWord{7, 11, 440},
+ dictWord{8, 11, 230},
+ dictWord{
+ 139,
+ 11,
+ 106,
+ },
+ dictWord{5, 0, 28},
+ dictWord{6, 0, 204},
+ dictWord{10, 0, 320},
+ dictWord{10, 0, 583},
+ dictWord{13, 0, 502},
+ dictWord{14, 0, 72},
+ dictWord{14, 0, 274},
+ dictWord{14, 0, 312},
+ dictWord{14, 0, 344},
+ dictWord{15, 0, 159},
+ dictWord{16, 0, 62},
+ dictWord{16, 0, 69},
+ dictWord{17, 0, 30},
+ dictWord{18, 0, 42},
+ dictWord{
+ 18,
+ 0,
+ 53,
+ },
+ dictWord{18, 0, 84},
+ dictWord{18, 0, 140},
+ dictWord{19, 0, 68},
+ dictWord{19, 0, 85},
+ dictWord{20, 0, 5},
+ dictWord{20, 0, 45},
+ dictWord{20, 0, 101},
+ dictWord{
+ 22,
+ 0,
+ 7,
+ },
+ dictWord{150, 0, 20},
+ dictWord{4, 0, 558},
+ dictWord{6, 0, 390},
+ dictWord{7, 0, 162},
+ dictWord{7, 0, 689},
+ dictWord{9, 0, 360},
+ dictWord{138, 0, 653},
+ dictWord{134, 0, 764},
+ dictWord{6, 0, 862},
+ dictWord{137, 0, 833},
+ dictWord{5, 0, 856},
+ dictWord{6, 0, 1672},
+ dictWord{6, 0, 1757},
+ dictWord{134, 0, 1781},
+ dictWord{
+ 5,
+ 0,
+ 92,
+ },
+ dictWord{10, 0, 736},
+ dictWord{140, 0, 102},
+ dictWord{6, 0, 1927},
+ dictWord{6, 0, 1944},
+ dictWord{8, 0, 924},
+ dictWord{8, 0, 948},
+ dictWord{
+ 10,
+ 0,
+ 967,
+ },
+ dictWord{138, 0, 978},
+ dictWord{134, 0, 1479},
+ dictWord{5, 0, 590},
+ dictWord{8, 0, 360},
+ dictWord{9, 0, 213},
+ dictWord{138, 0, 63},
+ dictWord{
+ 134,
+ 0,
+ 1521,
+ },
+ dictWord{6, 0, 709},
+ dictWord{134, 0, 891},
+ dictWord{132, 10, 443},
+ dictWord{13, 0, 477},
+ dictWord{14, 0, 120},
+ dictWord{148, 0, 61},
+ dictWord{
+ 4,
+ 11,
+ 914,
+ },
+ dictWord{5, 11, 800},
+ dictWord{133, 11, 852},
+ dictWord{10, 11, 54},
+ dictWord{141, 11, 115},
+ dictWord{4, 11, 918},
+ dictWord{133, 11, 876},
+ dictWord{139, 11, 152},
+ dictWord{4, 11, 92},
+ dictWord{133, 11, 274},
+ dictWord{135, 11, 1901},
+ dictWord{9, 11, 800},
+ dictWord{10, 11, 693},
+ dictWord{
+ 11,
+ 11,
+ 482,
+ },
+ dictWord{11, 11, 734},
+ dictWord{139, 11, 789},
+ dictWord{9, 0, 483},
+ dictWord{132, 10, 298},
+ dictWord{6, 0, 1213},
+ dictWord{141, 11, 498},
+ dictWord{135, 11, 1451},
+ dictWord{133, 11, 743},
+ dictWord{4, 0, 1022},
+ dictWord{10, 0, 1000},
+ dictWord{12, 0, 957},
+ dictWord{12, 0, 980},
+ dictWord{
+ 12,
+ 0,
+ 1013,
+ },
+ dictWord{14, 0, 481},
+ dictWord{144, 0, 116},
+ dictWord{8, 0, 503},
+ dictWord{17, 0, 29},
+ dictWord{4, 11, 49},
+ dictWord{7, 11, 280},
+ dictWord{
+ 135,
+ 11,
+ 1633,
+ },
+ dictWord{135, 0, 1712},
+ dictWord{134, 0, 466},
+ dictWord{136, 11, 47},
+ dictWord{5, 10, 164},
+ dictWord{7, 10, 121},
+ dictWord{142, 10, 189},
+ dictWord{
+ 7,
+ 10,
+ 812,
+ },
+ dictWord{7, 10, 1261},
+ dictWord{7, 10, 1360},
+ dictWord{9, 10, 632},
+ dictWord{140, 10, 352},
+ dictWord{139, 10, 556},
+ dictWord{132, 0, 731},
+ dictWord{5, 11, 272},
+ dictWord{5, 11, 908},
+ dictWord{5, 11, 942},
+ dictWord{7, 11, 1008},
+ dictWord{7, 11, 1560},
+ dictWord{8, 11, 197},
+ dictWord{9, 11, 47},
+ dictWord{11, 11, 538},
+ dictWord{139, 11, 742},
+ dictWord{4, 10, 172},
+ dictWord{9, 10, 611},
+ dictWord{10, 10, 436},
+ dictWord{12, 10, 673},
+ dictWord{
+ 141,
+ 10,
+ 255,
+ },
+ dictWord{133, 10, 844},
+ dictWord{10, 0, 484},
+ dictWord{11, 0, 754},
+ dictWord{12, 0, 457},
+ dictWord{14, 0, 171},
+ dictWord{14, 0, 389},
+ dictWord{
+ 146,
+ 0,
+ 153,
+ },
+ dictWord{9, 10, 263},
+ dictWord{10, 10, 147},
+ dictWord{138, 10, 492},
+ dictWord{137, 11, 891},
+ dictWord{138, 0, 241},
+ dictWord{133, 10, 537},
+ dictWord{6, 0, 2005},
+ dictWord{136, 0, 964},
+ dictWord{137, 10, 842},
+ dictWord{151, 11, 8},
+ dictWord{4, 11, 407},
+ dictWord{132, 11, 560},
+ dictWord{
+ 135,
+ 11,
+ 1884,
+ },
+ dictWord{6, 0, 1100},
+ dictWord{134, 0, 1242},
+ dictWord{135, 0, 954},
+ dictWord{5, 10, 230},
+ dictWord{5, 10, 392},
+ dictWord{6, 10, 420},
+ dictWord{
+ 9,
+ 10,
+ 568,
+ },
+ dictWord{140, 10, 612},
+ dictWord{4, 11, 475},
+ dictWord{11, 11, 35},
+ dictWord{11, 11, 90},
+ dictWord{13, 11, 7},
+ dictWord{13, 11, 71},
+ dictWord{
+ 13,
+ 11,
+ 177,
+ },
+ dictWord{142, 11, 422},
+ dictWord{136, 11, 332},
+ dictWord{135, 0, 1958},
+ dictWord{6, 0, 549},
+ dictWord{8, 0, 34},
+ dictWord{8, 0, 283},
+ dictWord{
+ 9,
+ 0,
+ 165,
+ },
+ dictWord{138, 0, 475},
+ dictWord{10, 0, 952},
+ dictWord{12, 0, 966},
+ dictWord{140, 0, 994},
+ dictWord{5, 0, 652},
+ dictWord{5, 0, 701},
+ dictWord{
+ 135,
+ 0,
+ 449,
+ },
+ dictWord{4, 0, 655},
+ dictWord{7, 0, 850},
+ dictWord{17, 0, 75},
+ dictWord{146, 0, 137},
+ dictWord{4, 0, 146},
+ dictWord{7, 0, 1618},
+ dictWord{8, 0, 670},
+ dictWord{
+ 5,
+ 10,
+ 41,
+ },
+ dictWord{7, 10, 1459},
+ dictWord{7, 10, 1469},
+ dictWord{7, 10, 1859},
+ dictWord{9, 10, 549},
+ dictWord{139, 10, 905},
+ dictWord{133, 10, 696},
+ dictWord{6, 0, 159},
+ dictWord{6, 0, 364},
+ dictWord{7, 0, 516},
+ dictWord{137, 0, 518},
+ dictWord{135, 0, 1439},
+ dictWord{6, 11, 222},
+ dictWord{7, 11, 636},
+ dictWord{
+ 7,
+ 11,
+ 1620,
+ },
+ dictWord{8, 11, 409},
+ dictWord{9, 11, 693},
+ dictWord{139, 11, 77},
+ dictWord{13, 0, 151},
+ dictWord{141, 11, 45},
+ dictWord{6, 0, 1027},
+ dictWord{
+ 4,
+ 11,
+ 336,
+ },
+ dictWord{132, 10, 771},
+ dictWord{139, 11, 392},
+ dictWord{10, 11, 121},
+ dictWord{11, 11, 175},
+ dictWord{149, 11, 16},
+ dictWord{8, 0, 950},
+ dictWord{138, 0, 983},
+ dictWord{133, 10, 921},
+ dictWord{135, 0, 993},
+ dictWord{6, 10, 180},
+ dictWord{7, 10, 1137},
+ dictWord{8, 10, 751},
+ dictWord{
+ 139,
+ 10,
+ 805,
+ },
+ dictWord{7, 0, 501},
+ dictWord{9, 0, 111},
+ dictWord{10, 0, 141},
+ dictWord{11, 0, 332},
+ dictWord{13, 0, 43},
+ dictWord{13, 0, 429},
+ dictWord{14, 0, 130},
+ dictWord{14, 0, 415},
+ dictWord{145, 0, 102},
+ dictWord{4, 10, 183},
+ dictWord{5, 11, 882},
+ dictWord{7, 10, 271},
+ dictWord{11, 10, 824},
+ dictWord{11, 10, 952},
+ dictWord{13, 10, 278},
+ dictWord{13, 10, 339},
+ dictWord{13, 10, 482},
+ dictWord{14, 10, 424},
+ dictWord{148, 10, 99},
+ dictWord{4, 10, 19},
+ dictWord{5, 10, 477},
+ dictWord{5, 10, 596},
+ dictWord{6, 10, 505},
+ dictWord{7, 10, 1221},
+ dictWord{11, 10, 907},
+ dictWord{12, 10, 209},
+ dictWord{141, 10, 214},
+ dictWord{
+ 135,
+ 10,
+ 1215,
+ },
+ dictWord{133, 0, 452},
+ dictWord{132, 11, 426},
+ dictWord{5, 0, 149},
+ dictWord{136, 0, 233},
+ dictWord{133, 0, 935},
+ dictWord{6, 11, 58},
+ dictWord{
+ 7,
+ 11,
+ 654,
+ },
+ dictWord{7, 11, 745},
+ dictWord{7, 11, 1969},
+ dictWord{8, 11, 240},
+ dictWord{8, 11, 675},
+ dictWord{9, 11, 479},
+ dictWord{9, 11, 731},
+ dictWord{
+ 10,
+ 11,
+ 330,
+ },
+ dictWord{10, 11, 593},
+ dictWord{10, 11, 817},
+ dictWord{11, 11, 32},
+ dictWord{11, 11, 133},
+ dictWord{11, 11, 221},
+ dictWord{145, 11, 68},
+ dictWord{
+ 12,
+ 0,
+ 582,
+ },
+ dictWord{18, 0, 131},
+ dictWord{7, 11, 102},
+ dictWord{137, 11, 538},
+ dictWord{136, 0, 801},
+ dictWord{134, 10, 1645},
+ dictWord{132, 0, 70},
+ dictWord{6, 10, 92},
+ dictWord{6, 10, 188},
+ dictWord{7, 10, 1269},
+ dictWord{7, 10, 1524},
+ dictWord{7, 10, 1876},
+ dictWord{10, 10, 228},
+ dictWord{139, 10, 1020},
+ dictWord{4, 10, 459},
+ dictWord{133, 10, 966},
+ dictWord{138, 0, 369},
+ dictWord{16, 0, 36},
+ dictWord{140, 10, 330},
+ dictWord{141, 11, 366},
+ dictWord{
+ 7,
+ 0,
+ 721,
+ },
+ dictWord{10, 0, 236},
+ dictWord{12, 0, 204},
+ dictWord{6, 10, 18},
+ dictWord{7, 10, 932},
+ dictWord{8, 10, 757},
+ dictWord{9, 10, 54},
+ dictWord{9, 10, 65},
+ dictWord{9, 10, 844},
+ dictWord{10, 10, 113},
+ dictWord{10, 10, 315},
+ dictWord{10, 10, 798},
+ dictWord{11, 10, 153},
+ dictWord{12, 10, 151},
+ dictWord{12, 10, 392},
+ dictWord{12, 10, 666},
+ dictWord{142, 10, 248},
+ dictWord{7, 0, 241},
+ dictWord{10, 0, 430},
+ dictWord{8, 10, 548},
+ dictWord{9, 10, 532},
+ dictWord{10, 10, 117},
+ dictWord{11, 10, 351},
+ dictWord{11, 10, 375},
+ dictWord{143, 10, 23},
+ dictWord{134, 10, 1742},
+ dictWord{133, 10, 965},
+ dictWord{133, 11, 566},
+ dictWord{
+ 6,
+ 11,
+ 48,
+ },
+ dictWord{135, 11, 63},
+ dictWord{134, 10, 182},
+ dictWord{10, 10, 65},
+ dictWord{10, 10, 488},
+ dictWord{138, 10, 497},
+ dictWord{6, 11, 114},
+ dictWord{7, 11, 1224},
+ dictWord{7, 11, 1556},
+ dictWord{136, 11, 3},
+ dictWord{134, 0, 1817},
+ dictWord{8, 11, 576},
+ dictWord{137, 11, 267},
+ dictWord{
+ 6,
+ 0,
+ 1078,
+ },
+ dictWord{144, 0, 16},
+ dictWord{9, 10, 588},
+ dictWord{138, 10, 260},
+ dictWord{138, 0, 1021},
+ dictWord{5, 0, 406},
+ dictWord{134, 0, 2022},
+ dictWord{133, 11, 933},
+ dictWord{6, 0, 69},
+ dictWord{135, 0, 117},
+ dictWord{7, 0, 1830},
+ dictWord{136, 11, 427},
+ dictWord{4, 0, 432},
+ dictWord{135, 0, 824},
+ dictWord{134, 10, 1786},
+ dictWord{133, 0, 826},
+ dictWord{139, 11, 67},
+ dictWord{133, 11, 759},
+ dictWord{135, 10, 308},
+ dictWord{137, 0, 816},
+ dictWord{
+ 133,
+ 0,
+ 1000,
+ },
+ dictWord{4, 0, 297},
+ dictWord{6, 0, 529},
+ dictWord{7, 0, 152},
+ dictWord{7, 0, 713},
+ dictWord{7, 0, 1845},
+ dictWord{8, 0, 710},
+ dictWord{8, 0, 717},
+ dictWord{12, 0, 639},
+ dictWord{140, 0, 685},
+ dictWord{7, 0, 423},
+ dictWord{136, 10, 588},
+ dictWord{136, 10, 287},
+ dictWord{136, 0, 510},
+ dictWord{
+ 134,
+ 0,
+ 1048,
+ },
+ dictWord{6, 0, 618},
+ dictWord{7, 11, 56},
+ dictWord{7, 11, 1989},
+ dictWord{8, 11, 337},
+ dictWord{8, 11, 738},
+ dictWord{9, 11, 600},
+ dictWord{
+ 10,
+ 11,
+ 483,
+ },
+ dictWord{12, 11, 37},
+ dictWord{13, 11, 447},
+ dictWord{142, 11, 92},
+ dictWord{4, 0, 520},
+ dictWord{135, 0, 575},
+ dictWord{8, 0, 990},
+ dictWord{
+ 138,
+ 0,
+ 977,
+ },
+ dictWord{135, 11, 774},
+ dictWord{9, 11, 347},
+ dictWord{11, 11, 24},
+ dictWord{140, 11, 170},
+ dictWord{136, 11, 379},
+ dictWord{140, 10, 290},
+ dictWord{132, 11, 328},
+ dictWord{4, 0, 321},
+ dictWord{134, 0, 569},
+ dictWord{4, 11, 101},
+ dictWord{135, 11, 1171},
+ dictWord{7, 0, 723},
+ dictWord{7, 0, 1135},
+ dictWord{5, 11, 833},
+ dictWord{136, 11, 744},
+ dictWord{7, 10, 719},
+ dictWord{8, 10, 809},
+ dictWord{136, 10, 834},
+ dictWord{8, 0, 921},
+ dictWord{136, 10, 796},
+ dictWord{5, 10, 210},
+ dictWord{6, 10, 213},
+ dictWord{7, 10, 60},
+ dictWord{10, 10, 364},
+ dictWord{139, 10, 135},
+ dictWord{5, 0, 397},
+ dictWord{6, 0, 154},
+ dictWord{7, 0, 676},
+ dictWord{8, 0, 443},
+ dictWord{8, 0, 609},
+ dictWord{9, 0, 24},
+ dictWord{9, 0, 325},
+ dictWord{10, 0, 35},
+ dictWord{11, 0, 535},
+ dictWord{11, 0, 672},
+ dictWord{11, 0, 1018},
+ dictWord{12, 0, 637},
+ dictWord{16, 0, 30},
+ dictWord{5, 10, 607},
+ dictWord{8, 10, 326},
+ dictWord{136, 10, 490},
+ dictWord{4, 10, 701},
+ dictWord{5, 10, 472},
+ dictWord{6, 11, 9},
+ dictWord{6, 11, 397},
+ dictWord{7, 11, 53},
+ dictWord{7, 11, 1742},
+ dictWord{9, 10, 758},
+ dictWord{10, 11, 632},
+ dictWord{
+ 11,
+ 11,
+ 828,
+ },
+ dictWord{140, 11, 146},
+ dictWord{135, 10, 380},
+ dictWord{135, 10, 1947},
+ dictWord{148, 11, 109},
+ dictWord{10, 10, 278},
+ dictWord{
+ 138,
+ 11,
+ 278,
+ },
+ dictWord{134, 0, 856},
+ dictWord{7, 0, 139},
+ dictWord{4, 10, 386},
+ dictWord{8, 10, 405},
+ dictWord{8, 10, 728},
+ dictWord{9, 10, 497},
+ dictWord{
+ 11,
+ 10,
+ 110,
+ },
+ dictWord{11, 10, 360},
+ dictWord{15, 10, 37},
+ dictWord{144, 10, 84},
+ dictWord{141, 0, 282},
+ dictWord{133, 0, 981},
+ dictWord{5, 0, 288},
+ dictWord{
+ 7,
+ 10,
+ 1452,
+ },
+ dictWord{7, 10, 1480},
+ dictWord{8, 10, 634},
+ dictWord{140, 10, 472},
+ dictWord{7, 0, 1890},
+ dictWord{8, 11, 367},
+ dictWord{10, 11, 760},
+ dictWord{
+ 14,
+ 11,
+ 79,
+ },
+ dictWord{20, 11, 17},
+ dictWord{152, 11, 0},
+ dictWord{4, 10, 524},
+ dictWord{136, 10, 810},
+ dictWord{4, 0, 56},
+ dictWord{7, 0, 1791},
+ dictWord{
+ 8,
+ 0,
+ 607,
+ },
+ dictWord{8, 0, 651},
+ dictWord{11, 0, 465},
+ dictWord{11, 0, 835},
+ dictWord{12, 0, 337},
+ dictWord{141, 0, 480},
+ dictWord{10, 10, 238},
+ dictWord{
+ 141,
+ 10,
+ 33,
+ },
+ dictWord{11, 11, 417},
+ dictWord{12, 11, 223},
+ dictWord{140, 11, 265},
+ dictWord{9, 0, 158},
+ dictWord{10, 0, 411},
+ dictWord{140, 0, 261},
+ dictWord{
+ 133,
+ 10,
+ 532,
+ },
+ dictWord{133, 10, 997},
+ dictWord{12, 11, 186},
+ dictWord{12, 11, 292},
+ dictWord{14, 11, 100},
+ dictWord{146, 11, 70},
+ dictWord{6, 0, 1403},
+ dictWord{136, 0, 617},
+ dictWord{134, 0, 1205},
+ dictWord{139, 0, 563},
+ dictWord{4, 0, 242},
+ dictWord{134, 0, 333},
+ dictWord{4, 11, 186},
+ dictWord{5, 11, 157},
+ dictWord{8, 11, 168},
+ dictWord{138, 11, 6},
+ dictWord{132, 0, 369},
+ dictWord{133, 11, 875},
+ dictWord{5, 10, 782},
+ dictWord{5, 10, 829},
+ dictWord{
+ 134,
+ 10,
+ 1738,
+ },
+ dictWord{134, 0, 622},
+ dictWord{135, 11, 1272},
+ dictWord{6, 0, 1407},
+ dictWord{7, 11, 111},
+ dictWord{136, 11, 581},
+ dictWord{7, 10, 1823},
+ dictWord{139, 10, 693},
+ dictWord{7, 0, 160},
+ dictWord{10, 0, 624},
+ dictWord{142, 0, 279},
+ dictWord{132, 0, 363},
+ dictWord{10, 11, 589},
+ dictWord{12, 11, 111},
+ dictWord{13, 11, 260},
+ dictWord{14, 11, 82},
+ dictWord{18, 11, 63},
+ dictWord{147, 11, 45},
+ dictWord{7, 11, 1364},
+ dictWord{7, 11, 1907},
+ dictWord{
+ 141,
+ 11,
+ 158,
+ },
+ dictWord{4, 11, 404},
+ dictWord{4, 11, 659},
+ dictWord{135, 11, 675},
+ dictWord{13, 11, 211},
+ dictWord{14, 11, 133},
+ dictWord{14, 11, 204},
+ dictWord{
+ 15,
+ 11,
+ 64,
+ },
+ dictWord{15, 11, 69},
+ dictWord{15, 11, 114},
+ dictWord{16, 11, 10},
+ dictWord{19, 11, 23},
+ dictWord{19, 11, 35},
+ dictWord{19, 11, 39},
+ dictWord{
+ 19,
+ 11,
+ 51,
+ },
+ dictWord{19, 11, 71},
+ dictWord{19, 11, 75},
+ dictWord{152, 11, 15},
+ dictWord{4, 10, 78},
+ dictWord{5, 10, 96},
+ dictWord{5, 10, 182},
+ dictWord{7, 10, 1724},
+ dictWord{7, 10, 1825},
+ dictWord{10, 10, 394},
+ dictWord{10, 10, 471},
+ dictWord{11, 10, 532},
+ dictWord{14, 10, 340},
+ dictWord{145, 10, 88},
+ dictWord{
+ 135,
+ 10,
+ 1964,
+ },
+ dictWord{133, 11, 391},
+ dictWord{11, 11, 887},
+ dictWord{14, 11, 365},
+ dictWord{142, 11, 375},
+ dictWord{5, 11, 540},
+ dictWord{6, 11, 1697},
+ dictWord{7, 11, 222},
+ dictWord{136, 11, 341},
+ dictWord{134, 11, 78},
+ dictWord{9, 0, 601},
+ dictWord{9, 0, 619},
+ dictWord{10, 0, 505},
+ dictWord{10, 0, 732},
+ dictWord{11, 0, 355},
+ dictWord{140, 0, 139},
+ dictWord{134, 0, 292},
+ dictWord{139, 0, 174},
+ dictWord{5, 0, 177},
+ dictWord{6, 0, 616},
+ dictWord{7, 0, 827},
+ dictWord{
+ 9,
+ 0,
+ 525,
+ },
+ dictWord{138, 0, 656},
+ dictWord{10, 0, 31},
+ dictWord{6, 10, 215},
+ dictWord{7, 10, 1028},
+ dictWord{7, 10, 1473},
+ dictWord{7, 10, 1721},
+ dictWord{
+ 9,
+ 10,
+ 424,
+ },
+ dictWord{138, 10, 779},
+ dictWord{135, 10, 584},
+ dictWord{136, 11, 293},
+ dictWord{134, 0, 685},
+ dictWord{135, 11, 1868},
+ dictWord{
+ 133,
+ 11,
+ 460,
+ },
+ dictWord{7, 0, 647},
+ dictWord{6, 10, 67},
+ dictWord{7, 10, 1630},
+ dictWord{9, 10, 354},
+ dictWord{9, 10, 675},
+ dictWord{10, 10, 830},
+ dictWord{
+ 14,
+ 10,
+ 80,
+ },
+ dictWord{145, 10, 80},
+ dictWord{4, 0, 161},
+ dictWord{133, 0, 631},
+ dictWord{6, 10, 141},
+ dictWord{7, 10, 225},
+ dictWord{9, 10, 59},
+ dictWord{9, 10, 607},
+ dictWord{10, 10, 312},
+ dictWord{11, 10, 687},
+ dictWord{12, 10, 555},
+ dictWord{13, 10, 373},
+ dictWord{13, 10, 494},
+ dictWord{148, 10, 58},
+ dictWord{
+ 7,
+ 11,
+ 965,
+ },
+ dictWord{7, 11, 1460},
+ dictWord{135, 11, 1604},
+ dictWord{136, 10, 783},
+ dictWord{134, 11, 388},
+ dictWord{6, 0, 722},
+ dictWord{6, 0, 1267},
+ dictWord{
+ 4,
+ 11,
+ 511,
+ },
+ dictWord{9, 11, 333},
+ dictWord{9, 11, 379},
+ dictWord{10, 11, 602},
+ dictWord{11, 11, 441},
+ dictWord{11, 11, 723},
+ dictWord{11, 11, 976},
+ dictWord{140, 11, 357},
+ dictWord{134, 0, 1797},
+ dictWord{135, 0, 1684},
+ dictWord{9, 0, 469},
+ dictWord{9, 0, 709},
+ dictWord{12, 0, 512},
+ dictWord{14, 0, 65},
+ dictWord{17, 0, 12},
+ dictWord{5, 11, 938},
+ dictWord{136, 11, 707},
+ dictWord{7, 0, 1230},
+ dictWord{136, 0, 531},
+ dictWord{10, 0, 229},
+ dictWord{11, 0, 73},
+ dictWord{
+ 11,
+ 0,
+ 376,
+ },
+ dictWord{139, 0, 433},
+ dictWord{12, 0, 268},
+ dictWord{12, 0, 640},
+ dictWord{142, 0, 119},
+ dictWord{7, 10, 430},
+ dictWord{139, 10, 46},
+ dictWord{
+ 6,
+ 0,
+ 558,
+ },
+ dictWord{7, 0, 651},
+ dictWord{8, 0, 421},
+ dictWord{9, 0, 0},
+ dictWord{10, 0, 34},
+ dictWord{139, 0, 1008},
+ dictWord{6, 0, 106},
+ dictWord{7, 0, 1786},
+ dictWord{7, 0, 1821},
+ dictWord{9, 0, 102},
+ dictWord{9, 0, 763},
+ dictWord{5, 10, 602},
+ dictWord{7, 10, 2018},
+ dictWord{137, 10, 418},
+ dictWord{5, 0, 65},
+ dictWord{
+ 6,
+ 0,
+ 416,
+ },
+ dictWord{7, 0, 1720},
+ dictWord{7, 0, 1924},
+ dictWord{10, 0, 109},
+ dictWord{11, 0, 14},
+ dictWord{11, 0, 70},
+ dictWord{11, 0, 569},
+ dictWord{11, 0, 735},
+ dictWord{15, 0, 153},
+ dictWord{20, 0, 80},
+ dictWord{136, 10, 677},
+ dictWord{135, 11, 1625},
+ dictWord{137, 11, 772},
+ dictWord{136, 0, 595},
+ dictWord{
+ 6,
+ 11,
+ 469,
+ },
+ dictWord{7, 11, 1709},
+ dictWord{138, 11, 515},
+ dictWord{7, 0, 1832},
+ dictWord{138, 0, 374},
+ dictWord{9, 0, 106},
+ dictWord{9, 0, 163},
+ dictWord{
+ 9,
+ 0,
+ 296,
+ },
+ dictWord{10, 0, 167},
+ dictWord{10, 0, 172},
+ dictWord{10, 0, 777},
+ dictWord{139, 0, 16},
+ dictWord{6, 0, 6},
+ dictWord{7, 0, 81},
+ dictWord{7, 0, 771},
+ dictWord{
+ 7,
+ 0,
+ 1731,
+ },
+ dictWord{9, 0, 405},
+ dictWord{138, 0, 421},
+ dictWord{4, 11, 500},
+ dictWord{135, 11, 938},
+ dictWord{5, 11, 68},
+ dictWord{134, 11, 383},
+ dictWord{
+ 5,
+ 0,
+ 881,
+ },
+ dictWord{133, 0, 885},
+ dictWord{6, 0, 854},
+ dictWord{6, 0, 1132},
+ dictWord{6, 0, 1495},
+ dictWord{6, 0, 1526},
+ dictWord{6, 0, 1533},
+ dictWord{
+ 134,
+ 0,
+ 1577,
+ },
+ dictWord{4, 11, 337},
+ dictWord{6, 11, 353},
+ dictWord{7, 11, 1934},
+ dictWord{8, 11, 488},
+ dictWord{137, 11, 429},
+ dictWord{7, 11, 236},
+ dictWord{
+ 7,
+ 11,
+ 1795,
+ },
+ dictWord{8, 11, 259},
+ dictWord{9, 11, 135},
+ dictWord{9, 11, 177},
+ dictWord{10, 11, 825},
+ dictWord{11, 11, 115},
+ dictWord{11, 11, 370},
+ dictWord{
+ 11,
+ 11,
+ 405,
+ },
+ dictWord{11, 11, 604},
+ dictWord{12, 11, 10},
+ dictWord{12, 11, 667},
+ dictWord{12, 11, 669},
+ dictWord{13, 11, 76},
+ dictWord{14, 11, 310},
+ dictWord{15, 11, 76},
+ dictWord{15, 11, 147},
+ dictWord{148, 11, 23},
+ dictWord{5, 0, 142},
+ dictWord{134, 0, 546},
+ dictWord{4, 11, 15},
+ dictWord{5, 11, 22},
+ dictWord{
+ 6,
+ 11,
+ 244,
+ },
+ dictWord{7, 11, 40},
+ dictWord{7, 11, 200},
+ dictWord{7, 11, 906},
+ dictWord{7, 11, 1199},
+ dictWord{9, 11, 616},
+ dictWord{10, 11, 716},
+ dictWord{
+ 11,
+ 11,
+ 635,
+ },
+ dictWord{11, 11, 801},
+ dictWord{140, 11, 458},
+ dictWord{5, 0, 466},
+ dictWord{11, 0, 571},
+ dictWord{12, 0, 198},
+ dictWord{13, 0, 283},
+ dictWord{
+ 14,
+ 0,
+ 186,
+ },
+ dictWord{15, 0, 21},
+ dictWord{15, 0, 103},
+ dictWord{135, 10, 329},
+ dictWord{4, 0, 185},
+ dictWord{5, 0, 257},
+ dictWord{5, 0, 839},
+ dictWord{5, 0, 936},
+ dictWord{9, 0, 399},
+ dictWord{10, 0, 258},
+ dictWord{10, 0, 395},
+ dictWord{10, 0, 734},
+ dictWord{11, 0, 1014},
+ dictWord{12, 0, 23},
+ dictWord{13, 0, 350},
+ dictWord{
+ 14,
+ 0,
+ 150,
+ },
+ dictWord{19, 0, 6},
+ dictWord{135, 11, 1735},
+ dictWord{12, 11, 36},
+ dictWord{141, 11, 337},
+ dictWord{5, 11, 598},
+ dictWord{7, 11, 791},
+ dictWord{
+ 8,
+ 11,
+ 108,
+ },
+ dictWord{137, 11, 123},
+ dictWord{132, 10, 469},
+ dictWord{7, 0, 404},
+ dictWord{7, 0, 1377},
+ dictWord{7, 0, 1430},
+ dictWord{7, 0, 2017},
+ dictWord{
+ 8,
+ 0,
+ 149,
+ },
+ dictWord{8, 0, 239},
+ dictWord{8, 0, 512},
+ dictWord{8, 0, 793},
+ dictWord{8, 0, 818},
+ dictWord{9, 0, 474},
+ dictWord{9, 0, 595},
+ dictWord{10, 0, 122},
+ dictWord{10, 0, 565},
+ dictWord{10, 0, 649},
+ dictWord{10, 0, 783},
+ dictWord{11, 0, 239},
+ dictWord{11, 0, 295},
+ dictWord{11, 0, 447},
+ dictWord{11, 0, 528},
+ dictWord{
+ 11,
+ 0,
+ 639,
+ },
+ dictWord{11, 0, 800},
+ dictWord{12, 0, 25},
+ dictWord{12, 0, 77},
+ dictWord{12, 0, 157},
+ dictWord{12, 0, 256},
+ dictWord{12, 0, 316},
+ dictWord{12, 0, 390},
+ dictWord{12, 0, 391},
+ dictWord{12, 0, 395},
+ dictWord{12, 0, 478},
+ dictWord{12, 0, 503},
+ dictWord{12, 0, 592},
+ dictWord{12, 0, 680},
+ dictWord{13, 0, 50},
+ dictWord{13, 0, 53},
+ dictWord{13, 0, 132},
+ dictWord{13, 0, 198},
+ dictWord{13, 0, 322},
+ dictWord{13, 0, 415},
+ dictWord{13, 0, 511},
+ dictWord{14, 0, 71},
+ dictWord{
+ 14,
+ 0,
+ 395,
+ },
+ dictWord{15, 0, 71},
+ dictWord{15, 0, 136},
+ dictWord{17, 0, 123},
+ dictWord{18, 0, 93},
+ dictWord{147, 0, 58},
+ dictWord{136, 0, 712},
+ dictWord{
+ 134,
+ 10,
+ 1743,
+ },
+ dictWord{5, 10, 929},
+ dictWord{6, 10, 340},
+ dictWord{8, 10, 376},
+ dictWord{136, 10, 807},
+ dictWord{6, 0, 1848},
+ dictWord{8, 0, 860},
+ dictWord{
+ 10,
+ 0,
+ 856,
+ },
+ dictWord{10, 0, 859},
+ dictWord{10, 0, 925},
+ dictWord{10, 0, 941},
+ dictWord{140, 0, 762},
+ dictWord{6, 0, 629},
+ dictWord{6, 0, 906},
+ dictWord{9, 0, 810},
+ dictWord{140, 0, 652},
+ dictWord{5, 10, 218},
+ dictWord{7, 10, 1610},
+ dictWord{138, 10, 83},
+ dictWord{7, 10, 1512},
+ dictWord{135, 10, 1794},
+ dictWord{
+ 4,
+ 0,
+ 377,
+ },
+ dictWord{24, 0, 13},
+ dictWord{4, 11, 155},
+ dictWord{7, 11, 1689},
+ dictWord{11, 10, 0},
+ dictWord{144, 10, 78},
+ dictWord{4, 11, 164},
+ dictWord{5, 11, 151},
+ dictWord{5, 11, 730},
+ dictWord{5, 11, 741},
+ dictWord{7, 11, 498},
+ dictWord{7, 11, 870},
+ dictWord{7, 11, 1542},
+ dictWord{12, 11, 213},
+ dictWord{14, 11, 36},
+ dictWord{14, 11, 391},
+ dictWord{17, 11, 111},
+ dictWord{18, 11, 6},
+ dictWord{18, 11, 46},
+ dictWord{18, 11, 151},
+ dictWord{19, 11, 36},
+ dictWord{20, 11, 32},
+ dictWord{20, 11, 56},
+ dictWord{20, 11, 69},
+ dictWord{20, 11, 102},
+ dictWord{21, 11, 4},
+ dictWord{22, 11, 8},
+ dictWord{22, 11, 10},
+ dictWord{22, 11, 14},
+ dictWord{
+ 150,
+ 11,
+ 31,
+ },
+ dictWord{7, 0, 1842},
+ dictWord{133, 10, 571},
+ dictWord{4, 10, 455},
+ dictWord{4, 11, 624},
+ dictWord{135, 11, 1752},
+ dictWord{134, 0, 1501},
+ dictWord{4, 11, 492},
+ dictWord{5, 11, 451},
+ dictWord{6, 10, 161},
+ dictWord{7, 10, 372},
+ dictWord{137, 10, 597},
+ dictWord{132, 10, 349},
+ dictWord{4, 0, 180},
+ dictWord{135, 0, 1906},
+ dictWord{135, 11, 835},
+ dictWord{141, 11, 70},
+ dictWord{132, 0, 491},
+ dictWord{137, 10, 751},
+ dictWord{6, 10, 432},
+ dictWord{
+ 139,
+ 10,
+ 322,
+ },
+ dictWord{4, 0, 171},
+ dictWord{138, 0, 234},
+ dictWord{6, 11, 113},
+ dictWord{135, 11, 436},
+ dictWord{4, 0, 586},
+ dictWord{7, 0, 1186},
+ dictWord{
+ 138,
+ 0,
+ 631,
+ },
+ dictWord{5, 10, 468},
+ dictWord{10, 10, 325},
+ dictWord{11, 10, 856},
+ dictWord{12, 10, 345},
+ dictWord{143, 10, 104},
+ dictWord{5, 10, 223},
+ dictWord{10, 11, 592},
+ dictWord{10, 11, 753},
+ dictWord{12, 11, 317},
+ dictWord{12, 11, 355},
+ dictWord{12, 11, 465},
+ dictWord{12, 11, 469},
+ dictWord{
+ 12,
+ 11,
+ 560,
+ },
+ dictWord{12, 11, 578},
+ dictWord{141, 11, 243},
+ dictWord{132, 10, 566},
+ dictWord{135, 11, 520},
+ dictWord{4, 10, 59},
+ dictWord{135, 10, 1394},
+ dictWord{6, 10, 436},
+ dictWord{139, 10, 481},
+ dictWord{9, 0, 931},
+ dictWord{10, 0, 334},
+ dictWord{20, 0, 71},
+ dictWord{4, 10, 48},
+ dictWord{5, 10, 271},
+ dictWord{
+ 7,
+ 10,
+ 953,
+ },
+ dictWord{135, 11, 1878},
+ dictWord{11, 0, 170},
+ dictWord{5, 10, 610},
+ dictWord{136, 10, 457},
+ dictWord{133, 10, 755},
+ dictWord{6, 0, 1587},
+ dictWord{135, 10, 1217},
+ dictWord{4, 10, 197},
+ dictWord{149, 11, 26},
+ dictWord{133, 11, 585},
+ dictWord{137, 11, 521},
+ dictWord{133, 0, 765},
+ dictWord{
+ 133,
+ 10,
+ 217,
+ },
+ dictWord{139, 11, 586},
+ dictWord{133, 0, 424},
+ dictWord{9, 11, 752},
+ dictWord{12, 11, 610},
+ dictWord{13, 11, 431},
+ dictWord{16, 11, 59},
+ dictWord{146, 11, 109},
+ dictWord{136, 0, 714},
+ dictWord{7, 0, 685},
+ dictWord{132, 11, 307},
+ dictWord{9, 0, 420},
+ dictWord{10, 0, 269},
+ dictWord{10, 0, 285},
+ dictWord{10, 0, 576},
+ dictWord{11, 0, 397},
+ dictWord{13, 0, 175},
+ dictWord{145, 0, 90},
+ dictWord{132, 0, 429},
+ dictWord{133, 11, 964},
+ dictWord{9, 11, 463},
+ dictWord{138, 11, 595},
+ dictWord{7, 0, 18},
+ dictWord{7, 0, 699},
+ dictWord{7, 0, 1966},
+ dictWord{8, 0, 752},
+ dictWord{9, 0, 273},
+ dictWord{9, 0, 412},
+ dictWord{
+ 9,
+ 0,
+ 703,
+ },
+ dictWord{10, 0, 71},
+ dictWord{10, 0, 427},
+ dictWord{138, 0, 508},
+ dictWord{4, 10, 165},
+ dictWord{7, 10, 1398},
+ dictWord{135, 10, 1829},
+ dictWord{
+ 4,
+ 0,
+ 53,
+ },
+ dictWord{5, 0, 186},
+ dictWord{7, 0, 752},
+ dictWord{7, 0, 828},
+ dictWord{142, 0, 116},
+ dictWord{8, 0, 575},
+ dictWord{10, 0, 289},
+ dictWord{139, 0, 319},
+ dictWord{132, 0, 675},
+ dictWord{134, 0, 1424},
+ dictWord{4, 11, 75},
+ dictWord{5, 11, 180},
+ dictWord{6, 11, 500},
+ dictWord{7, 11, 58},
+ dictWord{7, 11, 710},
+ dictWord{138, 11, 645},
+ dictWord{133, 11, 649},
+ dictWord{6, 11, 276},
+ dictWord{7, 11, 282},
+ dictWord{7, 11, 879},
+ dictWord{7, 11, 924},
+ dictWord{8, 11, 459},
+ dictWord{9, 11, 599},
+ dictWord{9, 11, 754},
+ dictWord{11, 11, 574},
+ dictWord{12, 11, 128},
+ dictWord{12, 11, 494},
+ dictWord{13, 11, 52},
+ dictWord{13, 11, 301},
+ dictWord{15, 11, 30},
+ dictWord{143, 11, 132},
+ dictWord{6, 0, 647},
+ dictWord{134, 0, 1095},
+ dictWord{5, 10, 9},
+ dictWord{7, 10, 297},
+ dictWord{7, 10, 966},
+ dictWord{140, 10, 306},
+ dictWord{132, 11, 200},
+ dictWord{134, 0, 1334},
+ dictWord{5, 10, 146},
+ dictWord{6, 10, 411},
+ dictWord{138, 10, 721},
+ dictWord{
+ 6,
+ 0,
+ 209,
+ },
+ dictWord{6, 0, 1141},
+ dictWord{6, 0, 1288},
+ dictWord{8, 0, 468},
+ dictWord{9, 0, 210},
+ dictWord{11, 0, 36},
+ dictWord{12, 0, 28},
+ dictWord{12, 0, 630},
+ dictWord{13, 0, 21},
+ dictWord{13, 0, 349},
+ dictWord{14, 0, 7},
+ dictWord{145, 0, 13},
+ dictWord{6, 10, 177},
+ dictWord{135, 10, 467},
+ dictWord{4, 0, 342},
+ dictWord{
+ 135,
+ 0,
+ 1179,
+ },
+ dictWord{10, 11, 454},
+ dictWord{140, 11, 324},
+ dictWord{4, 0, 928},
+ dictWord{133, 0, 910},
+ dictWord{7, 0, 1838},
+ dictWord{6, 11, 225},
+ dictWord{
+ 137,
+ 11,
+ 211,
+ },
+ dictWord{16, 0, 101},
+ dictWord{20, 0, 115},
+ dictWord{20, 0, 118},
+ dictWord{148, 0, 122},
+ dictWord{4, 0, 496},
+ dictWord{135, 0, 856},
+ dictWord{
+ 4,
+ 0,
+ 318,
+ },
+ dictWord{11, 0, 654},
+ dictWord{7, 11, 718},
+ dictWord{139, 11, 102},
+ dictWord{8, 11, 58},
+ dictWord{9, 11, 724},
+ dictWord{11, 11, 809},
+ dictWord{
+ 13,
+ 11,
+ 113,
+ },
+ dictWord{145, 11, 72},
+ dictWord{5, 10, 200},
+ dictWord{6, 11, 345},
+ dictWord{135, 11, 1247},
+ dictWord{8, 11, 767},
+ dictWord{8, 11, 803},
+ dictWord{
+ 9,
+ 11,
+ 301,
+ },
+ dictWord{137, 11, 903},
+ dictWord{7, 0, 915},
+ dictWord{8, 0, 247},
+ dictWord{19, 0, 0},
+ dictWord{7, 11, 1949},
+ dictWord{136, 11, 674},
+ dictWord{
+ 4,
+ 0,
+ 202,
+ },
+ dictWord{5, 0, 382},
+ dictWord{6, 0, 454},
+ dictWord{7, 0, 936},
+ dictWord{7, 0, 1803},
+ dictWord{8, 0, 758},
+ dictWord{9, 0, 375},
+ dictWord{9, 0, 895},
+ dictWord{
+ 10,
+ 0,
+ 743,
+ },
+ dictWord{10, 0, 792},
+ dictWord{11, 0, 978},
+ dictWord{11, 0, 1012},
+ dictWord{142, 0, 109},
+ dictWord{7, 0, 1150},
+ dictWord{7, 0, 1425},
+ dictWord{
+ 7,
+ 0,
+ 1453,
+ },
+ dictWord{140, 0, 513},
+ dictWord{134, 11, 259},
+ dictWord{138, 0, 791},
+ dictWord{11, 0, 821},
+ dictWord{12, 0, 110},
+ dictWord{12, 0, 153},
+ dictWord{
+ 18,
+ 0,
+ 41,
+ },
+ dictWord{150, 0, 19},
+ dictWord{134, 10, 481},
+ dictWord{132, 0, 796},
+ dictWord{6, 0, 445},
+ dictWord{9, 0, 909},
+ dictWord{136, 11, 254},
+ dictWord{
+ 10,
+ 0,
+ 776,
+ },
+ dictWord{13, 0, 345},
+ dictWord{142, 0, 425},
+ dictWord{4, 10, 84},
+ dictWord{7, 10, 1482},
+ dictWord{10, 10, 76},
+ dictWord{138, 10, 142},
+ dictWord{
+ 135,
+ 11,
+ 742,
+ },
+ dictWord{6, 0, 578},
+ dictWord{133, 10, 1015},
+ dictWord{6, 0, 1387},
+ dictWord{4, 10, 315},
+ dictWord{5, 10, 507},
+ dictWord{135, 10, 1370},
+ dictWord{4, 0, 438},
+ dictWord{133, 0, 555},
+ dictWord{136, 0, 766},
+ dictWord{133, 11, 248},
+ dictWord{134, 10, 1722},
+ dictWord{4, 11, 116},
+ dictWord{5, 11, 95},
+ dictWord{5, 11, 445},
+ dictWord{7, 11, 1688},
+ dictWord{8, 11, 29},
+ dictWord{9, 11, 272},
+ dictWord{11, 11, 509},
+ dictWord{139, 11, 915},
+ dictWord{135, 0, 541},
+ dictWord{133, 11, 543},
+ dictWord{8, 10, 222},
+ dictWord{8, 10, 476},
+ dictWord{9, 10, 238},
+ dictWord{11, 10, 516},
+ dictWord{11, 10, 575},
+ dictWord{
+ 15,
+ 10,
+ 109,
+ },
+ dictWord{146, 10, 100},
+ dictWord{6, 0, 880},
+ dictWord{134, 0, 1191},
+ dictWord{5, 11, 181},
+ dictWord{136, 11, 41},
+ dictWord{134, 0, 1506},
+ dictWord{132, 11, 681},
+ dictWord{7, 11, 25},
+ dictWord{8, 11, 202},
+ dictWord{138, 11, 536},
+ dictWord{139, 0, 983},
+ dictWord{137, 0, 768},
+ dictWord{132, 0, 584},
+ dictWord{9, 11, 423},
+ dictWord{140, 11, 89},
+ dictWord{8, 11, 113},
+ dictWord{9, 11, 877},
+ dictWord{10, 11, 554},
+ dictWord{11, 11, 83},
+ dictWord{12, 11, 136},
+ dictWord{147, 11, 109},
+ dictWord{7, 10, 706},
+ dictWord{7, 10, 1058},
+ dictWord{138, 10, 538},
+ dictWord{133, 11, 976},
+ dictWord{4, 11, 206},
+ dictWord{
+ 135,
+ 11,
+ 746,
+ },
+ dictWord{136, 11, 526},
+ dictWord{140, 0, 737},
+ dictWord{11, 10, 92},
+ dictWord{11, 10, 196},
+ dictWord{11, 10, 409},
+ dictWord{11, 10, 450},
+ dictWord{11, 10, 666},
+ dictWord{11, 10, 777},
+ dictWord{12, 10, 262},
+ dictWord{13, 10, 385},
+ dictWord{13, 10, 393},
+ dictWord{15, 10, 115},
+ dictWord{
+ 16,
+ 10,
+ 45,
+ },
+ dictWord{145, 10, 82},
+ dictWord{4, 0, 226},
+ dictWord{4, 0, 326},
+ dictWord{7, 0, 1770},
+ dictWord{4, 11, 319},
+ dictWord{5, 11, 699},
+ dictWord{138, 11, 673},
+ dictWord{6, 10, 40},
+ dictWord{135, 10, 1781},
+ dictWord{5, 0, 426},
+ dictWord{8, 0, 30},
+ dictWord{9, 0, 2},
+ dictWord{11, 0, 549},
+ dictWord{147, 0, 122},
+ dictWord{
+ 6,
+ 0,
+ 1161,
+ },
+ dictWord{134, 0, 1329},
+ dictWord{138, 10, 97},
+ dictWord{6, 10, 423},
+ dictWord{7, 10, 665},
+ dictWord{135, 10, 1210},
+ dictWord{7, 11, 13},
+ dictWord{
+ 8,
+ 11,
+ 226,
+ },
+ dictWord{10, 11, 537},
+ dictWord{11, 11, 570},
+ dictWord{11, 11, 605},
+ dictWord{11, 11, 799},
+ dictWord{11, 11, 804},
+ dictWord{12, 11, 85},
+ dictWord{12, 11, 516},
+ dictWord{12, 11, 623},
+ dictWord{13, 11, 112},
+ dictWord{13, 11, 361},
+ dictWord{14, 11, 77},
+ dictWord{14, 11, 78},
+ dictWord{17, 11, 28},
+ dictWord{147, 11, 110},
+ dictWord{132, 11, 769},
+ dictWord{132, 11, 551},
+ dictWord{132, 11, 728},
+ dictWord{147, 0, 117},
+ dictWord{9, 11, 57},
+ dictWord{
+ 9,
+ 11,
+ 459,
+ },
+ dictWord{10, 11, 425},
+ dictWord{11, 11, 119},
+ dictWord{12, 11, 184},
+ dictWord{12, 11, 371},
+ dictWord{13, 11, 358},
+ dictWord{145, 11, 51},
+ dictWord{
+ 5,
+ 11,
+ 188,
+ },
+ dictWord{5, 11, 814},
+ dictWord{8, 11, 10},
+ dictWord{9, 11, 421},
+ dictWord{9, 11, 729},
+ dictWord{10, 11, 609},
+ dictWord{139, 11, 689},
+ dictWord{134, 11, 624},
+ dictWord{135, 11, 298},
+ dictWord{135, 0, 462},
+ dictWord{4, 0, 345},
+ dictWord{139, 10, 624},
+ dictWord{136, 10, 574},
+ dictWord{
+ 4,
+ 0,
+ 385,
+ },
+ dictWord{7, 0, 265},
+ dictWord{135, 0, 587},
+ dictWord{6, 0, 808},
+ dictWord{132, 11, 528},
+ dictWord{133, 0, 398},
+ dictWord{132, 10, 354},
+ dictWord{
+ 4,
+ 0,
+ 347,
+ },
+ dictWord{5, 0, 423},
+ dictWord{5, 0, 996},
+ dictWord{135, 0, 1329},
+ dictWord{135, 10, 1558},
+ dictWord{7, 0, 1259},
+ dictWord{9, 0, 125},
+ dictWord{
+ 139,
+ 0,
+ 65,
+ },
+ dictWord{5, 0, 136},
+ dictWord{6, 0, 136},
+ dictWord{136, 0, 644},
+ dictWord{5, 11, 104},
+ dictWord{6, 11, 173},
+ dictWord{135, 11, 1631},
+ dictWord{
+ 135,
+ 0,
+ 469,
+ },
+ dictWord{133, 10, 830},
+ dictWord{4, 0, 278},
+ dictWord{5, 0, 465},
+ dictWord{135, 0, 1367},
+ dictWord{7, 11, 810},
+ dictWord{8, 11, 138},
+ dictWord{
+ 8,
+ 11,
+ 342,
+ },
+ dictWord{9, 11, 84},
+ dictWord{10, 11, 193},
+ dictWord{11, 11, 883},
+ dictWord{140, 11, 359},
+ dictWord{5, 10, 496},
+ dictWord{135, 10, 203},
+ dictWord{
+ 4,
+ 0,
+ 433,
+ },
+ dictWord{133, 0, 719},
+ dictWord{6, 11, 95},
+ dictWord{134, 10, 547},
+ dictWord{5, 10, 88},
+ dictWord{137, 10, 239},
+ dictWord{6, 11, 406},
+ dictWord{
+ 10,
+ 11,
+ 409,
+ },
+ dictWord{10, 11, 447},
+ dictWord{11, 11, 44},
+ dictWord{140, 11, 100},
+ dictWord{134, 0, 1423},
+ dictWord{7, 10, 650},
+ dictWord{135, 10, 1310},
+ dictWord{134, 0, 749},
+ dictWord{135, 11, 1243},
+ dictWord{135, 0, 1363},
+ dictWord{6, 0, 381},
+ dictWord{7, 0, 645},
+ dictWord{7, 0, 694},
+ dictWord{8, 0, 546},
+ dictWord{7, 10, 1076},
+ dictWord{9, 10, 80},
+ dictWord{11, 10, 78},
+ dictWord{11, 10, 421},
+ dictWord{11, 10, 534},
+ dictWord{140, 10, 545},
+ dictWord{
+ 134,
+ 11,
+ 1636,
+ },
+ dictWord{135, 11, 1344},
+ dictWord{12, 0, 277},
+ dictWord{7, 10, 274},
+ dictWord{11, 10, 479},
+ dictWord{139, 10, 507},
+ dictWord{6, 0, 705},
+ dictWord{
+ 6,
+ 0,
+ 783,
+ },
+ dictWord{6, 0, 1275},
+ dictWord{6, 0, 1481},
+ dictWord{4, 11, 282},
+ dictWord{7, 11, 1034},
+ dictWord{11, 11, 398},
+ dictWord{11, 11, 634},
+ dictWord{
+ 12,
+ 11,
+ 1,
+ },
+ dictWord{12, 11, 79},
+ dictWord{12, 11, 544},
+ dictWord{14, 11, 237},
+ dictWord{17, 11, 10},
+ dictWord{146, 11, 20},
+ dictWord{134, 0, 453},
+ dictWord{
+ 4,
+ 0,
+ 555,
+ },
+ dictWord{8, 0, 536},
+ dictWord{10, 0, 288},
+ dictWord{11, 0, 1005},
+ dictWord{4, 10, 497},
+ dictWord{135, 10, 1584},
+ dictWord{5, 11, 118},
+ dictWord{
+ 5,
+ 11,
+ 499,
+ },
+ dictWord{6, 11, 476},
+ dictWord{7, 11, 600},
+ dictWord{7, 11, 888},
+ dictWord{135, 11, 1096},
+ dictWord{138, 0, 987},
+ dictWord{7, 0, 1107},
+ dictWord{
+ 7,
+ 10,
+ 261,
+ },
+ dictWord{7, 10, 1115},
+ dictWord{7, 10, 1354},
+ dictWord{7, 10, 1588},
+ dictWord{7, 10, 1705},
+ dictWord{7, 10, 1902},
+ dictWord{9, 10, 465},
+ dictWord{10, 10, 248},
+ dictWord{10, 10, 349},
+ dictWord{10, 10, 647},
+ dictWord{11, 10, 527},
+ dictWord{11, 10, 660},
+ dictWord{11, 10, 669},
+ dictWord{
+ 12,
+ 10,
+ 529,
+ },
+ dictWord{141, 10, 305},
+ dictWord{7, 11, 296},
+ dictWord{7, 11, 596},
+ dictWord{8, 11, 560},
+ dictWord{8, 11, 586},
+ dictWord{9, 11, 612},
+ dictWord{
+ 11,
+ 11,
+ 100,
+ },
+ dictWord{11, 11, 304},
+ dictWord{12, 11, 46},
+ dictWord{13, 11, 89},
+ dictWord{14, 11, 112},
+ dictWord{145, 11, 122},
+ dictWord{9, 0, 370},
+ dictWord{
+ 138,
+ 0,
+ 90,
+ },
+ dictWord{136, 10, 13},
+ dictWord{132, 0, 860},
+ dictWord{7, 10, 642},
+ dictWord{8, 10, 250},
+ dictWord{11, 10, 123},
+ dictWord{11, 10, 137},
+ dictWord{
+ 13,
+ 10,
+ 48,
+ },
+ dictWord{142, 10, 95},
+ dictWord{135, 10, 1429},
+ dictWord{137, 11, 321},
+ dictWord{132, 0, 257},
+ dictWord{135, 0, 2031},
+ dictWord{7, 0, 1768},
+ dictWord{7, 11, 1599},
+ dictWord{7, 11, 1723},
+ dictWord{8, 11, 79},
+ dictWord{8, 11, 106},
+ dictWord{8, 11, 190},
+ dictWord{8, 11, 302},
+ dictWord{8, 11, 383},
+ dictWord{9, 11, 119},
+ dictWord{9, 11, 233},
+ dictWord{9, 11, 298},
+ dictWord{9, 11, 419},
+ dictWord{9, 11, 471},
+ dictWord{10, 11, 181},
+ dictWord{10, 11, 406},
+ dictWord{11, 11, 57},
+ dictWord{11, 11, 85},
+ dictWord{11, 11, 120},
+ dictWord{11, 11, 177},
+ dictWord{11, 11, 296},
+ dictWord{11, 11, 382},
+ dictWord{11, 11, 454},
+ dictWord{11, 11, 758},
+ dictWord{11, 11, 999},
+ dictWord{12, 11, 27},
+ dictWord{12, 11, 98},
+ dictWord{12, 11, 131},
+ dictWord{12, 11, 245},
+ dictWord{
+ 12,
+ 11,
+ 312,
+ },
+ dictWord{12, 11, 446},
+ dictWord{12, 11, 454},
+ dictWord{13, 11, 25},
+ dictWord{13, 11, 98},
+ dictWord{13, 11, 426},
+ dictWord{13, 11, 508},
+ dictWord{
+ 14,
+ 11,
+ 6,
+ },
+ dictWord{14, 11, 163},
+ dictWord{14, 11, 272},
+ dictWord{14, 11, 277},
+ dictWord{14, 11, 370},
+ dictWord{15, 11, 95},
+ dictWord{15, 11, 138},
+ dictWord{
+ 15,
+ 11,
+ 167,
+ },
+ dictWord{17, 11, 18},
+ dictWord{17, 11, 38},
+ dictWord{20, 11, 96},
+ dictWord{149, 11, 32},
+ dictWord{5, 11, 722},
+ dictWord{134, 11, 1759},
+ dictWord{145, 11, 16},
+ dictWord{6, 0, 1071},
+ dictWord{134, 0, 1561},
+ dictWord{10, 10, 545},
+ dictWord{140, 10, 301},
+ dictWord{6, 0, 83},
+ dictWord{6, 0, 1733},
+ dictWord{135, 0, 1389},
+ dictWord{4, 0, 835},
+ dictWord{135, 0, 1818},
+ dictWord{133, 11, 258},
+ dictWord{4, 10, 904},
+ dictWord{133, 10, 794},
+ dictWord{
+ 134,
+ 0,
+ 2006,
+ },
+ dictWord{5, 11, 30},
+ dictWord{7, 11, 495},
+ dictWord{8, 11, 134},
+ dictWord{9, 11, 788},
+ dictWord{140, 11, 438},
+ dictWord{135, 11, 2004},
+ dictWord{
+ 137,
+ 0,
+ 696,
+ },
+ dictWord{5, 11, 50},
+ dictWord{6, 11, 439},
+ dictWord{7, 11, 780},
+ dictWord{135, 11, 1040},
+ dictWord{7, 11, 772},
+ dictWord{7, 11, 1104},
+ dictWord{
+ 7,
+ 11,
+ 1647,
+ },
+ dictWord{11, 11, 269},
+ dictWord{11, 11, 539},
+ dictWord{11, 11, 607},
+ dictWord{11, 11, 627},
+ dictWord{11, 11, 706},
+ dictWord{11, 11, 975},
+ dictWord{12, 11, 248},
+ dictWord{12, 11, 311},
+ dictWord{12, 11, 434},
+ dictWord{12, 11, 600},
+ dictWord{12, 11, 622},
+ dictWord{13, 11, 297},
+ dictWord{
+ 13,
+ 11,
+ 367,
+ },
+ dictWord{13, 11, 485},
+ dictWord{14, 11, 69},
+ dictWord{14, 11, 409},
+ dictWord{143, 11, 108},
+ dictWord{5, 11, 1},
+ dictWord{6, 11, 81},
+ dictWord{
+ 138,
+ 11,
+ 520,
+ },
+ dictWord{7, 0, 1718},
+ dictWord{9, 0, 95},
+ dictWord{9, 0, 274},
+ dictWord{10, 0, 279},
+ dictWord{10, 0, 317},
+ dictWord{10, 0, 420},
+ dictWord{11, 0, 303},
+ dictWord{11, 0, 808},
+ dictWord{12, 0, 134},
+ dictWord{12, 0, 367},
+ dictWord{13, 0, 149},
+ dictWord{13, 0, 347},
+ dictWord{14, 0, 349},
+ dictWord{14, 0, 406},
+ dictWord{
+ 18,
+ 0,
+ 22,
+ },
+ dictWord{18, 0, 89},
+ dictWord{18, 0, 122},
+ dictWord{147, 0, 47},
+ dictWord{5, 11, 482},
+ dictWord{8, 11, 98},
+ dictWord{9, 11, 172},
+ dictWord{10, 11, 222},
+ dictWord{10, 11, 700},
+ dictWord{10, 11, 822},
+ dictWord{11, 11, 302},
+ dictWord{11, 11, 778},
+ dictWord{12, 11, 50},
+ dictWord{12, 11, 127},
+ dictWord{
+ 12,
+ 11,
+ 396,
+ },
+ dictWord{13, 11, 62},
+ dictWord{13, 11, 328},
+ dictWord{14, 11, 122},
+ dictWord{147, 11, 72},
+ dictWord{7, 10, 386},
+ dictWord{138, 10, 713},
+ dictWord{
+ 6,
+ 10,
+ 7,
+ },
+ dictWord{6, 10, 35},
+ dictWord{7, 10, 147},
+ dictWord{7, 10, 1069},
+ dictWord{7, 10, 1568},
+ dictWord{7, 10, 1575},
+ dictWord{7, 10, 1917},
+ dictWord{
+ 8,
+ 10,
+ 43,
+ },
+ dictWord{8, 10, 208},
+ dictWord{9, 10, 128},
+ dictWord{9, 10, 866},
+ dictWord{10, 10, 20},
+ dictWord{11, 10, 981},
+ dictWord{147, 10, 33},
+ dictWord{
+ 133,
+ 0,
+ 26,
+ },
+ dictWord{132, 0, 550},
+ dictWord{5, 11, 2},
+ dictWord{7, 11, 1494},
+ dictWord{136, 11, 589},
+ dictWord{6, 11, 512},
+ dictWord{7, 11, 797},
+ dictWord{
+ 8,
+ 11,
+ 253,
+ },
+ dictWord{9, 11, 77},
+ dictWord{10, 11, 1},
+ dictWord{10, 11, 129},
+ dictWord{10, 11, 225},
+ dictWord{11, 11, 118},
+ dictWord{11, 11, 226},
+ dictWord{
+ 11,
+ 11,
+ 251,
+ },
+ dictWord{11, 11, 430},
+ dictWord{11, 11, 701},
+ dictWord{11, 11, 974},
+ dictWord{11, 11, 982},
+ dictWord{12, 11, 64},
+ dictWord{12, 11, 260},
+ dictWord{
+ 12,
+ 11,
+ 488,
+ },
+ dictWord{140, 11, 690},
+ dictWord{7, 10, 893},
+ dictWord{141, 10, 424},
+ dictWord{134, 0, 901},
+ dictWord{136, 0, 822},
+ dictWord{4, 0, 902},
+ dictWord{5, 0, 809},
+ dictWord{134, 0, 122},
+ dictWord{6, 0, 807},
+ dictWord{134, 0, 1366},
+ dictWord{7, 0, 262},
+ dictWord{5, 11, 748},
+ dictWord{134, 11, 553},
+ dictWord{133, 0, 620},
+ dictWord{4, 0, 34},
+ dictWord{5, 0, 574},
+ dictWord{7, 0, 279},
+ dictWord{7, 0, 1624},
+ dictWord{136, 0, 601},
+ dictWord{9, 0, 170},
+ dictWord{
+ 6,
+ 10,
+ 322,
+ },
+ dictWord{9, 10, 552},
+ dictWord{11, 10, 274},
+ dictWord{13, 10, 209},
+ dictWord{13, 10, 499},
+ dictWord{14, 10, 85},
+ dictWord{15, 10, 126},
+ dictWord{
+ 145,
+ 10,
+ 70,
+ },
+ dictWord{132, 0, 537},
+ dictWord{4, 11, 12},
+ dictWord{7, 11, 420},
+ dictWord{7, 11, 522},
+ dictWord{7, 11, 809},
+ dictWord{8, 11, 797},
+ dictWord{
+ 141,
+ 11,
+ 88,
+ },
+ dictWord{133, 0, 332},
+ dictWord{8, 10, 83},
+ dictWord{8, 10, 742},
+ dictWord{8, 10, 817},
+ dictWord{9, 10, 28},
+ dictWord{9, 10, 29},
+ dictWord{9, 10, 885},
+ dictWord{10, 10, 387},
+ dictWord{11, 10, 633},
+ dictWord{11, 10, 740},
+ dictWord{13, 10, 235},
+ dictWord{13, 10, 254},
+ dictWord{15, 10, 143},
+ dictWord{
+ 143,
+ 10,
+ 146,
+ },
+ dictWord{6, 0, 1909},
+ dictWord{9, 0, 964},
+ dictWord{12, 0, 822},
+ dictWord{12, 0, 854},
+ dictWord{12, 0, 865},
+ dictWord{12, 0, 910},
+ dictWord{12, 0, 938},
+ dictWord{15, 0, 169},
+ dictWord{15, 0, 208},
+ dictWord{15, 0, 211},
+ dictWord{18, 0, 205},
+ dictWord{18, 0, 206},
+ dictWord{18, 0, 220},
+ dictWord{18, 0, 223},
+ dictWord{152, 0, 24},
+ dictWord{140, 10, 49},
+ dictWord{5, 11, 528},
+ dictWord{135, 11, 1580},
+ dictWord{6, 0, 261},
+ dictWord{8, 0, 182},
+ dictWord{139, 0, 943},
+ dictWord{134, 0, 1721},
+ dictWord{4, 0, 933},
+ dictWord{133, 0, 880},
+ dictWord{136, 11, 321},
+ dictWord{5, 11, 266},
+ dictWord{9, 11, 290},
+ dictWord{9, 11, 364},
+ dictWord{10, 11, 293},
+ dictWord{11, 11, 606},
+ dictWord{142, 11, 45},
+ dictWord{6, 0, 1609},
+ dictWord{4, 11, 50},
+ dictWord{6, 11, 510},
+ dictWord{6, 11, 594},
+ dictWord{9, 11, 121},
+ dictWord{10, 11, 49},
+ dictWord{10, 11, 412},
+ dictWord{139, 11, 834},
+ dictWord{7, 0, 895},
+ dictWord{136, 11, 748},
+ dictWord{132, 11, 466},
+ dictWord{4, 10, 110},
+ dictWord{10, 10, 415},
+ dictWord{10, 10, 597},
+ dictWord{142, 10, 206},
+ dictWord{133, 0, 812},
+ dictWord{135, 11, 281},
+ dictWord{
+ 6,
+ 0,
+ 1890,
+ },
+ dictWord{6, 0, 1902},
+ dictWord{6, 0, 1916},
+ dictWord{9, 0, 929},
+ dictWord{9, 0, 942},
+ dictWord{9, 0, 975},
+ dictWord{9, 0, 984},
+ dictWord{9, 0, 986},
+ dictWord{
+ 9,
+ 0,
+ 1011,
+ },
+ dictWord{9, 0, 1019},
+ dictWord{12, 0, 804},
+ dictWord{12, 0, 851},
+ dictWord{12, 0, 867},
+ dictWord{12, 0, 916},
+ dictWord{12, 0, 923},
+ dictWord{
+ 15,
+ 0,
+ 194,
+ },
+ dictWord{15, 0, 204},
+ dictWord{15, 0, 210},
+ dictWord{15, 0, 222},
+ dictWord{15, 0, 223},
+ dictWord{15, 0, 229},
+ dictWord{15, 0, 250},
+ dictWord{
+ 18,
+ 0,
+ 179,
+ },
+ dictWord{18, 0, 186},
+ dictWord{18, 0, 192},
+ dictWord{7, 10, 205},
+ dictWord{135, 10, 2000},
+ dictWord{132, 11, 667},
+ dictWord{135, 0, 778},
+ dictWord{
+ 4,
+ 0,
+ 137,
+ },
+ dictWord{7, 0, 1178},
+ dictWord{135, 0, 1520},
+ dictWord{134, 0, 1314},
+ dictWord{4, 11, 242},
+ dictWord{134, 11, 333},
+ dictWord{6, 0, 1661},
+ dictWord{7, 0, 1975},
+ dictWord{7, 0, 2009},
+ dictWord{135, 0, 2011},
+ dictWord{134, 0, 1591},
+ dictWord{4, 10, 283},
+ dictWord{135, 10, 1194},
+ dictWord{
+ 11,
+ 0,
+ 820,
+ },
+ dictWord{150, 0, 51},
+ dictWord{4, 11, 39},
+ dictWord{5, 11, 36},
+ dictWord{7, 11, 1843},
+ dictWord{8, 11, 407},
+ dictWord{11, 11, 144},
+ dictWord{
+ 140,
+ 11,
+ 523,
+ },
+ dictWord{134, 10, 1720},
+ dictWord{4, 11, 510},
+ dictWord{7, 11, 29},
+ dictWord{7, 11, 66},
+ dictWord{7, 11, 1980},
+ dictWord{10, 11, 487},
+ dictWord{
+ 10,
+ 11,
+ 809,
+ },
+ dictWord{146, 11, 9},
+ dictWord{5, 0, 89},
+ dictWord{7, 0, 1915},
+ dictWord{9, 0, 185},
+ dictWord{9, 0, 235},
+ dictWord{10, 0, 64},
+ dictWord{10, 0, 270},
+ dictWord{10, 0, 403},
+ dictWord{10, 0, 469},
+ dictWord{10, 0, 529},
+ dictWord{10, 0, 590},
+ dictWord{11, 0, 140},
+ dictWord{11, 0, 860},
+ dictWord{13, 0, 1},
+ dictWord{
+ 13,
+ 0,
+ 422,
+ },
+ dictWord{14, 0, 341},
+ dictWord{14, 0, 364},
+ dictWord{17, 0, 93},
+ dictWord{18, 0, 113},
+ dictWord{19, 0, 97},
+ dictWord{147, 0, 113},
+ dictWord{133, 0, 695},
+ dictWord{6, 0, 987},
+ dictWord{134, 0, 1160},
+ dictWord{5, 0, 6},
+ dictWord{6, 0, 183},
+ dictWord{7, 0, 680},
+ dictWord{7, 0, 978},
+ dictWord{7, 0, 1013},
+ dictWord{
+ 7,
+ 0,
+ 1055,
+ },
+ dictWord{12, 0, 230},
+ dictWord{13, 0, 172},
+ dictWord{146, 0, 29},
+ dictWord{134, 11, 570},
+ dictWord{132, 11, 787},
+ dictWord{134, 11, 518},
+ dictWord{
+ 6,
+ 0,
+ 29,
+ },
+ dictWord{139, 0, 63},
+ dictWord{132, 11, 516},
+ dictWord{136, 11, 821},
+ dictWord{132, 0, 311},
+ dictWord{134, 0, 1740},
+ dictWord{7, 0, 170},
+ dictWord{8, 0, 90},
+ dictWord{8, 0, 177},
+ dictWord{8, 0, 415},
+ dictWord{11, 0, 714},
+ dictWord{14, 0, 281},
+ dictWord{136, 10, 735},
+ dictWord{134, 0, 1961},
+ dictWord{
+ 135,
+ 11,
+ 1405,
+ },
+ dictWord{4, 11, 10},
+ dictWord{7, 11, 917},
+ dictWord{139, 11, 786},
+ dictWord{5, 10, 132},
+ dictWord{9, 10, 486},
+ dictWord{9, 10, 715},
+ dictWord{
+ 10,
+ 10,
+ 458,
+ },
+ dictWord{11, 10, 373},
+ dictWord{11, 10, 668},
+ dictWord{11, 10, 795},
+ dictWord{11, 10, 897},
+ dictWord{12, 10, 272},
+ dictWord{12, 10, 424},
+ dictWord{12, 10, 539},
+ dictWord{12, 10, 558},
+ dictWord{14, 10, 245},
+ dictWord{14, 10, 263},
+ dictWord{14, 10, 264},
+ dictWord{14, 10, 393},
+ dictWord{
+ 142,
+ 10,
+ 403,
+ },
+ dictWord{11, 0, 91},
+ dictWord{13, 0, 129},
+ dictWord{15, 0, 101},
+ dictWord{145, 0, 125},
+ dictWord{135, 0, 1132},
+ dictWord{4, 0, 494},
+ dictWord{6, 0, 74},
+ dictWord{7, 0, 44},
+ dictWord{7, 0, 407},
+ dictWord{12, 0, 17},
+ dictWord{15, 0, 5},
+ dictWord{148, 0, 11},
+ dictWord{133, 10, 379},
+ dictWord{5, 0, 270},
+ dictWord{
+ 5,
+ 11,
+ 684,
+ },
+ dictWord{6, 10, 89},
+ dictWord{6, 10, 400},
+ dictWord{7, 10, 1569},
+ dictWord{7, 10, 1623},
+ dictWord{7, 10, 1850},
+ dictWord{8, 10, 218},
+ dictWord{
+ 8,
+ 10,
+ 422,
+ },
+ dictWord{9, 10, 570},
+ dictWord{138, 10, 626},
+ dictWord{4, 0, 276},
+ dictWord{133, 0, 296},
+ dictWord{6, 0, 1523},
+ dictWord{134, 11, 27},
+ dictWord{
+ 6,
+ 10,
+ 387,
+ },
+ dictWord{7, 10, 882},
+ dictWord{141, 10, 111},
+ dictWord{6, 10, 224},
+ dictWord{7, 10, 877},
+ dictWord{137, 10, 647},
+ dictWord{135, 10, 790},
+ dictWord{
+ 4,
+ 0,
+ 7,
+ },
+ dictWord{5, 0, 90},
+ dictWord{5, 0, 158},
+ dictWord{6, 0, 542},
+ dictWord{7, 0, 221},
+ dictWord{7, 0, 1574},
+ dictWord{9, 0, 490},
+ dictWord{10, 0, 540},
+ dictWord{
+ 11,
+ 0,
+ 443,
+ },
+ dictWord{139, 0, 757},
+ dictWord{7, 0, 588},
+ dictWord{9, 0, 175},
+ dictWord{138, 0, 530},
+ dictWord{135, 10, 394},
+ dictWord{142, 11, 23},
+ dictWord{
+ 134,
+ 0,
+ 786,
+ },
+ dictWord{135, 0, 580},
+ dictWord{7, 0, 88},
+ dictWord{136, 0, 627},
+ dictWord{5, 0, 872},
+ dictWord{6, 0, 57},
+ dictWord{7, 0, 471},
+ dictWord{9, 0, 447},
+ dictWord{137, 0, 454},
+ dictWord{6, 11, 342},
+ dictWord{6, 11, 496},
+ dictWord{8, 11, 275},
+ dictWord{137, 11, 206},
+ dictWord{4, 11, 909},
+ dictWord{133, 11, 940},
+ dictWord{6, 0, 735},
+ dictWord{132, 11, 891},
+ dictWord{8, 0, 845},
+ dictWord{8, 0, 916},
+ dictWord{135, 10, 1409},
+ dictWord{5, 0, 31},
+ dictWord{134, 0, 614},
+ dictWord{11, 0, 458},
+ dictWord{12, 0, 15},
+ dictWord{140, 0, 432},
+ dictWord{8, 0, 330},
+ dictWord{140, 0, 477},
+ dictWord{4, 0, 530},
+ dictWord{5, 0, 521},
+ dictWord{
+ 7,
+ 0,
+ 1200,
+ },
+ dictWord{10, 0, 460},
+ dictWord{132, 11, 687},
+ dictWord{6, 0, 424},
+ dictWord{135, 0, 1866},
+ dictWord{9, 0, 569},
+ dictWord{12, 0, 12},
+ dictWord{
+ 12,
+ 0,
+ 81,
+ },
+ dictWord{12, 0, 319},
+ dictWord{13, 0, 69},
+ dictWord{14, 0, 259},
+ dictWord{16, 0, 87},
+ dictWord{17, 0, 1},
+ dictWord{17, 0, 21},
+ dictWord{17, 0, 24},
+ dictWord{
+ 18,
+ 0,
+ 15,
+ },
+ dictWord{18, 0, 56},
+ dictWord{18, 0, 59},
+ dictWord{18, 0, 127},
+ dictWord{18, 0, 154},
+ dictWord{19, 0, 19},
+ dictWord{148, 0, 31},
+ dictWord{7, 0, 1302},
+ dictWord{136, 10, 38},
+ dictWord{134, 11, 253},
+ dictWord{5, 10, 261},
+ dictWord{7, 10, 78},
+ dictWord{7, 10, 199},
+ dictWord{8, 10, 815},
+ dictWord{9, 10, 126},
+ dictWord{138, 10, 342},
+ dictWord{5, 0, 595},
+ dictWord{135, 0, 1863},
+ dictWord{6, 11, 41},
+ dictWord{141, 11, 160},
+ dictWord{5, 0, 13},
+ dictWord{134, 0, 142},
+ dictWord{6, 0, 97},
+ dictWord{7, 0, 116},
+ dictWord{8, 0, 322},
+ dictWord{8, 0, 755},
+ dictWord{9, 0, 548},
+ dictWord{10, 0, 714},
+ dictWord{11, 0, 884},
+ dictWord{13, 0, 324},
+ dictWord{7, 11, 1304},
+ dictWord{138, 11, 477},
+ dictWord{132, 10, 628},
+ dictWord{134, 11, 1718},
+ dictWord{7, 10, 266},
+ dictWord{136, 10, 804},
+ dictWord{135, 10, 208},
+ dictWord{7, 0, 1021},
+ dictWord{6, 10, 79},
+ dictWord{135, 10, 1519},
+ dictWord{7, 0, 1472},
+ dictWord{135, 0, 1554},
+ dictWord{6, 11, 362},
+ dictWord{146, 11, 51},
+ dictWord{7, 0, 1071},
+ dictWord{7, 0, 1541},
+ dictWord{7, 0, 1767},
+ dictWord{7, 0, 1806},
+ dictWord{11, 0, 162},
+ dictWord{11, 0, 242},
+ dictWord{11, 0, 452},
+ dictWord{12, 0, 605},
+ dictWord{15, 0, 26},
+ dictWord{144, 0, 44},
+ dictWord{136, 10, 741},
+ dictWord{133, 11, 115},
+ dictWord{145, 0, 115},
+ dictWord{134, 10, 376},
+ dictWord{6, 0, 1406},
+ dictWord{134, 0, 1543},
+ dictWord{5, 11, 193},
+ dictWord{12, 11, 178},
+ dictWord{13, 11, 130},
+ dictWord{
+ 145,
+ 11,
+ 84,
+ },
+ dictWord{135, 0, 1111},
+ dictWord{8, 0, 1},
+ dictWord{9, 0, 650},
+ dictWord{10, 0, 326},
+ dictWord{5, 11, 705},
+ dictWord{137, 11, 606},
+ dictWord{5, 0, 488},
+ dictWord{6, 0, 527},
+ dictWord{7, 0, 489},
+ dictWord{7, 0, 1636},
+ dictWord{8, 0, 121},
+ dictWord{8, 0, 144},
+ dictWord{8, 0, 359},
+ dictWord{9, 0, 193},
+ dictWord{9, 0, 241},
+ dictWord{9, 0, 336},
+ dictWord{9, 0, 882},
+ dictWord{11, 0, 266},
+ dictWord{11, 0, 372},
+ dictWord{11, 0, 944},
+ dictWord{12, 0, 401},
+ dictWord{140, 0, 641},
+ dictWord{135, 11, 174},
+ dictWord{6, 0, 267},
+ dictWord{7, 10, 244},
+ dictWord{7, 10, 632},
+ dictWord{7, 10, 1609},
+ dictWord{8, 10, 178},
+ dictWord{8, 10, 638},
+ dictWord{141, 10, 58},
+ dictWord{134, 0, 1983},
+ dictWord{134, 0, 1155},
+ dictWord{134, 0, 1575},
+ dictWord{134, 0, 1438},
+ dictWord{9, 0, 31},
+ dictWord{
+ 10,
+ 0,
+ 244,
+ },
+ dictWord{10, 0, 699},
+ dictWord{12, 0, 149},
+ dictWord{141, 0, 497},
+ dictWord{133, 0, 377},
+ dictWord{4, 11, 122},
+ dictWord{5, 11, 796},
+ dictWord{
+ 5,
+ 11,
+ 952,
+ },
+ dictWord{6, 11, 1660},
+ dictWord{6, 11, 1671},
+ dictWord{8, 11, 567},
+ dictWord{9, 11, 687},
+ dictWord{9, 11, 742},
+ dictWord{10, 11, 686},
+ dictWord{
+ 11,
+ 11,
+ 356,
+ },
+ dictWord{11, 11, 682},
+ dictWord{140, 11, 281},
+ dictWord{145, 0, 101},
+ dictWord{11, 11, 0},
+ dictWord{144, 11, 78},
+ dictWord{5, 11, 179},
+ dictWord{
+ 5,
+ 10,
+ 791,
+ },
+ dictWord{7, 11, 1095},
+ dictWord{135, 11, 1213},
+ dictWord{8, 11, 372},
+ dictWord{9, 11, 122},
+ dictWord{138, 11, 175},
+ dictWord{7, 10, 686},
+ dictWord{8, 10, 33},
+ dictWord{8, 10, 238},
+ dictWord{10, 10, 616},
+ dictWord{11, 10, 467},
+ dictWord{11, 10, 881},
+ dictWord{13, 10, 217},
+ dictWord{13, 10, 253},
+ dictWord{142, 10, 268},
+ dictWord{9, 0, 476},
+ dictWord{4, 11, 66},
+ dictWord{7, 11, 722},
+ dictWord{135, 11, 904},
+ dictWord{7, 11, 352},
+ dictWord{137, 11, 684},
+ dictWord{135, 0, 2023},
+ dictWord{135, 0, 1836},
+ dictWord{132, 10, 447},
+ dictWord{5, 0, 843},
+ dictWord{144, 0, 35},
+ dictWord{137, 11, 779},
+ dictWord{
+ 141,
+ 11,
+ 35,
+ },
+ dictWord{4, 10, 128},
+ dictWord{5, 10, 415},
+ dictWord{6, 10, 462},
+ dictWord{7, 10, 294},
+ dictWord{7, 10, 578},
+ dictWord{10, 10, 710},
+ dictWord{
+ 139,
+ 10,
+ 86,
+ },
+ dictWord{132, 0, 554},
+ dictWord{133, 0, 536},
+ dictWord{136, 10, 587},
+ dictWord{5, 0, 207},
+ dictWord{9, 0, 79},
+ dictWord{11, 0, 625},
+ dictWord{
+ 145,
+ 0,
+ 7,
+ },
+ dictWord{7, 0, 1371},
+ dictWord{6, 10, 427},
+ dictWord{138, 10, 692},
+ dictWord{4, 0, 424},
+ dictWord{4, 10, 195},
+ dictWord{135, 10, 802},
+ dictWord{
+ 8,
+ 0,
+ 785,
+ },
+ dictWord{133, 11, 564},
+ dictWord{135, 0, 336},
+ dictWord{4, 0, 896},
+ dictWord{6, 0, 1777},
+ dictWord{134, 11, 556},
+ dictWord{137, 11, 103},
+ dictWord{134, 10, 1683},
+ dictWord{7, 11, 544},
+ dictWord{8, 11, 719},
+ dictWord{138, 11, 61},
+ dictWord{138, 10, 472},
+ dictWord{4, 11, 5},
+ dictWord{5, 11, 498},
+ dictWord{136, 11, 637},
+ dictWord{7, 0, 750},
+ dictWord{9, 0, 223},
+ dictWord{11, 0, 27},
+ dictWord{11, 0, 466},
+ dictWord{12, 0, 624},
+ dictWord{14, 0, 265},
+ dictWord{
+ 146,
+ 0,
+ 61,
+ },
+ dictWord{12, 0, 238},
+ dictWord{18, 0, 155},
+ dictWord{12, 11, 238},
+ dictWord{146, 11, 155},
+ dictWord{151, 10, 28},
+ dictWord{133, 11, 927},
+ dictWord{12, 0, 383},
+ dictWord{5, 10, 3},
+ dictWord{8, 10, 578},
+ dictWord{9, 10, 118},
+ dictWord{10, 10, 705},
+ dictWord{141, 10, 279},
+ dictWord{4, 11, 893},
+ dictWord{
+ 5,
+ 11,
+ 780,
+ },
+ dictWord{133, 11, 893},
+ dictWord{4, 0, 603},
+ dictWord{133, 0, 661},
+ dictWord{4, 0, 11},
+ dictWord{6, 0, 128},
+ dictWord{7, 0, 231},
+ dictWord{
+ 7,
+ 0,
+ 1533,
+ },
+ dictWord{10, 0, 725},
+ dictWord{5, 10, 229},
+ dictWord{5, 11, 238},
+ dictWord{135, 11, 1350},
+ dictWord{8, 10, 102},
+ dictWord{10, 10, 578},
+ dictWord{
+ 10,
+ 10,
+ 672,
+ },
+ dictWord{12, 10, 496},
+ dictWord{13, 10, 408},
+ dictWord{14, 10, 121},
+ dictWord{145, 10, 106},
+ dictWord{132, 0, 476},
+ dictWord{134, 0, 1552},
+ dictWord{134, 11, 1729},
+ dictWord{8, 10, 115},
+ dictWord{8, 10, 350},
+ dictWord{9, 10, 489},
+ dictWord{10, 10, 128},
+ dictWord{11, 10, 306},
+ dictWord{
+ 12,
+ 10,
+ 373,
+ },
+ dictWord{14, 10, 30},
+ dictWord{17, 10, 79},
+ dictWord{19, 10, 80},
+ dictWord{150, 10, 55},
+ dictWord{135, 0, 1807},
+ dictWord{4, 0, 680},
+ dictWord{
+ 4,
+ 11,
+ 60,
+ },
+ dictWord{7, 11, 760},
+ dictWord{7, 11, 1800},
+ dictWord{8, 11, 314},
+ dictWord{9, 11, 700},
+ dictWord{139, 11, 487},
+ dictWord{4, 10, 230},
+ dictWord{
+ 5,
+ 10,
+ 702,
+ },
+ dictWord{148, 11, 94},
+ dictWord{132, 11, 228},
+ dictWord{139, 0, 435},
+ dictWord{9, 0, 20},
+ dictWord{10, 0, 324},
+ dictWord{10, 0, 807},
+ dictWord{
+ 139,
+ 0,
+ 488,
+ },
+ dictWord{6, 10, 1728},
+ dictWord{136, 11, 419},
+ dictWord{4, 10, 484},
+ dictWord{18, 10, 26},
+ dictWord{19, 10, 42},
+ dictWord{20, 10, 43},
+ dictWord{
+ 21,
+ 10,
+ 0,
+ },
+ dictWord{23, 10, 27},
+ dictWord{152, 10, 14},
+ dictWord{135, 0, 1431},
+ dictWord{133, 11, 828},
+ dictWord{5, 0, 112},
+ dictWord{6, 0, 103},
+ dictWord{
+ 6,
+ 0,
+ 150,
+ },
+ dictWord{7, 0, 1303},
+ dictWord{9, 0, 292},
+ dictWord{10, 0, 481},
+ dictWord{20, 0, 13},
+ dictWord{7, 11, 176},
+ dictWord{7, 11, 178},
+ dictWord{7, 11, 1110},
+ dictWord{10, 11, 481},
+ dictWord{148, 11, 13},
+ dictWord{138, 0, 356},
+ dictWord{4, 11, 51},
+ dictWord{5, 11, 39},
+ dictWord{6, 11, 4},
+ dictWord{7, 11, 591},
+ dictWord{
+ 7,
+ 11,
+ 849,
+ },
+ dictWord{7, 11, 951},
+ dictWord{7, 11, 1129},
+ dictWord{7, 11, 1613},
+ dictWord{7, 11, 1760},
+ dictWord{7, 11, 1988},
+ dictWord{9, 11, 434},
+ dictWord{10, 11, 754},
+ dictWord{11, 11, 25},
+ dictWord{11, 11, 37},
+ dictWord{139, 11, 414},
+ dictWord{6, 0, 1963},
+ dictWord{134, 0, 2000},
+ dictWord{
+ 132,
+ 10,
+ 633,
+ },
+ dictWord{6, 0, 1244},
+ dictWord{133, 11, 902},
+ dictWord{135, 11, 928},
+ dictWord{140, 0, 18},
+ dictWord{138, 0, 204},
+ dictWord{135, 11, 1173},
+ dictWord{134, 0, 867},
+ dictWord{4, 0, 708},
+ dictWord{8, 0, 15},
+ dictWord{9, 0, 50},
+ dictWord{9, 0, 386},
+ dictWord{11, 0, 18},
+ dictWord{11, 0, 529},
+ dictWord{140, 0, 228},
+ dictWord{134, 11, 270},
+ dictWord{4, 0, 563},
+ dictWord{7, 0, 109},
+ dictWord{7, 0, 592},
+ dictWord{7, 0, 637},
+ dictWord{7, 0, 770},
+ dictWord{8, 0, 463},
+ dictWord{
+ 9,
+ 0,
+ 60,
+ },
+ dictWord{9, 0, 335},
+ dictWord{9, 0, 904},
+ dictWord{10, 0, 73},
+ dictWord{11, 0, 434},
+ dictWord{12, 0, 585},
+ dictWord{13, 0, 331},
+ dictWord{18, 0, 110},
+ dictWord{148, 0, 60},
+ dictWord{132, 0, 502},
+ dictWord{14, 11, 359},
+ dictWord{19, 11, 52},
+ dictWord{148, 11, 47},
+ dictWord{6, 11, 377},
+ dictWord{7, 11, 1025},
+ dictWord{9, 11, 613},
+ dictWord{145, 11, 104},
+ dictWord{6, 0, 347},
+ dictWord{10, 0, 161},
+ dictWord{5, 10, 70},
+ dictWord{5, 10, 622},
+ dictWord{6, 10, 334},
+ dictWord{
+ 7,
+ 10,
+ 1032,
+ },
+ dictWord{9, 10, 171},
+ dictWord{11, 10, 26},
+ dictWord{11, 10, 213},
+ dictWord{11, 10, 637},
+ dictWord{11, 10, 707},
+ dictWord{12, 10, 202},
+ dictWord{12, 10, 380},
+ dictWord{13, 10, 226},
+ dictWord{13, 10, 355},
+ dictWord{14, 10, 222},
+ dictWord{145, 10, 42},
+ dictWord{132, 11, 416},
+ dictWord{4, 0, 33},
+ dictWord{5, 0, 102},
+ dictWord{6, 0, 284},
+ dictWord{7, 0, 1079},
+ dictWord{7, 0, 1423},
+ dictWord{7, 0, 1702},
+ dictWord{8, 0, 470},
+ dictWord{9, 0, 554},
+ dictWord{
+ 9,
+ 0,
+ 723,
+ },
+ dictWord{11, 0, 333},
+ dictWord{142, 11, 372},
+ dictWord{5, 11, 152},
+ dictWord{5, 11, 197},
+ dictWord{7, 11, 340},
+ dictWord{7, 11, 867},
+ dictWord{
+ 10,
+ 11,
+ 548,
+ },
+ dictWord{10, 11, 581},
+ dictWord{11, 11, 6},
+ dictWord{12, 11, 3},
+ dictWord{12, 11, 19},
+ dictWord{14, 11, 110},
+ dictWord{142, 11, 289},
+ dictWord{
+ 7,
+ 0,
+ 246,
+ },
+ dictWord{135, 0, 840},
+ dictWord{6, 0, 10},
+ dictWord{8, 0, 571},
+ dictWord{9, 0, 739},
+ dictWord{143, 0, 91},
+ dictWord{6, 0, 465},
+ dictWord{7, 0, 1465},
+ dictWord{
+ 4,
+ 10,
+ 23,
+ },
+ dictWord{4, 10, 141},
+ dictWord{5, 10, 313},
+ dictWord{5, 10, 1014},
+ dictWord{6, 10, 50},
+ dictWord{7, 10, 142},
+ dictWord{7, 10, 559},
+ dictWord{
+ 8,
+ 10,
+ 640,
+ },
+ dictWord{9, 10, 460},
+ dictWord{9, 10, 783},
+ dictWord{11, 10, 741},
+ dictWord{12, 10, 183},
+ dictWord{141, 10, 488},
+ dictWord{133, 0, 626},
+ dictWord{
+ 136,
+ 0,
+ 614,
+ },
+ dictWord{138, 0, 237},
+ dictWord{7, 11, 34},
+ dictWord{7, 11, 190},
+ dictWord{8, 11, 28},
+ dictWord{8, 11, 141},
+ dictWord{8, 11, 444},
+ dictWord{
+ 8,
+ 11,
+ 811,
+ },
+ dictWord{9, 11, 468},
+ dictWord{11, 11, 334},
+ dictWord{12, 11, 24},
+ dictWord{12, 11, 386},
+ dictWord{140, 11, 576},
+ dictWord{133, 11, 757},
+ dictWord{
+ 5,
+ 0,
+ 18,
+ },
+ dictWord{6, 0, 526},
+ dictWord{13, 0, 24},
+ dictWord{13, 0, 110},
+ dictWord{19, 0, 5},
+ dictWord{147, 0, 44},
+ dictWord{6, 0, 506},
+ dictWord{134, 11, 506},
+ dictWord{135, 11, 1553},
+ dictWord{4, 0, 309},
+ dictWord{5, 0, 462},
+ dictWord{7, 0, 970},
+ dictWord{7, 0, 1097},
+ dictWord{22, 0, 30},
+ dictWord{22, 0, 33},
+ dictWord{
+ 7,
+ 11,
+ 1385,
+ },
+ dictWord{11, 11, 582},
+ dictWord{11, 11, 650},
+ dictWord{11, 11, 901},
+ dictWord{11, 11, 949},
+ dictWord{12, 11, 232},
+ dictWord{12, 11, 236},
+ dictWord{13, 11, 413},
+ dictWord{13, 11, 501},
+ dictWord{146, 11, 116},
+ dictWord{9, 0, 140},
+ dictWord{5, 10, 222},
+ dictWord{138, 10, 534},
+ dictWord{6, 0, 1056},
+ dictWord{137, 10, 906},
+ dictWord{134, 0, 1704},
+ dictWord{138, 10, 503},
+ dictWord{134, 0, 1036},
+ dictWord{5, 10, 154},
+ dictWord{7, 10, 1491},
+ dictWord{
+ 10,
+ 10,
+ 379,
+ },
+ dictWord{138, 10, 485},
+ dictWord{4, 11, 383},
+ dictWord{133, 10, 716},
+ dictWord{134, 0, 1315},
+ dictWord{5, 0, 86},
+ dictWord{7, 0, 743},
+ dictWord{
+ 9,
+ 0,
+ 85,
+ },
+ dictWord{10, 0, 281},
+ dictWord{10, 0, 432},
+ dictWord{11, 0, 825},
+ dictWord{12, 0, 251},
+ dictWord{13, 0, 118},
+ dictWord{142, 0, 378},
+ dictWord{
+ 8,
+ 0,
+ 264,
+ },
+ dictWord{4, 10, 91},
+ dictWord{5, 10, 388},
+ dictWord{5, 10, 845},
+ dictWord{6, 10, 206},
+ dictWord{6, 10, 252},
+ dictWord{6, 10, 365},
+ dictWord{7, 10, 136},
+ dictWord{7, 10, 531},
+ dictWord{136, 10, 621},
+ dictWord{5, 0, 524},
+ dictWord{133, 0, 744},
+ dictWord{5, 11, 277},
+ dictWord{141, 11, 247},
+ dictWord{
+ 132,
+ 11,
+ 435,
+ },
+ dictWord{10, 0, 107},
+ dictWord{140, 0, 436},
+ dictWord{132, 0, 927},
+ dictWord{10, 0, 123},
+ dictWord{12, 0, 670},
+ dictWord{146, 0, 94},
+ dictWord{
+ 7,
+ 0,
+ 1149,
+ },
+ dictWord{9, 0, 156},
+ dictWord{138, 0, 957},
+ dictWord{5, 11, 265},
+ dictWord{6, 11, 212},
+ dictWord{135, 11, 28},
+ dictWord{133, 0, 778},
+ dictWord{
+ 133,
+ 0,
+ 502,
+ },
+ dictWord{8, 0, 196},
+ dictWord{10, 0, 283},
+ dictWord{139, 0, 406},
+ dictWord{135, 10, 576},
+ dictWord{136, 11, 535},
+ dictWord{134, 0, 1312},
+ dictWord{
+ 5,
+ 10,
+ 771,
+ },
+ dictWord{5, 10, 863},
+ dictWord{5, 10, 898},
+ dictWord{6, 10, 1632},
+ dictWord{6, 10, 1644},
+ dictWord{134, 10, 1780},
+ dictWord{5, 0, 855},
+ dictWord{5, 10, 331},
+ dictWord{135, 11, 1487},
+ dictWord{132, 11, 702},
+ dictWord{5, 11, 808},
+ dictWord{135, 11, 2045},
+ dictWord{7, 0, 1400},
+ dictWord{
+ 9,
+ 0,
+ 446,
+ },
+ dictWord{138, 0, 45},
+ dictWord{140, 10, 632},
+ dictWord{132, 0, 1003},
+ dictWord{5, 11, 166},
+ dictWord{8, 11, 739},
+ dictWord{140, 11, 511},
+ dictWord{
+ 5,
+ 10,
+ 107,
+ },
+ dictWord{7, 10, 201},
+ dictWord{136, 10, 518},
+ dictWord{6, 10, 446},
+ dictWord{135, 10, 1817},
+ dictWord{134, 0, 1532},
+ dictWord{
+ 134,
+ 0,
+ 1097,
+ },
+ dictWord{4, 11, 119},
+ dictWord{5, 11, 170},
+ dictWord{5, 11, 447},
+ dictWord{7, 11, 1708},
+ dictWord{7, 11, 1889},
+ dictWord{9, 11, 357},
+ dictWord{
+ 9,
+ 11,
+ 719,
+ },
+ dictWord{12, 11, 486},
+ dictWord{140, 11, 596},
+ dictWord{9, 10, 851},
+ dictWord{141, 10, 510},
+ dictWord{7, 0, 612},
+ dictWord{8, 0, 545},
+ dictWord{
+ 8,
+ 0,
+ 568,
+ },
+ dictWord{8, 0, 642},
+ dictWord{9, 0, 717},
+ dictWord{10, 0, 541},
+ dictWord{10, 0, 763},
+ dictWord{11, 0, 449},
+ dictWord{12, 0, 489},
+ dictWord{13, 0, 153},
+ dictWord{13, 0, 296},
+ dictWord{14, 0, 138},
+ dictWord{14, 0, 392},
+ dictWord{15, 0, 50},
+ dictWord{16, 0, 6},
+ dictWord{16, 0, 12},
+ dictWord{20, 0, 9},
+ dictWord{
+ 132,
+ 10,
+ 504,
+ },
+ dictWord{4, 11, 450},
+ dictWord{135, 11, 1158},
+ dictWord{11, 0, 54},
+ dictWord{13, 0, 173},
+ dictWord{13, 0, 294},
+ dictWord{5, 10, 883},
+ dictWord{
+ 5,
+ 10,
+ 975,
+ },
+ dictWord{8, 10, 392},
+ dictWord{148, 10, 7},
+ dictWord{13, 0, 455},
+ dictWord{15, 0, 99},
+ dictWord{15, 0, 129},
+ dictWord{144, 0, 68},
+ dictWord{135, 0, 172},
+ dictWord{132, 11, 754},
+ dictWord{5, 10, 922},
+ dictWord{134, 10, 1707},
+ dictWord{134, 0, 1029},
+ dictWord{17, 11, 39},
+ dictWord{148, 11, 36},
+ dictWord{
+ 4,
+ 0,
+ 568,
+ },
+ dictWord{5, 10, 993},
+ dictWord{7, 10, 515},
+ dictWord{137, 10, 91},
+ dictWord{132, 0, 732},
+ dictWord{10, 0, 617},
+ dictWord{138, 11, 617},
+ dictWord{
+ 134,
+ 0,
+ 974,
+ },
+ dictWord{7, 0, 989},
+ dictWord{10, 0, 377},
+ dictWord{12, 0, 363},
+ dictWord{13, 0, 68},
+ dictWord{13, 0, 94},
+ dictWord{14, 0, 108},
+ dictWord{
+ 142,
+ 0,
+ 306,
+ },
+ dictWord{136, 0, 733},
+ dictWord{132, 0, 428},
+ dictWord{7, 0, 1789},
+ dictWord{135, 11, 1062},
+ dictWord{7, 0, 2015},
+ dictWord{140, 0, 665},
+ dictWord{135, 10, 1433},
+ dictWord{5, 0, 287},
+ dictWord{7, 10, 921},
+ dictWord{8, 10, 580},
+ dictWord{8, 10, 593},
+ dictWord{8, 10, 630},
+ dictWord{138, 10, 28},
+ dictWord{138, 0, 806},
+ dictWord{4, 10, 911},
+ dictWord{5, 10, 867},
+ dictWord{5, 10, 1013},
+ dictWord{7, 10, 2034},
+ dictWord{8, 10, 798},
+ dictWord{136, 10, 813},
+ dictWord{134, 0, 1539},
+ dictWord{8, 11, 523},
+ dictWord{150, 11, 34},
+ dictWord{135, 11, 740},
+ dictWord{7, 11, 238},
+ dictWord{7, 11, 2033},
+ dictWord{
+ 8,
+ 11,
+ 120,
+ },
+ dictWord{8, 11, 188},
+ dictWord{8, 11, 659},
+ dictWord{9, 11, 598},
+ dictWord{10, 11, 466},
+ dictWord{12, 11, 342},
+ dictWord{12, 11, 588},
+ dictWord{
+ 13,
+ 11,
+ 503,
+ },
+ dictWord{14, 11, 246},
+ dictWord{143, 11, 92},
+ dictWord{7, 0, 1563},
+ dictWord{141, 0, 182},
+ dictWord{5, 10, 135},
+ dictWord{6, 10, 519},
+ dictWord{
+ 7,
+ 10,
+ 1722,
+ },
+ dictWord{10, 10, 271},
+ dictWord{11, 10, 261},
+ dictWord{145, 10, 54},
+ dictWord{14, 10, 338},
+ dictWord{148, 10, 81},
+ dictWord{7, 0, 484},
+ dictWord{
+ 4,
+ 10,
+ 300,
+ },
+ dictWord{133, 10, 436},
+ dictWord{145, 11, 114},
+ dictWord{6, 0, 1623},
+ dictWord{134, 0, 1681},
+ dictWord{133, 11, 640},
+ dictWord{4, 11, 201},
+ dictWord{7, 11, 1744},
+ dictWord{8, 11, 602},
+ dictWord{11, 11, 247},
+ dictWord{11, 11, 826},
+ dictWord{145, 11, 65},
+ dictWord{8, 11, 164},
+ dictWord{
+ 146,
+ 11,
+ 62,
+ },
+ dictWord{6, 0, 1833},
+ dictWord{6, 0, 1861},
+ dictWord{136, 0, 878},
+ dictWord{134, 0, 1569},
+ dictWord{8, 10, 357},
+ dictWord{10, 10, 745},
+ dictWord{
+ 14,
+ 10,
+ 426,
+ },
+ dictWord{17, 10, 94},
+ dictWord{147, 10, 57},
+ dictWord{12, 0, 93},
+ dictWord{12, 0, 501},
+ dictWord{13, 0, 362},
+ dictWord{14, 0, 151},
+ dictWord{15, 0, 40},
+ dictWord{15, 0, 59},
+ dictWord{16, 0, 46},
+ dictWord{17, 0, 25},
+ dictWord{18, 0, 14},
+ dictWord{18, 0, 134},
+ dictWord{19, 0, 25},
+ dictWord{19, 0, 69},
+ dictWord{
+ 20,
+ 0,
+ 16,
+ },
+ dictWord{20, 0, 19},
+ dictWord{20, 0, 66},
+ dictWord{21, 0, 23},
+ dictWord{21, 0, 25},
+ dictWord{150, 0, 42},
+ dictWord{6, 0, 1748},
+ dictWord{8, 0, 715},
+ dictWord{
+ 9,
+ 0,
+ 802,
+ },
+ dictWord{10, 0, 46},
+ dictWord{10, 0, 819},
+ dictWord{13, 0, 308},
+ dictWord{14, 0, 351},
+ dictWord{14, 0, 363},
+ dictWord{146, 0, 67},
+ dictWord{
+ 132,
+ 0,
+ 994,
+ },
+ dictWord{4, 0, 63},
+ dictWord{133, 0, 347},
+ dictWord{132, 0, 591},
+ dictWord{133, 0, 749},
+ dictWord{7, 11, 1577},
+ dictWord{10, 11, 304},
+ dictWord{
+ 10,
+ 11,
+ 549,
+ },
+ dictWord{11, 11, 424},
+ dictWord{12, 11, 365},
+ dictWord{13, 11, 220},
+ dictWord{13, 11, 240},
+ dictWord{142, 11, 33},
+ dictWord{133, 0, 366},
+ dictWord{
+ 7,
+ 0,
+ 557,
+ },
+ dictWord{12, 0, 547},
+ dictWord{14, 0, 86},
+ dictWord{133, 10, 387},
+ dictWord{135, 0, 1747},
+ dictWord{132, 11, 907},
+ dictWord{5, 11, 100},
+ dictWord{10, 11, 329},
+ dictWord{12, 11, 416},
+ dictWord{149, 11, 29},
+ dictWord{4, 10, 6},
+ dictWord{5, 10, 708},
+ dictWord{136, 10, 75},
+ dictWord{7, 10, 1351},
+ dictWord{9, 10, 581},
+ dictWord{10, 10, 639},
+ dictWord{11, 10, 453},
+ dictWord{140, 10, 584},
+ dictWord{7, 0, 89},
+ dictWord{132, 10, 303},
+ dictWord{138, 10, 772},
+ dictWord{132, 11, 176},
+ dictWord{5, 11, 636},
+ dictWord{5, 11, 998},
+ dictWord{8, 11, 26},
+ dictWord{137, 11, 358},
+ dictWord{7, 11, 9},
+ dictWord{7, 11, 1508},
+ dictWord{9, 11, 317},
+ dictWord{10, 11, 210},
+ dictWord{10, 11, 292},
+ dictWord{10, 11, 533},
+ dictWord{11, 11, 555},
+ dictWord{12, 11, 526},
+ dictWord{
+ 12,
+ 11,
+ 607,
+ },
+ dictWord{13, 11, 263},
+ dictWord{13, 11, 459},
+ dictWord{142, 11, 271},
+ dictWord{134, 0, 1463},
+ dictWord{6, 0, 772},
+ dictWord{6, 0, 1137},
+ dictWord{
+ 139,
+ 11,
+ 595,
+ },
+ dictWord{7, 0, 977},
+ dictWord{139, 11, 66},
+ dictWord{138, 0, 893},
+ dictWord{20, 0, 48},
+ dictWord{148, 11, 48},
+ dictWord{5, 0, 824},
+ dictWord{
+ 133,
+ 0,
+ 941,
+ },
+ dictWord{134, 11, 295},
+ dictWord{7, 0, 1543},
+ dictWord{7, 0, 1785},
+ dictWord{10, 0, 690},
+ dictWord{4, 10, 106},
+ dictWord{139, 10, 717},
+ dictWord{
+ 7,
+ 0,
+ 440,
+ },
+ dictWord{8, 0, 230},
+ dictWord{139, 0, 106},
+ dictWord{5, 10, 890},
+ dictWord{133, 10, 988},
+ dictWord{6, 10, 626},
+ dictWord{142, 10, 431},
+ dictWord{
+ 10,
+ 11,
+ 127,
+ },
+ dictWord{141, 11, 27},
+ dictWord{17, 0, 32},
+ dictWord{10, 10, 706},
+ dictWord{150, 10, 44},
+ dictWord{132, 0, 216},
+ dictWord{137, 0, 332},
+ dictWord{4, 10, 698},
+ dictWord{136, 11, 119},
+ dictWord{139, 11, 267},
+ dictWord{138, 10, 17},
+ dictWord{11, 11, 526},
+ dictWord{11, 11, 939},
+ dictWord{
+ 141,
+ 11,
+ 290,
+ },
+ dictWord{7, 11, 1167},
+ dictWord{11, 11, 934},
+ dictWord{13, 11, 391},
+ dictWord{145, 11, 76},
+ dictWord{139, 11, 39},
+ dictWord{134, 10, 84},
+ dictWord{
+ 4,
+ 0,
+ 914,
+ },
+ dictWord{5, 0, 800},
+ dictWord{133, 0, 852},
+ dictWord{10, 0, 416},
+ dictWord{141, 0, 115},
+ dictWord{7, 0, 564},
+ dictWord{142, 0, 168},
+ dictWord{
+ 4,
+ 0,
+ 918,
+ },
+ dictWord{133, 0, 876},
+ dictWord{134, 0, 1764},
+ dictWord{152, 0, 3},
+ dictWord{4, 0, 92},
+ dictWord{5, 0, 274},
+ dictWord{7, 11, 126},
+ dictWord{136, 11, 84},
+ dictWord{140, 10, 498},
+ dictWord{136, 11, 790},
+ dictWord{8, 0, 501},
+ dictWord{5, 10, 986},
+ dictWord{6, 10, 130},
+ dictWord{7, 10, 1582},
+ dictWord{
+ 8,
+ 10,
+ 458,
+ },
+ dictWord{10, 10, 101},
+ dictWord{10, 10, 318},
+ dictWord{138, 10, 823},
+ dictWord{6, 11, 64},
+ dictWord{12, 11, 377},
+ dictWord{141, 11, 309},
+ dictWord{
+ 5,
+ 0,
+ 743,
+ },
+ dictWord{138, 0, 851},
+ dictWord{4, 0, 49},
+ dictWord{7, 0, 280},
+ dictWord{135, 0, 1633},
+ dictWord{134, 0, 879},
+ dictWord{136, 0, 47},
+ dictWord{
+ 7,
+ 10,
+ 1644,
+ },
+ dictWord{137, 10, 129},
+ dictWord{132, 0, 865},
+ dictWord{134, 0, 1202},
+ dictWord{9, 11, 34},
+ dictWord{139, 11, 484},
+ dictWord{135, 10, 997},
+ dictWord{5, 0, 272},
+ dictWord{5, 0, 908},
+ dictWord{5, 0, 942},
+ dictWord{8, 0, 197},
+ dictWord{9, 0, 47},
+ dictWord{11, 0, 538},
+ dictWord{139, 0, 742},
+ dictWord{
+ 6,
+ 11,
+ 1700,
+ },
+ dictWord{7, 11, 26},
+ dictWord{7, 11, 293},
+ dictWord{7, 11, 382},
+ dictWord{7, 11, 1026},
+ dictWord{7, 11, 1087},
+ dictWord{7, 11, 2027},
+ dictWord{
+ 8,
+ 11,
+ 24,
+ },
+ dictWord{8, 11, 114},
+ dictWord{8, 11, 252},
+ dictWord{8, 11, 727},
+ dictWord{8, 11, 729},
+ dictWord{9, 11, 30},
+ dictWord{9, 11, 199},
+ dictWord{9, 11, 231},
+ dictWord{9, 11, 251},
+ dictWord{9, 11, 334},
+ dictWord{9, 11, 361},
+ dictWord{9, 11, 488},
+ dictWord{9, 11, 712},
+ dictWord{10, 11, 55},
+ dictWord{10, 11, 60},
+ dictWord{
+ 10,
+ 11,
+ 232,
+ },
+ dictWord{10, 11, 332},
+ dictWord{10, 11, 384},
+ dictWord{10, 11, 396},
+ dictWord{10, 11, 504},
+ dictWord{10, 11, 542},
+ dictWord{10, 11, 652},
+ dictWord{11, 11, 20},
+ dictWord{11, 11, 48},
+ dictWord{11, 11, 207},
+ dictWord{11, 11, 291},
+ dictWord{11, 11, 298},
+ dictWord{11, 11, 342},
+ dictWord{
+ 11,
+ 11,
+ 365,
+ },
+ dictWord{11, 11, 394},
+ dictWord{11, 11, 620},
+ dictWord{11, 11, 705},
+ dictWord{11, 11, 1017},
+ dictWord{12, 11, 123},
+ dictWord{12, 11, 340},
+ dictWord{12, 11, 406},
+ dictWord{12, 11, 643},
+ dictWord{13, 11, 61},
+ dictWord{13, 11, 269},
+ dictWord{13, 11, 311},
+ dictWord{13, 11, 319},
+ dictWord{13, 11, 486},
+ dictWord{14, 11, 234},
+ dictWord{15, 11, 62},
+ dictWord{15, 11, 85},
+ dictWord{16, 11, 71},
+ dictWord{18, 11, 119},
+ dictWord{148, 11, 105},
+ dictWord{
+ 6,
+ 0,
+ 1455,
+ },
+ dictWord{150, 11, 37},
+ dictWord{135, 10, 1927},
+ dictWord{135, 0, 1911},
+ dictWord{137, 0, 891},
+ dictWord{7, 10, 1756},
+ dictWord{137, 10, 98},
+ dictWord{7, 10, 1046},
+ dictWord{139, 10, 160},
+ dictWord{132, 0, 761},
+ dictWord{6, 11, 379},
+ dictWord{7, 11, 270},
+ dictWord{7, 11, 1116},
+ dictWord{
+ 8,
+ 11,
+ 176,
+ },
+ dictWord{8, 11, 183},
+ dictWord{9, 11, 432},
+ dictWord{9, 11, 661},
+ dictWord{12, 11, 247},
+ dictWord{12, 11, 617},
+ dictWord{146, 11, 125},
+ dictWord{
+ 6,
+ 10,
+ 45,
+ },
+ dictWord{7, 10, 433},
+ dictWord{8, 10, 129},
+ dictWord{9, 10, 21},
+ dictWord{10, 10, 392},
+ dictWord{11, 10, 79},
+ dictWord{12, 10, 499},
+ dictWord{
+ 13,
+ 10,
+ 199,
+ },
+ dictWord{141, 10, 451},
+ dictWord{4, 0, 407},
+ dictWord{5, 11, 792},
+ dictWord{133, 11, 900},
+ dictWord{132, 0, 560},
+ dictWord{135, 0, 183},
+ dictWord{
+ 13,
+ 0,
+ 490,
+ },
+ dictWord{7, 10, 558},
+ dictWord{136, 10, 353},
+ dictWord{4, 0, 475},
+ dictWord{6, 0, 731},
+ dictWord{11, 0, 35},
+ dictWord{13, 0, 71},
+ dictWord{13, 0, 177},
+ dictWord{14, 0, 422},
+ dictWord{133, 10, 785},
+ dictWord{8, 10, 81},
+ dictWord{9, 10, 189},
+ dictWord{9, 10, 201},
+ dictWord{11, 10, 478},
+ dictWord{11, 10, 712},
+ dictWord{141, 10, 338},
+ dictWord{4, 0, 418},
+ dictWord{4, 0, 819},
+ dictWord{133, 10, 353},
+ dictWord{151, 10, 26},
+ dictWord{4, 11, 901},
+ dictWord{
+ 133,
+ 11,
+ 776,
+ },
+ dictWord{132, 0, 575},
+ dictWord{7, 0, 818},
+ dictWord{16, 0, 92},
+ dictWord{17, 0, 14},
+ dictWord{17, 0, 45},
+ dictWord{18, 0, 75},
+ dictWord{148, 0, 18},
+ dictWord{
+ 6,
+ 0,
+ 222,
+ },
+ dictWord{7, 0, 636},
+ dictWord{7, 0, 1620},
+ dictWord{8, 0, 409},
+ dictWord{9, 0, 693},
+ dictWord{139, 0, 77},
+ dictWord{6, 10, 25},
+ dictWord{7, 10, 855},
+ dictWord{7, 10, 1258},
+ dictWord{144, 10, 32},
+ dictWord{6, 0, 1880},
+ dictWord{6, 0, 1887},
+ dictWord{6, 0, 1918},
+ dictWord{6, 0, 1924},
+ dictWord{9, 0, 967},
+ dictWord{9, 0, 995},
+ dictWord{9, 0, 1015},
+ dictWord{12, 0, 826},
+ dictWord{12, 0, 849},
+ dictWord{12, 0, 857},
+ dictWord{12, 0, 860},
+ dictWord{12, 0, 886},
+ dictWord{
+ 12,
+ 0,
+ 932,
+ },
+ dictWord{18, 0, 228},
+ dictWord{18, 0, 231},
+ dictWord{146, 0, 240},
+ dictWord{134, 0, 633},
+ dictWord{134, 0, 1308},
+ dictWord{4, 11, 37},
+ dictWord{
+ 5,
+ 11,
+ 334,
+ },
+ dictWord{135, 11, 1253},
+ dictWord{10, 0, 86},
+ dictWord{4, 10, 4},
+ dictWord{7, 10, 1118},
+ dictWord{7, 10, 1320},
+ dictWord{7, 10, 1706},
+ dictWord{
+ 8,
+ 10,
+ 277,
+ },
+ dictWord{9, 10, 622},
+ dictWord{11, 10, 724},
+ dictWord{12, 10, 350},
+ dictWord{12, 10, 397},
+ dictWord{13, 10, 28},
+ dictWord{13, 10, 159},
+ dictWord{
+ 15,
+ 10,
+ 89,
+ },
+ dictWord{18, 10, 5},
+ dictWord{19, 10, 9},
+ dictWord{20, 10, 34},
+ dictWord{150, 10, 47},
+ dictWord{132, 11, 508},
+ dictWord{137, 11, 448},
+ dictWord{
+ 12,
+ 11,
+ 107,
+ },
+ dictWord{146, 11, 31},
+ dictWord{132, 0, 817},
+ dictWord{134, 0, 663},
+ dictWord{133, 0, 882},
+ dictWord{134, 0, 914},
+ dictWord{132, 11, 540},
+ dictWord{132, 11, 533},
+ dictWord{136, 11, 608},
+ dictWord{8, 0, 885},
+ dictWord{138, 0, 865},
+ dictWord{132, 0, 426},
+ dictWord{6, 0, 58},
+ dictWord{7, 0, 745},
+ dictWord{7, 0, 1969},
+ dictWord{8, 0, 399},
+ dictWord{8, 0, 675},
+ dictWord{9, 0, 479},
+ dictWord{9, 0, 731},
+ dictWord{10, 0, 330},
+ dictWord{10, 0, 593},
+ dictWord{
+ 10,
+ 0,
+ 817,
+ },
+ dictWord{11, 0, 32},
+ dictWord{11, 0, 133},
+ dictWord{11, 0, 221},
+ dictWord{145, 0, 68},
+ dictWord{134, 10, 255},
+ dictWord{7, 0, 102},
+ dictWord{
+ 137,
+ 0,
+ 538,
+ },
+ dictWord{137, 10, 216},
+ dictWord{7, 11, 253},
+ dictWord{136, 11, 549},
+ dictWord{135, 11, 912},
+ dictWord{9, 10, 183},
+ dictWord{139, 10, 286},
+ dictWord{11, 10, 956},
+ dictWord{151, 10, 3},
+ dictWord{8, 11, 527},
+ dictWord{18, 11, 60},
+ dictWord{147, 11, 24},
+ dictWord{4, 10, 536},
+ dictWord{7, 10, 1141},
+ dictWord{10, 10, 723},
+ dictWord{139, 10, 371},
+ dictWord{133, 11, 920},
+ dictWord{7, 0, 876},
+ dictWord{135, 10, 285},
+ dictWord{135, 10, 560},
+ dictWord{
+ 132,
+ 10,
+ 690,
+ },
+ dictWord{142, 11, 126},
+ dictWord{11, 10, 33},
+ dictWord{12, 10, 571},
+ dictWord{149, 10, 1},
+ dictWord{133, 0, 566},
+ dictWord{9, 0, 139},
+ dictWord{
+ 10,
+ 0,
+ 399,
+ },
+ dictWord{11, 0, 469},
+ dictWord{12, 0, 634},
+ dictWord{13, 0, 223},
+ dictWord{132, 11, 483},
+ dictWord{6, 0, 48},
+ dictWord{135, 0, 63},
+ dictWord{18, 0, 12},
+ dictWord{7, 10, 1862},
+ dictWord{12, 10, 491},
+ dictWord{12, 10, 520},
+ dictWord{13, 10, 383},
+ dictWord{142, 10, 244},
+ dictWord{135, 11, 1665},
+ dictWord{132, 11, 448},
+ dictWord{9, 11, 495},
+ dictWord{146, 11, 104},
+ dictWord{6, 0, 114},
+ dictWord{7, 0, 1224},
+ dictWord{7, 0, 1556},
+ dictWord{136, 0, 3},
+ dictWord{
+ 4,
+ 10,
+ 190,
+ },
+ dictWord{133, 10, 554},
+ dictWord{8, 0, 576},
+ dictWord{9, 0, 267},
+ dictWord{133, 10, 1001},
+ dictWord{133, 10, 446},
+ dictWord{133, 0, 933},
+ dictWord{139, 11, 1009},
+ dictWord{8, 11, 653},
+ dictWord{13, 11, 93},
+ dictWord{147, 11, 14},
+ dictWord{6, 0, 692},
+ dictWord{6, 0, 821},
+ dictWord{134, 0, 1077},
+ dictWord{5, 11, 172},
+ dictWord{135, 11, 801},
+ dictWord{138, 0, 752},
+ dictWord{4, 0, 375},
+ dictWord{134, 0, 638},
+ dictWord{134, 0, 1011},
+ dictWord{
+ 140,
+ 11,
+ 540,
+ },
+ dictWord{9, 0, 96},
+ dictWord{133, 11, 260},
+ dictWord{139, 11, 587},
+ dictWord{135, 10, 1231},
+ dictWord{12, 0, 30},
+ dictWord{13, 0, 148},
+ dictWord{
+ 14,
+ 0,
+ 87,
+ },
+ dictWord{14, 0, 182},
+ dictWord{16, 0, 42},
+ dictWord{20, 0, 70},
+ dictWord{132, 10, 304},
+ dictWord{6, 0, 1398},
+ dictWord{7, 0, 56},
+ dictWord{7, 0, 1989},
+ dictWord{8, 0, 337},
+ dictWord{8, 0, 738},
+ dictWord{9, 0, 600},
+ dictWord{12, 0, 37},
+ dictWord{13, 0, 447},
+ dictWord{142, 0, 92},
+ dictWord{138, 0, 666},
+ dictWord{
+ 5,
+ 0,
+ 394,
+ },
+ dictWord{7, 0, 487},
+ dictWord{136, 0, 246},
+ dictWord{9, 0, 437},
+ dictWord{6, 10, 53},
+ dictWord{6, 10, 199},
+ dictWord{7, 10, 1408},
+ dictWord{8, 10, 32},
+ dictWord{8, 10, 93},
+ dictWord{10, 10, 397},
+ dictWord{10, 10, 629},
+ dictWord{11, 10, 593},
+ dictWord{11, 10, 763},
+ dictWord{13, 10, 326},
+ dictWord{145, 10, 35},
+ dictWord{134, 10, 105},
+ dictWord{9, 0, 320},
+ dictWord{10, 0, 506},
+ dictWord{138, 10, 794},
+ dictWord{7, 11, 57},
+ dictWord{8, 11, 167},
+ dictWord{8, 11, 375},
+ dictWord{9, 11, 82},
+ dictWord{9, 11, 561},
+ dictWord{10, 11, 620},
+ dictWord{10, 11, 770},
+ dictWord{11, 10, 704},
+ dictWord{141, 10, 396},
+ dictWord{6, 0, 1003},
+ dictWord{5, 10, 114},
+ dictWord{5, 10, 255},
+ dictWord{141, 10, 285},
+ dictWord{7, 0, 866},
+ dictWord{135, 0, 1163},
+ dictWord{133, 11, 531},
+ dictWord{
+ 132,
+ 0,
+ 328,
+ },
+ dictWord{7, 10, 2035},
+ dictWord{8, 10, 19},
+ dictWord{9, 10, 89},
+ dictWord{138, 10, 831},
+ dictWord{8, 11, 194},
+ dictWord{136, 11, 756},
+ dictWord{
+ 136,
+ 0,
+ 1000,
+ },
+ dictWord{5, 11, 453},
+ dictWord{134, 11, 441},
+ dictWord{4, 0, 101},
+ dictWord{5, 0, 833},
+ dictWord{7, 0, 1171},
+ dictWord{136, 0, 744},
+ dictWord{
+ 133,
+ 0,
+ 726,
+ },
+ dictWord{136, 10, 746},
+ dictWord{138, 0, 176},
+ dictWord{6, 0, 9},
+ dictWord{6, 0, 397},
+ dictWord{7, 0, 53},
+ dictWord{7, 0, 1742},
+ dictWord{10, 0, 632},
+ dictWord{11, 0, 828},
+ dictWord{140, 0, 146},
+ dictWord{135, 11, 22},
+ dictWord{145, 11, 64},
+ dictWord{132, 0, 839},
+ dictWord{11, 0, 417},
+ dictWord{12, 0, 223},
+ dictWord{140, 0, 265},
+ dictWord{4, 11, 102},
+ dictWord{7, 11, 815},
+ dictWord{7, 11, 1699},
+ dictWord{139, 11, 964},
+ dictWord{5, 10, 955},
+ dictWord{
+ 136,
+ 10,
+ 814,
+ },
+ dictWord{6, 0, 1931},
+ dictWord{6, 0, 2007},
+ dictWord{18, 0, 246},
+ dictWord{146, 0, 247},
+ dictWord{8, 0, 198},
+ dictWord{11, 0, 29},
+ dictWord{140, 0, 534},
+ dictWord{135, 0, 1771},
+ dictWord{6, 0, 846},
+ dictWord{7, 11, 1010},
+ dictWord{11, 11, 733},
+ dictWord{11, 11, 759},
+ dictWord{12, 11, 563},
+ dictWord{
+ 13,
+ 11,
+ 34,
+ },
+ dictWord{14, 11, 101},
+ dictWord{18, 11, 45},
+ dictWord{146, 11, 129},
+ dictWord{4, 0, 186},
+ dictWord{5, 0, 157},
+ dictWord{8, 0, 168},
+ dictWord{138, 0, 6},
+ dictWord{132, 11, 899},
+ dictWord{133, 10, 56},
+ dictWord{148, 10, 100},
+ dictWord{133, 0, 875},
+ dictWord{5, 0, 773},
+ dictWord{5, 0, 991},
+ dictWord{6, 0, 1635},
+ dictWord{134, 0, 1788},
+ dictWord{6, 0, 1274},
+ dictWord{9, 0, 477},
+ dictWord{141, 0, 78},
+ dictWord{4, 0, 639},
+ dictWord{7, 0, 111},
+ dictWord{8, 0, 581},
+ dictWord{
+ 12,
+ 0,
+ 177,
+ },
+ dictWord{6, 11, 52},
+ dictWord{9, 11, 104},
+ dictWord{9, 11, 559},
+ dictWord{10, 10, 4},
+ dictWord{10, 10, 13},
+ dictWord{11, 10, 638},
+ dictWord{
+ 12,
+ 11,
+ 308,
+ },
+ dictWord{19, 11, 87},
+ dictWord{148, 10, 57},
+ dictWord{132, 11, 604},
+ dictWord{4, 11, 301},
+ dictWord{133, 10, 738},
+ dictWord{133, 10, 758},
+ dictWord{134, 0, 1747},
+ dictWord{7, 11, 1440},
+ dictWord{11, 11, 854},
+ dictWord{11, 11, 872},
+ dictWord{11, 11, 921},
+ dictWord{12, 11, 551},
+ dictWord{
+ 13,
+ 11,
+ 472,
+ },
+ dictWord{142, 11, 367},
+ dictWord{7, 0, 1364},
+ dictWord{7, 0, 1907},
+ dictWord{141, 0, 158},
+ dictWord{134, 0, 873},
+ dictWord{4, 0, 404},
+ dictWord{
+ 4,
+ 0,
+ 659,
+ },
+ dictWord{7, 0, 552},
+ dictWord{135, 0, 675},
+ dictWord{135, 10, 1112},
+ dictWord{139, 10, 328},
+ dictWord{7, 11, 508},
+ dictWord{137, 10, 133},
+ dictWord{133, 0, 391},
+ dictWord{5, 10, 110},
+ dictWord{6, 10, 169},
+ dictWord{6, 10, 1702},
+ dictWord{7, 10, 400},
+ dictWord{8, 10, 538},
+ dictWord{9, 10, 184},
+ dictWord{
+ 9,
+ 10,
+ 524,
+ },
+ dictWord{140, 10, 218},
+ dictWord{6, 11, 310},
+ dictWord{7, 11, 1849},
+ dictWord{8, 11, 72},
+ dictWord{8, 11, 272},
+ dictWord{8, 11, 431},
+ dictWord{
+ 9,
+ 11,
+ 12,
+ },
+ dictWord{9, 11, 351},
+ dictWord{10, 11, 563},
+ dictWord{10, 11, 630},
+ dictWord{10, 11, 810},
+ dictWord{11, 11, 367},
+ dictWord{11, 11, 599},
+ dictWord{11, 11, 686},
+ dictWord{140, 11, 672},
+ dictWord{5, 0, 540},
+ dictWord{6, 0, 1697},
+ dictWord{136, 0, 668},
+ dictWord{132, 0, 883},
+ dictWord{134, 0, 78},
+ dictWord{12, 0, 628},
+ dictWord{18, 0, 79},
+ dictWord{6, 10, 133},
+ dictWord{9, 10, 353},
+ dictWord{139, 10, 993},
+ dictWord{6, 11, 181},
+ dictWord{7, 11, 537},
+ dictWord{
+ 8,
+ 11,
+ 64,
+ },
+ dictWord{9, 11, 127},
+ dictWord{10, 11, 496},
+ dictWord{12, 11, 510},
+ dictWord{141, 11, 384},
+ dictWord{6, 10, 93},
+ dictWord{7, 10, 1422},
+ dictWord{
+ 7,
+ 10,
+ 1851,
+ },
+ dictWord{8, 10, 673},
+ dictWord{9, 10, 529},
+ dictWord{140, 10, 43},
+ dictWord{137, 10, 371},
+ dictWord{134, 0, 1460},
+ dictWord{134, 0, 962},
+ dictWord{4, 11, 244},
+ dictWord{135, 11, 233},
+ dictWord{9, 10, 25},
+ dictWord{10, 10, 467},
+ dictWord{138, 10, 559},
+ dictWord{4, 10, 335},
+ dictWord{
+ 135,
+ 10,
+ 942,
+ },
+ dictWord{133, 0, 460},
+ dictWord{135, 11, 334},
+ dictWord{134, 11, 1650},
+ dictWord{4, 0, 199},
+ dictWord{139, 0, 34},
+ dictWord{5, 10, 601},
+ dictWord{
+ 8,
+ 10,
+ 39,
+ },
+ dictWord{10, 10, 773},
+ dictWord{11, 10, 84},
+ dictWord{12, 10, 205},
+ dictWord{142, 10, 1},
+ dictWord{133, 10, 870},
+ dictWord{134, 0, 388},
+ dictWord{14, 0, 474},
+ dictWord{148, 0, 120},
+ dictWord{133, 11, 369},
+ dictWord{139, 0, 271},
+ dictWord{4, 0, 511},
+ dictWord{9, 0, 333},
+ dictWord{9, 0, 379},
+ dictWord{
+ 10,
+ 0,
+ 602,
+ },
+ dictWord{11, 0, 441},
+ dictWord{11, 0, 723},
+ dictWord{11, 0, 976},
+ dictWord{12, 0, 357},
+ dictWord{132, 10, 181},
+ dictWord{134, 0, 608},
+ dictWord{134, 10, 1652},
+ dictWord{22, 0, 49},
+ dictWord{137, 11, 338},
+ dictWord{140, 0, 988},
+ dictWord{134, 0, 617},
+ dictWord{5, 0, 938},
+ dictWord{136, 0, 707},
+ dictWord{132, 10, 97},
+ dictWord{5, 10, 147},
+ dictWord{6, 10, 286},
+ dictWord{7, 10, 1362},
+ dictWord{141, 10, 176},
+ dictWord{6, 0, 756},
+ dictWord{
+ 134,
+ 0,
+ 1149,
+ },
+ dictWord{133, 11, 896},
+ dictWord{6, 10, 375},
+ dictWord{7, 10, 169},
+ dictWord{7, 10, 254},
+ dictWord{136, 10, 780},
+ dictWord{134, 0, 1583},
+ dictWord{135, 10, 1447},
+ dictWord{139, 0, 285},
+ dictWord{7, 11, 1117},
+ dictWord{8, 11, 393},
+ dictWord{136, 11, 539},
+ dictWord{135, 0, 344},
+ dictWord{
+ 6,
+ 0,
+ 469,
+ },
+ dictWord{7, 0, 1709},
+ dictWord{138, 0, 515},
+ dictWord{5, 10, 629},
+ dictWord{135, 10, 1549},
+ dictWord{5, 11, 4},
+ dictWord{5, 11, 810},
+ dictWord{
+ 6,
+ 11,
+ 13,
+ },
+ dictWord{6, 11, 538},
+ dictWord{6, 11, 1690},
+ dictWord{6, 11, 1726},
+ dictWord{7, 11, 499},
+ dictWord{7, 11, 1819},
+ dictWord{8, 11, 148},
+ dictWord{
+ 8,
+ 11,
+ 696,
+ },
+ dictWord{8, 11, 791},
+ dictWord{12, 11, 125},
+ dictWord{13, 11, 54},
+ dictWord{143, 11, 9},
+ dictWord{135, 11, 1268},
+ dictWord{137, 0, 404},
+ dictWord{
+ 132,
+ 0,
+ 500,
+ },
+ dictWord{5, 0, 68},
+ dictWord{134, 0, 383},
+ dictWord{11, 0, 216},
+ dictWord{139, 0, 340},
+ dictWord{4, 11, 925},
+ dictWord{5, 11, 803},
+ dictWord{
+ 8,
+ 11,
+ 698,
+ },
+ dictWord{138, 11, 828},
+ dictWord{4, 0, 337},
+ dictWord{6, 0, 353},
+ dictWord{7, 0, 1934},
+ dictWord{8, 0, 488},
+ dictWord{137, 0, 429},
+ dictWord{7, 0, 236},
+ dictWord{7, 0, 1795},
+ dictWord{8, 0, 259},
+ dictWord{9, 0, 135},
+ dictWord{9, 0, 177},
+ dictWord{9, 0, 860},
+ dictWord{10, 0, 825},
+ dictWord{11, 0, 115},
+ dictWord{
+ 11,
+ 0,
+ 370,
+ },
+ dictWord{11, 0, 405},
+ dictWord{11, 0, 604},
+ dictWord{12, 0, 10},
+ dictWord{12, 0, 667},
+ dictWord{12, 0, 669},
+ dictWord{13, 0, 76},
+ dictWord{14, 0, 310},
+ dictWord{15, 0, 76},
+ dictWord{15, 0, 147},
+ dictWord{148, 0, 23},
+ dictWord{4, 0, 15},
+ dictWord{4, 0, 490},
+ dictWord{5, 0, 22},
+ dictWord{6, 0, 244},
+ dictWord{7, 0, 40},
+ dictWord{7, 0, 200},
+ dictWord{7, 0, 906},
+ dictWord{7, 0, 1199},
+ dictWord{9, 0, 616},
+ dictWord{10, 0, 716},
+ dictWord{11, 0, 635},
+ dictWord{11, 0, 801},
+ dictWord{
+ 140,
+ 0,
+ 458,
+ },
+ dictWord{12, 0, 756},
+ dictWord{132, 10, 420},
+ dictWord{134, 0, 1504},
+ dictWord{6, 0, 757},
+ dictWord{133, 11, 383},
+ dictWord{6, 0, 1266},
+ dictWord{
+ 135,
+ 0,
+ 1735,
+ },
+ dictWord{5, 0, 598},
+ dictWord{7, 0, 791},
+ dictWord{8, 0, 108},
+ dictWord{9, 0, 123},
+ dictWord{7, 10, 1570},
+ dictWord{140, 10, 542},
+ dictWord{
+ 142,
+ 11,
+ 410,
+ },
+ dictWord{9, 11, 660},
+ dictWord{138, 11, 347},
+}
diff --git a/vendor/github.com/andybalholm/brotli/symbol_list.go b/vendor/github.com/andybalholm/brotli/symbol_list.go
new file mode 100644
index 0000000..c5cb49e
--- /dev/null
+++ b/vendor/github.com/andybalholm/brotli/symbol_list.go
@@ -0,0 +1,22 @@
+package brotli
+
+/* Copyright 2013 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Utilities for building Huffman decoding tables. */
+
+type symbolList struct {
+ storage []uint16
+ offset int
+}
+
+func symbolListGet(sl symbolList, i int) uint16 {
+ return sl.storage[i+sl.offset]
+}
+
+func symbolListPut(sl symbolList, i int, val uint16) {
+ sl.storage[i+sl.offset] = val
+}
diff --git a/vendor/github.com/andybalholm/brotli/transform.go b/vendor/github.com/andybalholm/brotli/transform.go
new file mode 100644
index 0000000..d2c043a
--- /dev/null
+++ b/vendor/github.com/andybalholm/brotli/transform.go
@@ -0,0 +1,641 @@
+package brotli
+
+const (
+ transformIdentity = 0
+ transformOmitLast1 = 1
+ transformOmitLast2 = 2
+ transformOmitLast3 = 3
+ transformOmitLast4 = 4
+ transformOmitLast5 = 5
+ transformOmitLast6 = 6
+ transformOmitLast7 = 7
+ transformOmitLast8 = 8
+ transformOmitLast9 = 9
+ transformUppercaseFirst = 10
+ transformUppercaseAll = 11
+ transformOmitFirst1 = 12
+ transformOmitFirst2 = 13
+ transformOmitFirst3 = 14
+ transformOmitFirst4 = 15
+ transformOmitFirst5 = 16
+ transformOmitFirst6 = 17
+ transformOmitFirst7 = 18
+ transformOmitFirst8 = 19
+ transformOmitFirst9 = 20
+ transformShiftFirst = 21
+ transformShiftAll = 22 + iota - 22
+ numTransformTypes
+)
+
+const transformsMaxCutOff = transformOmitLast9
+
+type transforms struct {
+ prefix_suffix_size uint16
+ prefix_suffix []byte
+ prefix_suffix_map []uint16
+ num_transforms uint32
+ transforms []byte
+ params []byte
+ cutOffTransforms [transformsMaxCutOff + 1]int16
+}
+
+func transformPrefixId(t *transforms, I int) byte {
+ return t.transforms[(I*3)+0]
+}
+
+func transformType(t *transforms, I int) byte {
+ return t.transforms[(I*3)+1]
+}
+
+func transformSuffixId(t *transforms, I int) byte {
+ return t.transforms[(I*3)+2]
+}
+
+func transformPrefix(t *transforms, I int) []byte {
+ return t.prefix_suffix[t.prefix_suffix_map[transformPrefixId(t, I)]:]
+}
+
+func transformSuffix(t *transforms, I int) []byte {
+ return t.prefix_suffix[t.prefix_suffix_map[transformSuffixId(t, I)]:]
+}
+
+/* RFC 7932 transforms string data */
+const kPrefixSuffix string = "\001 \002, \010 of the \004 of \002s \001.\005 and \004 " + "in \001\"\004 to \002\">\001\n\002. \001]\005 for \003 a \006 " + "that \001'\006 with \006 from \004 by \001(\006. T" + "he \004 on \004 as \004 is \004ing \002\n\t\001:\003ed " + "\002=\"\004 at \003ly \001,\002='\005.com/\007. This \005" + " not \003er \003al \004ful \004ive \005less \004es" + "t \004ize \002\xc2\xa0\004ous \005 the \002e \000"
+
+var kPrefixSuffixMap = [50]uint16{
+ 0x00,
+ 0x02,
+ 0x05,
+ 0x0E,
+ 0x13,
+ 0x16,
+ 0x18,
+ 0x1E,
+ 0x23,
+ 0x25,
+ 0x2A,
+ 0x2D,
+ 0x2F,
+ 0x32,
+ 0x34,
+ 0x3A,
+ 0x3E,
+ 0x45,
+ 0x47,
+ 0x4E,
+ 0x55,
+ 0x5A,
+ 0x5C,
+ 0x63,
+ 0x68,
+ 0x6D,
+ 0x72,
+ 0x77,
+ 0x7A,
+ 0x7C,
+ 0x80,
+ 0x83,
+ 0x88,
+ 0x8C,
+ 0x8E,
+ 0x91,
+ 0x97,
+ 0x9F,
+ 0xA5,
+ 0xA9,
+ 0xAD,
+ 0xB2,
+ 0xB7,
+ 0xBD,
+ 0xC2,
+ 0xC7,
+ 0xCA,
+ 0xCF,
+ 0xD5,
+ 0xD8,
+}
+
+/* RFC 7932 transforms */
+var kTransformsData = []byte{
+ 49,
+ transformIdentity,
+ 49,
+ 49,
+ transformIdentity,
+ 0,
+ 0,
+ transformIdentity,
+ 0,
+ 49,
+ transformOmitFirst1,
+ 49,
+ 49,
+ transformUppercaseFirst,
+ 0,
+ 49,
+ transformIdentity,
+ 47,
+ 0,
+ transformIdentity,
+ 49,
+ 4,
+ transformIdentity,
+ 0,
+ 49,
+ transformIdentity,
+ 3,
+ 49,
+ transformUppercaseFirst,
+ 49,
+ 49,
+ transformIdentity,
+ 6,
+ 49,
+ transformOmitFirst2,
+ 49,
+ 49,
+ transformOmitLast1,
+ 49,
+ 1,
+ transformIdentity,
+ 0,
+ 49,
+ transformIdentity,
+ 1,
+ 0,
+ transformUppercaseFirst,
+ 0,
+ 49,
+ transformIdentity,
+ 7,
+ 49,
+ transformIdentity,
+ 9,
+ 48,
+ transformIdentity,
+ 0,
+ 49,
+ transformIdentity,
+ 8,
+ 49,
+ transformIdentity,
+ 5,
+ 49,
+ transformIdentity,
+ 10,
+ 49,
+ transformIdentity,
+ 11,
+ 49,
+ transformOmitLast3,
+ 49,
+ 49,
+ transformIdentity,
+ 13,
+ 49,
+ transformIdentity,
+ 14,
+ 49,
+ transformOmitFirst3,
+ 49,
+ 49,
+ transformOmitLast2,
+ 49,
+ 49,
+ transformIdentity,
+ 15,
+ 49,
+ transformIdentity,
+ 16,
+ 0,
+ transformUppercaseFirst,
+ 49,
+ 49,
+ transformIdentity,
+ 12,
+ 5,
+ transformIdentity,
+ 49,
+ 0,
+ transformIdentity,
+ 1,
+ 49,
+ transformOmitFirst4,
+ 49,
+ 49,
+ transformIdentity,
+ 18,
+ 49,
+ transformIdentity,
+ 17,
+ 49,
+ transformIdentity,
+ 19,
+ 49,
+ transformIdentity,
+ 20,
+ 49,
+ transformOmitFirst5,
+ 49,
+ 49,
+ transformOmitFirst6,
+ 49,
+ 47,
+ transformIdentity,
+ 49,
+ 49,
+ transformOmitLast4,
+ 49,
+ 49,
+ transformIdentity,
+ 22,
+ 49,
+ transformUppercaseAll,
+ 49,
+ 49,
+ transformIdentity,
+ 23,
+ 49,
+ transformIdentity,
+ 24,
+ 49,
+ transformIdentity,
+ 25,
+ 49,
+ transformOmitLast7,
+ 49,
+ 49,
+ transformOmitLast1,
+ 26,
+ 49,
+ transformIdentity,
+ 27,
+ 49,
+ transformIdentity,
+ 28,
+ 0,
+ transformIdentity,
+ 12,
+ 49,
+ transformIdentity,
+ 29,
+ 49,
+ transformOmitFirst9,
+ 49,
+ 49,
+ transformOmitFirst7,
+ 49,
+ 49,
+ transformOmitLast6,
+ 49,
+ 49,
+ transformIdentity,
+ 21,
+ 49,
+ transformUppercaseFirst,
+ 1,
+ 49,
+ transformOmitLast8,
+ 49,
+ 49,
+ transformIdentity,
+ 31,
+ 49,
+ transformIdentity,
+ 32,
+ 47,
+ transformIdentity,
+ 3,
+ 49,
+ transformOmitLast5,
+ 49,
+ 49,
+ transformOmitLast9,
+ 49,
+ 0,
+ transformUppercaseFirst,
+ 1,
+ 49,
+ transformUppercaseFirst,
+ 8,
+ 5,
+ transformIdentity,
+ 21,
+ 49,
+ transformUppercaseAll,
+ 0,
+ 49,
+ transformUppercaseFirst,
+ 10,
+ 49,
+ transformIdentity,
+ 30,
+ 0,
+ transformIdentity,
+ 5,
+ 35,
+ transformIdentity,
+ 49,
+ 47,
+ transformIdentity,
+ 2,
+ 49,
+ transformUppercaseFirst,
+ 17,
+ 49,
+ transformIdentity,
+ 36,
+ 49,
+ transformIdentity,
+ 33,
+ 5,
+ transformIdentity,
+ 0,
+ 49,
+ transformUppercaseFirst,
+ 21,
+ 49,
+ transformUppercaseFirst,
+ 5,
+ 49,
+ transformIdentity,
+ 37,
+ 0,
+ transformIdentity,
+ 30,
+ 49,
+ transformIdentity,
+ 38,
+ 0,
+ transformUppercaseAll,
+ 0,
+ 49,
+ transformIdentity,
+ 39,
+ 0,
+ transformUppercaseAll,
+ 49,
+ 49,
+ transformIdentity,
+ 34,
+ 49,
+ transformUppercaseAll,
+ 8,
+ 49,
+ transformUppercaseFirst,
+ 12,
+ 0,
+ transformIdentity,
+ 21,
+ 49,
+ transformIdentity,
+ 40,
+ 0,
+ transformUppercaseFirst,
+ 12,
+ 49,
+ transformIdentity,
+ 41,
+ 49,
+ transformIdentity,
+ 42,
+ 49,
+ transformUppercaseAll,
+ 17,
+ 49,
+ transformIdentity,
+ 43,
+ 0,
+ transformUppercaseFirst,
+ 5,
+ 49,
+ transformUppercaseAll,
+ 10,
+ 0,
+ transformIdentity,
+ 34,
+ 49,
+ transformUppercaseFirst,
+ 33,
+ 49,
+ transformIdentity,
+ 44,
+ 49,
+ transformUppercaseAll,
+ 5,
+ 45,
+ transformIdentity,
+ 49,
+ 0,
+ transformIdentity,
+ 33,
+ 49,
+ transformUppercaseFirst,
+ 30,
+ 49,
+ transformUppercaseAll,
+ 30,
+ 49,
+ transformIdentity,
+ 46,
+ 49,
+ transformUppercaseAll,
+ 1,
+ 49,
+ transformUppercaseFirst,
+ 34,
+ 0,
+ transformUppercaseFirst,
+ 33,
+ 0,
+ transformUppercaseAll,
+ 30,
+ 0,
+ transformUppercaseAll,
+ 1,
+ 49,
+ transformUppercaseAll,
+ 33,
+ 49,
+ transformUppercaseAll,
+ 21,
+ 49,
+ transformUppercaseAll,
+ 12,
+ 0,
+ transformUppercaseAll,
+ 5,
+ 49,
+ transformUppercaseAll,
+ 34,
+ 0,
+ transformUppercaseAll,
+ 12,
+ 0,
+ transformUppercaseFirst,
+ 30,
+ 0,
+ transformUppercaseAll,
+ 34,
+ 0,
+ transformUppercaseFirst,
+ 34,
+}
+
+var kBrotliTransforms = transforms{
+ 217,
+ []byte(kPrefixSuffix),
+ kPrefixSuffixMap[:],
+ 121,
+ kTransformsData,
+ nil, /* no extra parameters */
+ [transformsMaxCutOff + 1]int16{0, 12, 27, 23, 42, 63, 56, 48, 59, 64},
+}
+
+func getTransforms() *transforms {
+ return &kBrotliTransforms
+}
+
+func toUpperCase(p []byte) int {
+ if p[0] < 0xC0 {
+ if p[0] >= 'a' && p[0] <= 'z' {
+ p[0] ^= 32
+ }
+
+ return 1
+ }
+
+ /* An overly simplified uppercasing model for UTF-8. */
+ if p[0] < 0xE0 {
+ p[1] ^= 32
+ return 2
+ }
+
+ /* An arbitrary transform for three byte characters. */
+ p[2] ^= 5
+
+ return 3
+}
+
+func shiftTransform(word []byte, word_len int, parameter uint16) int {
+ /* Limited sign extension: scalar < (1 << 24). */
+ var scalar uint32 = (uint32(parameter) & 0x7FFF) + (0x1000000 - (uint32(parameter) & 0x8000))
+ if word[0] < 0x80 {
+ /* 1-byte rune / 0sssssss / 7 bit scalar (ASCII). */
+ scalar += uint32(word[0])
+
+ word[0] = byte(scalar & 0x7F)
+ return 1
+ } else if word[0] < 0xC0 {
+ /* Continuation / 10AAAAAA. */
+ return 1
+ } else if word[0] < 0xE0 {
+ /* 2-byte rune / 110sssss AAssssss / 11 bit scalar. */
+ if word_len < 2 {
+ return 1
+ }
+ scalar += uint32(word[1]&0x3F | (word[0]&0x1F)<<6)
+ word[0] = byte(0xC0 | (scalar>>6)&0x1F)
+ word[1] = byte(uint32(word[1]&0xC0) | scalar&0x3F)
+ return 2
+ } else if word[0] < 0xF0 {
+ /* 3-byte rune / 1110ssss AAssssss BBssssss / 16 bit scalar. */
+ if word_len < 3 {
+ return word_len
+ }
+ scalar += uint32(word[2])&0x3F | uint32(word[1]&0x3F)<<6 | uint32(word[0]&0x0F)<<12
+ word[0] = byte(0xE0 | (scalar>>12)&0x0F)
+ word[1] = byte(uint32(word[1]&0xC0) | (scalar>>6)&0x3F)
+ word[2] = byte(uint32(word[2]&0xC0) | scalar&0x3F)
+ return 3
+ } else if word[0] < 0xF8 {
+ /* 4-byte rune / 11110sss AAssssss BBssssss CCssssss / 21 bit scalar. */
+ if word_len < 4 {
+ return word_len
+ }
+ scalar += uint32(word[3])&0x3F | uint32(word[2]&0x3F)<<6 | uint32(word[1]&0x3F)<<12 | uint32(word[0]&0x07)<<18
+ word[0] = byte(0xF0 | (scalar>>18)&0x07)
+ word[1] = byte(uint32(word[1]&0xC0) | (scalar>>12)&0x3F)
+ word[2] = byte(uint32(word[2]&0xC0) | (scalar>>6)&0x3F)
+ word[3] = byte(uint32(word[3]&0xC0) | scalar&0x3F)
+ return 4
+ }
+
+ return 1
+}
+
+func transformDictionaryWord(dst []byte, word []byte, len int, trans *transforms, transform_idx int) int {
+ var idx int = 0
+ var prefix []byte = transformPrefix(trans, transform_idx)
+ var type_ byte = transformType(trans, transform_idx)
+ var suffix []byte = transformSuffix(trans, transform_idx)
+ {
+ var prefix_len int = int(prefix[0])
+ prefix = prefix[1:]
+ for {
+ tmp1 := prefix_len
+ prefix_len--
+ if tmp1 == 0 {
+ break
+ }
+ dst[idx] = prefix[0]
+ idx++
+ prefix = prefix[1:]
+ }
+ }
+ {
+ var t int = int(type_)
+ var i int = 0
+ if t <= transformOmitLast9 {
+ len -= t
+ } else if t >= transformOmitFirst1 && t <= transformOmitFirst9 {
+ var skip int = t - (transformOmitFirst1 - 1)
+ word = word[skip:]
+ len -= skip
+ }
+
+ for i < len {
+ dst[idx] = word[i]
+ idx++
+ i++
+ }
+ if t == transformUppercaseFirst {
+ toUpperCase(dst[idx-len:])
+ } else if t == transformUppercaseAll {
+ var uppercase []byte = dst
+ uppercase = uppercase[idx-len:]
+ for len > 0 {
+ var step int = toUpperCase(uppercase)
+ uppercase = uppercase[step:]
+ len -= step
+ }
+ } else if t == transformShiftFirst {
+ var param uint16 = uint16(trans.params[transform_idx*2]) + uint16(trans.params[transform_idx*2+1])<<8
+ shiftTransform(dst[idx-len:], int(len), param)
+ } else if t == transformShiftAll {
+ var param uint16 = uint16(trans.params[transform_idx*2]) + uint16(trans.params[transform_idx*2+1])<<8
+ var shift []byte = dst
+ shift = shift[idx-len:]
+ for len > 0 {
+ var step int = shiftTransform(shift, int(len), param)
+ shift = shift[step:]
+ len -= step
+ }
+ }
+ }
+ {
+ var suffix_len int = int(suffix[0])
+ suffix = suffix[1:]
+ for {
+ tmp2 := suffix_len
+ suffix_len--
+ if tmp2 == 0 {
+ break
+ }
+ dst[idx] = suffix[0]
+ idx++
+ suffix = suffix[1:]
+ }
+ return idx
+ }
+}
diff --git a/vendor/github.com/andybalholm/brotli/utf8_util.go b/vendor/github.com/andybalholm/brotli/utf8_util.go
new file mode 100644
index 0000000..3244247
--- /dev/null
+++ b/vendor/github.com/andybalholm/brotli/utf8_util.go
@@ -0,0 +1,70 @@
+package brotli
+
+/* Copyright 2013 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Heuristics for deciding about the UTF8-ness of strings. */
+
+const kMinUTF8Ratio float64 = 0.75
+
+/* Returns 1 if at least min_fraction of the bytes between pos and
+ pos + length in the (data, mask) ring-buffer is UTF8-encoded, otherwise
+ returns 0. */
+func parseAsUTF8(symbol *int, input []byte, size uint) uint {
+ /* ASCII */
+ if input[0]&0x80 == 0 {
+ *symbol = int(input[0])
+ if *symbol > 0 {
+ return 1
+ }
+ }
+
+ /* 2-byte UTF8 */
+ if size > 1 && input[0]&0xE0 == 0xC0 && input[1]&0xC0 == 0x80 {
+ *symbol = (int(input[0])&0x1F)<<6 | int(input[1])&0x3F
+ if *symbol > 0x7F {
+ return 2
+ }
+ }
+
+ /* 3-byte UFT8 */
+ if size > 2 && input[0]&0xF0 == 0xE0 && input[1]&0xC0 == 0x80 && input[2]&0xC0 == 0x80 {
+ *symbol = (int(input[0])&0x0F)<<12 | (int(input[1])&0x3F)<<6 | int(input[2])&0x3F
+ if *symbol > 0x7FF {
+ return 3
+ }
+ }
+
+ /* 4-byte UFT8 */
+ if size > 3 && input[0]&0xF8 == 0xF0 && input[1]&0xC0 == 0x80 && input[2]&0xC0 == 0x80 && input[3]&0xC0 == 0x80 {
+ *symbol = (int(input[0])&0x07)<<18 | (int(input[1])&0x3F)<<12 | (int(input[2])&0x3F)<<6 | int(input[3])&0x3F
+ if *symbol > 0xFFFF && *symbol <= 0x10FFFF {
+ return 4
+ }
+ }
+
+ /* Not UTF8, emit a special symbol above the UTF8-code space */
+ *symbol = 0x110000 | int(input[0])
+
+ return 1
+}
+
+/* Returns 1 if at least min_fraction of the data is UTF8-encoded.*/
+func isMostlyUTF8(data []byte, pos uint, mask uint, length uint, min_fraction float64) bool {
+ var size_utf8 uint = 0
+ var i uint = 0
+ for i < length {
+ var symbol int
+ current_data := data[(pos+i)&mask:]
+ var bytes_read uint = parseAsUTF8(&symbol, current_data, length-i)
+ i += bytes_read
+ if symbol < 0x110000 {
+ size_utf8 += bytes_read
+ }
+ }
+
+ return float64(size_utf8) > min_fraction*float64(length)
+}
diff --git a/vendor/github.com/andybalholm/brotli/util.go b/vendor/github.com/andybalholm/brotli/util.go
new file mode 100644
index 0000000..a84553a
--- /dev/null
+++ b/vendor/github.com/andybalholm/brotli/util.go
@@ -0,0 +1,7 @@
+package brotli
+
+func assert(cond bool) {
+ if !cond {
+ panic("assertion failure")
+ }
+}
diff --git a/vendor/github.com/andybalholm/brotli/write_bits.go b/vendor/github.com/andybalholm/brotli/write_bits.go
new file mode 100644
index 0000000..8729901
--- /dev/null
+++ b/vendor/github.com/andybalholm/brotli/write_bits.go
@@ -0,0 +1,52 @@
+package brotli
+
+import "encoding/binary"
+
+/* Copyright 2010 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Write bits into a byte array. */
+
+/* This function writes bits into bytes in increasing addresses, and within
+ a byte least-significant-bit first.
+
+ The function can write up to 56 bits in one go with WriteBits
+ Example: let's assume that 3 bits (Rs below) have been written already:
+
+ BYTE-0 BYTE+1 BYTE+2
+
+ 0000 0RRR 0000 0000 0000 0000
+
+ Now, we could write 5 or less bits in MSB by just sifting by 3
+ and OR'ing to BYTE-0.
+
+ For n bits, we take the last 5 bits, OR that with high bits in BYTE-0,
+ and locate the rest in BYTE+1, BYTE+2, etc. */
+func writeBits(n_bits uint, bits uint64, pos *uint, array []byte) {
+ /* This branch of the code can write up to 56 bits at a time,
+ 7 bits are lost by being perhaps already in *p and at least
+ 1 bit is needed to initialize the bit-stream ahead (i.e. if 7
+ bits are in *p and we write 57 bits, then the next write will
+ access a byte that was never initialized). */
+ p := array[*pos>>3:]
+ v := uint64(p[0])
+ v |= bits << (*pos & 7)
+ binary.LittleEndian.PutUint64(p, v)
+ *pos += n_bits
+}
+
+func writeSingleBit(bit bool, pos *uint, array []byte) {
+ if bit {
+ writeBits(1, 1, pos, array)
+ } else {
+ writeBits(1, 0, pos, array)
+ }
+}
+
+func writeBitsPrepareStorage(pos uint, array []byte) {
+ assert(pos&7 == 0)
+ array[pos>>3] = 0
+}
diff --git a/vendor/github.com/andybalholm/brotli/writer.go b/vendor/github.com/andybalholm/brotli/writer.go
new file mode 100644
index 0000000..39feaef
--- /dev/null
+++ b/vendor/github.com/andybalholm/brotli/writer.go
@@ -0,0 +1,119 @@
+package brotli
+
+import (
+ "errors"
+ "io"
+)
+
+const (
+ BestSpeed = 0
+ BestCompression = 11
+ DefaultCompression = 6
+)
+
+// WriterOptions configures Writer.
+type WriterOptions struct {
+ // Quality controls the compression-speed vs compression-density trade-offs.
+ // The higher the quality, the slower the compression. Range is 0 to 11.
+ Quality int
+ // LGWin is the base 2 logarithm of the sliding window size.
+ // Range is 10 to 24. 0 indicates automatic configuration based on Quality.
+ LGWin int
+}
+
+var (
+ errEncode = errors.New("brotli: encode error")
+ errWriterClosed = errors.New("brotli: Writer is closed")
+)
+
+// Writes to the returned writer are compressed and written to dst.
+// It is the caller's responsibility to call Close on the Writer when done.
+// Writes may be buffered and not flushed until Close.
+func NewWriter(dst io.Writer) *Writer {
+ return NewWriterLevel(dst, DefaultCompression)
+}
+
+// NewWriterLevel is like NewWriter but specifies the compression level instead
+// of assuming DefaultCompression.
+// The compression level can be DefaultCompression or any integer value between
+// BestSpeed and BestCompression inclusive.
+func NewWriterLevel(dst io.Writer, level int) *Writer {
+ return NewWriterOptions(dst, WriterOptions{
+ Quality: level,
+ })
+}
+
+// NewWriterOptions is like NewWriter but specifies WriterOptions
+func NewWriterOptions(dst io.Writer, options WriterOptions) *Writer {
+ w := new(Writer)
+ w.options = options
+ w.Reset(dst)
+ return w
+}
+
+// Reset discards the Writer's state and makes it equivalent to the result of
+// its original state from NewWriter or NewWriterLevel, but writing to dst
+// instead. This permits reusing a Writer rather than allocating a new one.
+func (w *Writer) Reset(dst io.Writer) {
+ encoderInitState(w)
+ w.params.quality = w.options.Quality
+ if w.options.LGWin > 0 {
+ w.params.lgwin = uint(w.options.LGWin)
+ }
+ w.dst = dst
+ w.err = nil
+}
+
+func (w *Writer) writeChunk(p []byte, op int) (n int, err error) {
+ if w.dst == nil {
+ return 0, errWriterClosed
+ }
+ if w.err != nil {
+ return 0, w.err
+ }
+
+ for {
+ availableIn := uint(len(p))
+ nextIn := p
+ success := encoderCompressStream(w, op, &availableIn, &nextIn)
+ bytesConsumed := len(p) - int(availableIn)
+ p = p[bytesConsumed:]
+ n += bytesConsumed
+ if !success {
+ return n, errEncode
+ }
+
+ if len(p) == 0 || w.err != nil {
+ return n, w.err
+ }
+ }
+}
+
+// Flush outputs encoded data for all input provided to Write. The resulting
+// output can be decoded to match all input before Flush, but the stream is
+// not yet complete until after Close.
+// Flush has a negative impact on compression.
+func (w *Writer) Flush() error {
+ _, err := w.writeChunk(nil, operationFlush)
+ return err
+}
+
+// Close flushes remaining data to the decorated writer.
+func (w *Writer) Close() error {
+ // If stream is already closed, it is reported by `writeChunk`.
+ _, err := w.writeChunk(nil, operationFinish)
+ w.dst = nil
+ return err
+}
+
+// Write implements io.Writer. Flush or Close must be called to ensure that the
+// encoded bytes are actually flushed to the underlying Writer.
+func (w *Writer) Write(p []byte) (n int, err error) {
+ return w.writeChunk(p, operationProcess)
+}
+
+type nopCloser struct {
+ io.Writer
+}
+
+func (nopCloser) Close() error { return nil }
diff --git a/vendor/github.com/btcsuite/btcd/btcec/v2/LICENSE b/vendor/github.com/btcsuite/btcd/btcec/v2/LICENSE
new file mode 100644
index 0000000..46dcd39
--- /dev/null
+++ b/vendor/github.com/btcsuite/btcd/btcec/v2/LICENSE
@@ -0,0 +1,16 @@
+ISC License
+
+Copyright (c) 2013-2023 The btcsuite developers
+Copyright (c) 2015-2016 The Decred developers
+
+Permission to use, copy, modify, and distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
diff --git a/vendor/github.com/btcsuite/btcd/btcec/v2/README.md b/vendor/github.com/btcsuite/btcd/btcec/v2/README.md
new file mode 100644
index 0000000..5339177
--- /dev/null
+++ b/vendor/github.com/btcsuite/btcd/btcec/v2/README.md
@@ -0,0 +1,40 @@
+btcec
+=====
+
+[![Build Status](https://github.com/btcsuite/btcd/workflows/Build%20and%20Test/badge.svg)](https://github.com/btcsuite/btcd/actions)
+[![ISC License](http://img.shields.io/badge/license-ISC-blue.svg)](http://copyfree.org)
+[![GoDoc](https://pkg.go.dev/github.com/btcsuite/btcd/btcec/v2?status.png)](https://pkg.go.dev/github.com/btcsuite/btcd/btcec/v2)
+
+Package btcec implements elliptic curve cryptography needed for working with
+Bitcoin (secp256k1 only for now). It is designed so that it may be used with the
+standard crypto/ecdsa packages provided with go. A comprehensive suite of test
+is provided to ensure proper functionality. Package btcec was originally based
+on work from ThePiachu which is licensed under the same terms as Go, but it has
+significantly diverged since then. The btcsuite developers original is licensed
+under the liberal ISC license.
+
+Although this package was primarily written for btcd, it has intentionally been
+designed so it can be used as a standalone package for any projects needing to
+use secp256k1 elliptic curve cryptography.
+
+## Installation and Updating
+
+```bash
+$ go install -u -v github.com/btcsuite/btcd/btcec/v2
+```
+
+## Examples
+
+* [Sign Message](https://pkg.go.dev/github.com/btcsuite/btcd/btcec/v2#example-package--SignMessage)
+ Demonstrates signing a message with a secp256k1 private key that is first
+ parsed form raw bytes and serializing the generated signature.
+
+* [Verify Signature](https://pkg.go.dev/github.com/btcsuite/btcd/btcec/v2#example-package--VerifySignature)
+ Demonstrates verifying a secp256k1 signature against a public key that is
+ first parsed from raw bytes. The signature is also parsed from raw bytes.
+
+## License
+
+Package btcec is licensed under the [copyfree](http://copyfree.org) ISC License
+except for btcec.go and btcec_test.go which is under the same license as Go.
+
diff --git a/vendor/github.com/btcsuite/btcd/btcec/v2/btcec.go b/vendor/github.com/btcsuite/btcd/btcec/v2/btcec.go
new file mode 100644
index 0000000..f85baba
--- /dev/null
+++ b/vendor/github.com/btcsuite/btcd/btcec/v2/btcec.go
@@ -0,0 +1,56 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Copyright 2011 ThePiachu. All rights reserved.
+// Copyright 2013-2014 The btcsuite developers
+// Use of this source code is governed by an ISC
+// license that can be found in the LICENSE file.
+
+package btcec
+
+// References:
+// [SECG]: Recommended Elliptic Curve Domain Parameters
+// http://www.secg.org/sec2-v2.pdf
+//
+// [GECC]: Guide to Elliptic Curve Cryptography (Hankerson, Menezes, Vanstone)
+
+// This package operates, internally, on Jacobian coordinates. For a given
+// (x, y) position on the curve, the Jacobian coordinates are (x1, y1, z1)
+// where x = x1/z1² and y = y1/z1³. The greatest speedups come when the whole
+// calculation can be performed within the transform (as in ScalarMult and
+// ScalarBaseMult). But even for Add and Double, it's faster to apply and
+// reverse the transform than to operate in affine coordinates.
+
+import (
+ secp "github.com/decred/dcrd/dcrec/secp256k1/v4"
+)
+
+// KoblitzCurve provides an implementation for secp256k1 that fits the ECC
+// Curve interface from crypto/elliptic.
+type KoblitzCurve = secp.KoblitzCurve
+
+// S256 returns a Curve which implements secp256k1.
+func S256() *KoblitzCurve {
+ return secp.S256()
+}
+
+// CurveParams contains the parameters for the secp256k1 curve.
+type CurveParams = secp.CurveParams
+
+// Params returns the secp256k1 curve parameters for convenience.
+func Params() *CurveParams {
+ return secp.Params()
+}
+
+// Generator returns the public key at the Generator Point.
+func Generator() *PublicKey {
+ var (
+ result JacobianPoint
+ k secp.ModNScalar
+ )
+
+ k.SetInt(1)
+ ScalarBaseMultNonConst(&k, &result)
+
+ result.ToAffine()
+
+ return NewPublicKey(&result.X, &result.Y)
+}
diff --git a/vendor/github.com/btcsuite/btcd/btcec/v2/ciphering.go b/vendor/github.com/btcsuite/btcd/btcec/v2/ciphering.go
new file mode 100644
index 0000000..88d93e2
--- /dev/null
+++ b/vendor/github.com/btcsuite/btcd/btcec/v2/ciphering.go
@@ -0,0 +1,16 @@
+// Copyright (c) 2015-2016 The btcsuite developers
+// Use of this source code is governed by an ISC
+// license that can be found in the LICENSE file.
+
+package btcec
+
+import (
+ secp "github.com/decred/dcrd/dcrec/secp256k1/v4"
+)
+
+// GenerateSharedSecret generates a shared secret based on a private key and a
+// public key using Diffie-Hellman key exchange (ECDH) (RFC 4753).
+// RFC5903 Section 9 states we should only return x.
+func GenerateSharedSecret(privkey *PrivateKey, pubkey *PublicKey) []byte {
+ return secp.GenerateSharedSecret(privkey, pubkey)
+}
diff --git a/vendor/github.com/btcsuite/btcd/btcec/v2/curve.go b/vendor/github.com/btcsuite/btcd/btcec/v2/curve.go
new file mode 100644
index 0000000..70a9229
--- /dev/null
+++ b/vendor/github.com/btcsuite/btcd/btcec/v2/curve.go
@@ -0,0 +1,115 @@
+// Copyright (c) 2015-2021 The btcsuite developers
+// Copyright (c) 2015-2021 The Decred developers
+
+package btcec
+
+import (
+ "fmt"
+
+ secp "github.com/decred/dcrd/dcrec/secp256k1/v4"
+)
+
+// JacobianPoint is an element of the group formed by the secp256k1 curve in
+// Jacobian projective coordinates and thus represents a point on the curve.
+type JacobianPoint = secp.JacobianPoint
+
+// infinityPoint is the jacobian representation of the point at infinity.
+var infinityPoint JacobianPoint
+
+// MakeJacobianPoint returns a Jacobian point with the provided X, Y, and Z
+// coordinates.
+func MakeJacobianPoint(x, y, z *FieldVal) JacobianPoint {
+ return secp.MakeJacobianPoint(x, y, z)
+}
+
+// AddNonConst adds the passed Jacobian points together and stores the result
+// in the provided result param in *non-constant* time.
+func AddNonConst(p1, p2, result *JacobianPoint) {
+ secp.AddNonConst(p1, p2, result)
+}
+
+// DecompressY attempts to calculate the Y coordinate for the given X
+// coordinate such that the result pair is a point on the secp256k1 curve. It
+// adjusts Y based on the desired oddness and returns whether or not it was
+// successful since not all X coordinates are valid.
+//
+// The magnitude of the provided X coordinate field val must be a max of 8 for
+// a correct result. The resulting Y field val will have a max magnitude of 2.
+func DecompressY(x *FieldVal, odd bool, resultY *FieldVal) bool {
+ return secp.DecompressY(x, odd, resultY)
+}
+
+// DoubleNonConst doubles the passed Jacobian point and stores the result in
+// the provided result parameter in *non-constant* time.
+//
+// NOTE: The point must be normalized for this function to return the correct
+// result. The resulting point will be normalized.
+func DoubleNonConst(p, result *JacobianPoint) {
+ secp.DoubleNonConst(p, result)
+}
+
+// ScalarBaseMultNonConst multiplies k*G where G is the base point of the group
+// and k is a big endian integer. The result is stored in Jacobian coordinates
+// (x1, y1, z1).
+//
+// NOTE: The resulting point will be normalized.
+func ScalarBaseMultNonConst(k *ModNScalar, result *JacobianPoint) {
+ secp.ScalarBaseMultNonConst(k, result)
+}
+
+// ScalarMultNonConst multiplies k*P where k is a big endian integer modulo the
+// curve order and P is a point in Jacobian projective coordinates and stores
+// the result in the provided Jacobian point.
+//
+// NOTE: The point must be normalized for this function to return the correct
+// result. The resulting point will be normalized.
+func ScalarMultNonConst(k *ModNScalar, point, result *JacobianPoint) {
+ secp.ScalarMultNonConst(k, point, result)
+}
+
+// ParseJacobian parses a byte slice point as a secp.Publickey and returns the
+// pubkey as a JacobianPoint. If the nonce is a zero slice, the infinityPoint
+// is returned.
+func ParseJacobian(point []byte) (JacobianPoint, error) {
+ var result JacobianPoint
+
+ if len(point) != 33 {
+ str := fmt.Sprintf("invalid nonce: invalid length: %v",
+ len(point))
+ return JacobianPoint{}, makeError(secp.ErrPubKeyInvalidLen, str)
+ }
+
+ if point[0] == 0x00 {
+ return infinityPoint, nil
+ }
+
+ noncePk, err := secp.ParsePubKey(point)
+ if err != nil {
+ return JacobianPoint{}, err
+ }
+ noncePk.AsJacobian(&result)
+
+ return result, nil
+}
+
+// JacobianToByteSlice converts the passed JacobianPoint to a Pubkey
+// and serializes that to a byte slice. If the JacobianPoint is the infinity
+// point, a zero slice is returned.
+func JacobianToByteSlice(point JacobianPoint) []byte {
+ if point.X == infinityPoint.X && point.Y == infinityPoint.Y {
+ return make([]byte, 33)
+ }
+
+ point.ToAffine()
+
+ return NewPublicKey(
+ &point.X, &point.Y,
+ ).SerializeCompressed()
+}
+
+// GeneratorJacobian sets the passed JacobianPoint to the Generator Point.
+func GeneratorJacobian(jacobian *JacobianPoint) {
+ var k ModNScalar
+ k.SetInt(1)
+ ScalarBaseMultNonConst(&k, jacobian)
+}
diff --git a/vendor/github.com/btcsuite/btcd/btcec/v2/doc.go b/vendor/github.com/btcsuite/btcd/btcec/v2/doc.go
new file mode 100644
index 0000000..fa8346a
--- /dev/null
+++ b/vendor/github.com/btcsuite/btcd/btcec/v2/doc.go
@@ -0,0 +1,21 @@
+// Copyright (c) 2013-2014 The btcsuite developers
+// Use of this source code is governed by an ISC
+// license that can be found in the LICENSE file.
+
+/*
+Package btcec implements support for the elliptic curves needed for bitcoin.
+
+Bitcoin uses elliptic curve cryptography using koblitz curves
+(specifically secp256k1) for cryptographic functions. See
+http://www.secg.org/collateral/sec2_final.pdf for details on the
+standard.
+
+This package provides the data structures and functions implementing the
+crypto/elliptic Curve interface in order to permit using these curves
+with the standard crypto/ecdsa package provided with go. Helper
+functionality is provided to parse signatures and public keys from
+standard formats. It was designed for use with btcd, but should be
+general enough for other uses of elliptic curve crypto. It was originally based
+on some initial work by ThePiachu, but has significantly diverged since then.
+*/
+package btcec
diff --git a/vendor/github.com/btcsuite/btcd/btcec/v2/error.go b/vendor/github.com/btcsuite/btcd/btcec/v2/error.go
new file mode 100644
index 0000000..df6ec67
--- /dev/null
+++ b/vendor/github.com/btcsuite/btcd/btcec/v2/error.go
@@ -0,0 +1,24 @@
+// Copyright (c) 2013-2021 The btcsuite developers
+// Copyright (c) 2015-2021 The Decred developers
+
+package btcec
+
+import (
+ secp "github.com/decred/dcrd/dcrec/secp256k1/v4"
+)
+
+// Error identifies an error related to public key cryptography using a
+// sec256k1 curve. It has full support for errors.Is and errors.As, so the
+// caller can ascertain the specific reason for the error by checking the
+// underlying error.
+type Error = secp.Error
+
+// ErrorKind identifies a kind of error. It has full support for errors.Is and
+// errors.As, so the caller can directly check against an error kind when
+// determining the reason for an error.
+type ErrorKind = secp.ErrorKind
+
+// makeError creates an secp.Error given a set of arguments.
+func makeError(kind ErrorKind, desc string) Error {
+ return Error{Err: kind, Description: desc}
+}
diff --git a/vendor/github.com/btcsuite/btcd/btcec/v2/field.go b/vendor/github.com/btcsuite/btcd/btcec/v2/field.go
new file mode 100644
index 0000000..fef6f34
--- /dev/null
+++ b/vendor/github.com/btcsuite/btcd/btcec/v2/field.go
@@ -0,0 +1,43 @@
+package btcec
+
+import secp "github.com/decred/dcrd/dcrec/secp256k1/v4"
+
+// FieldVal implements optimized fixed-precision arithmetic over the secp256k1
+// finite field. This means all arithmetic is performed modulo
+// '0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f'.
+//
+// WARNING: Since it is so important for the field arithmetic to be extremely
+// fast for high performance crypto, this type does not perform any validation
+// of documented preconditions where it ordinarily would. As a result, it is
+// IMPERATIVE for callers to understand some key concepts that are described
+// below and ensure the methods are called with the necessary preconditions
+// that each method is documented with. For example, some methods only give the
+// correct result if the field value is normalized and others require the field
+// values involved to have a maximum magnitude and THERE ARE NO EXPLICIT CHECKS
+// TO ENSURE THOSE PRECONDITIONS ARE SATISFIED. This does, unfortunately, make
+// the type more difficult to use correctly and while I typically prefer to
+// ensure all state and input is valid for most code, this is a bit of an
+// exception because those extra checks really add up in what ends up being
+// critical hot paths.
+//
+// The first key concept when working with this type is normalization. In order
+// to avoid the need to propagate a ton of carries, the internal representation
+// provides additional overflow bits for each word of the overall 256-bit
+// value. This means that there are multiple internal representations for the
+// same value and, as a result, any methods that rely on comparison of the
+// value, such as equality and oddness determination, require the caller to
+// provide a normalized value.
+//
+// The second key concept when working with this type is magnitude. As
+// previously mentioned, the internal representation provides additional
+// overflow bits which means that the more math operations that are performed
+// on the field value between normalizations, the more those overflow bits
+// accumulate. The magnitude is effectively that maximum possible number of
+// those overflow bits that could possibly be required as a result of a given
+// operation. Since there are only a limited number of overflow bits available,
+// this implies that the max possible magnitude MUST be tracked by the caller
+// and the caller MUST normalize the field value if a given operation would
+// cause the magnitude of the result to exceed the max allowed value.
+//
+// IMPORTANT: The max allowed magnitude of a field value is 64.
+type FieldVal = secp.FieldVal
diff --git a/vendor/github.com/btcsuite/btcd/btcec/v2/modnscalar.go b/vendor/github.com/btcsuite/btcd/btcec/v2/modnscalar.go
new file mode 100644
index 0000000..939b0c1
--- /dev/null
+++ b/vendor/github.com/btcsuite/btcd/btcec/v2/modnscalar.go
@@ -0,0 +1,45 @@
+// Copyright (c) 2013-2021 The btcsuite developers
+// Copyright (c) 2015-2021 The Decred developers
+
+package btcec
+
+import (
+ secp "github.com/decred/dcrd/dcrec/secp256k1/v4"
+)
+
+// ModNScalar implements optimized 256-bit constant-time fixed-precision
+// arithmetic over the secp256k1 group order. This means all arithmetic is
+// performed modulo:
+//
+// 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141
+//
+// It only implements the arithmetic needed for elliptic curve operations,
+// however, the operations that are not implemented can typically be worked
+// around if absolutely needed. For example, subtraction can be performed by
+// adding the negation.
+//
+// Should it be absolutely necessary, conversion to the standard library
+// math/big.Int can be accomplished by using the Bytes method, slicing the
+// resulting fixed-size array, and feeding it to big.Int.SetBytes. However,
+// that should typically be avoided when possible as conversion to big.Ints
+// requires allocations, is not constant time, and is slower when working modulo
+// the group order.
+type ModNScalar = secp.ModNScalar
+
+// NonceRFC6979 generates a nonce deterministically according to RFC 6979 using
+// HMAC-SHA256 for the hashing function. It takes a 32-byte hash as an input
+// and returns a 32-byte nonce to be used for deterministic signing. The extra
+// and version arguments are optional, but allow additional data to be added to
+// the input of the HMAC. When provided, the extra data must be 32-bytes and
+// version must be 16 bytes or they will be ignored.
+//
+// Finally, the extraIterations parameter provides a method to produce a stream
+// of deterministic nonces to ensure the signing code is able to produce a nonce
+// that results in a valid signature in the extremely unlikely event the
+// original nonce produced results in an invalid signature (e.g. R == 0).
+// Signing code should start with 0 and increment it if necessary.
+func NonceRFC6979(privKey []byte, hash []byte, extra []byte, version []byte,
+ extraIterations uint32) *ModNScalar {
+
+ return secp.NonceRFC6979(privKey, hash, extra, version, extraIterations)
+}
diff --git a/vendor/github.com/btcsuite/btcd/btcec/v2/privkey.go b/vendor/github.com/btcsuite/btcd/btcec/v2/privkey.go
new file mode 100644
index 0000000..d0dbd8d
--- /dev/null
+++ b/vendor/github.com/btcsuite/btcd/btcec/v2/privkey.go
@@ -0,0 +1,37 @@
+// Copyright (c) 2013-2016 The btcsuite developers
+// Use of this source code is governed by an ISC
+// license that can be found in the LICENSE file.
+
+package btcec
+
+import (
+ secp "github.com/decred/dcrd/dcrec/secp256k1/v4"
+)
+
+// PrivateKey wraps an ecdsa.PrivateKey as a convenience mainly for signing
+// things with the private key without having to directly import the ecdsa
+// package.
+type PrivateKey = secp.PrivateKey
+
+// PrivKeyFromBytes returns a private and public key for `curve' based on the
+// private key passed as an argument as a byte slice.
+func PrivKeyFromBytes(pk []byte) (*PrivateKey, *PublicKey) {
+ privKey := secp.PrivKeyFromBytes(pk)
+
+ return privKey, privKey.PubKey()
+}
+
+// NewPrivateKey is a wrapper for ecdsa.GenerateKey that returns a PrivateKey
+// instead of the normal ecdsa.PrivateKey.
+func NewPrivateKey() (*PrivateKey, error) {
+ return secp.GeneratePrivateKey()
+}
+
+// PrivKeyFromScalar instantiates a new private key from a scalar encoded as a
+// big integer.
+func PrivKeyFromScalar(key *ModNScalar) *PrivateKey {
+ return &PrivateKey{Key: *key}
+}
+
+// PrivKeyBytesLen defines the length in bytes of a serialized private key.
+const PrivKeyBytesLen = 32
diff --git a/vendor/github.com/btcsuite/btcd/btcec/v2/pubkey.go b/vendor/github.com/btcsuite/btcd/btcec/v2/pubkey.go
new file mode 100644
index 0000000..2c3a5cc
--- /dev/null
+++ b/vendor/github.com/btcsuite/btcd/btcec/v2/pubkey.go
@@ -0,0 +1,88 @@
+// Copyright (c) 2013-2014 The btcsuite developers
+// Use of this source code is governed by an ISC
+// license that can be found in the LICENSE file.
+
+package btcec
+
+import (
+ secp "github.com/decred/dcrd/dcrec/secp256k1/v4"
+)
+
+// These constants define the lengths of serialized public keys.
+const (
+ // PubKeyBytesLenCompressed is the bytes length of a serialized compressed
+ // public key.
+ PubKeyBytesLenCompressed = 33
+)
+
+const (
+ pubkeyCompressed byte = 0x2 // y_bit + x coord
+ pubkeyUncompressed byte = 0x4 // x coord + y coord
+ pubkeyHybrid byte = 0x6 // y_bit + x coord + y coord
+)
+
+// IsCompressedPubKey returns true the passed serialized public key has
+// been encoded in compressed format, and false otherwise.
+func IsCompressedPubKey(pubKey []byte) bool {
+ // The public key is only compressed if it is the correct length and
+ // the format (first byte) is one of the compressed pubkey values.
+ return len(pubKey) == PubKeyBytesLenCompressed &&
+ (pubKey[0]&^byte(0x1) == pubkeyCompressed)
+}
+
+// ParsePubKey parses a public key for a koblitz curve from a bytestring into a
+// ecdsa.Publickey, verifying that it is valid. It supports compressed,
+// uncompressed and hybrid signature formats.
+func ParsePubKey(pubKeyStr []byte) (*PublicKey, error) {
+ return secp.ParsePubKey(pubKeyStr)
+}
+
+// PublicKey is an ecdsa.PublicKey with additional functions to
+// serialize in uncompressed, compressed, and hybrid formats.
+type PublicKey = secp.PublicKey
+
+// NewPublicKey instantiates a new public key with the given x and y
+// coordinates.
+//
+// It should be noted that, unlike ParsePubKey, since this accepts arbitrary x
+// and y coordinates, it allows creation of public keys that are not valid
+// points on the secp256k1 curve. The IsOnCurve method of the returned instance
+// can be used to determine validity.
+func NewPublicKey(x, y *FieldVal) *PublicKey {
+ return secp.NewPublicKey(x, y)
+}
+
+// SerializedKey is a type for representing a public key in its compressed
+// serialized form.
+//
+// NOTE: This type is useful when using public keys as keys in maps.
+type SerializedKey [PubKeyBytesLenCompressed]byte
+
+// ToPubKey returns the public key parsed from the serialized key.
+func (s SerializedKey) ToPubKey() (*PublicKey, error) {
+ return ParsePubKey(s[:])
+}
+
+// SchnorrSerialized returns the Schnorr serialized, x-only 32-byte
+// representation of the serialized key.
+func (s SerializedKey) SchnorrSerialized() [32]byte {
+ var serializedSchnorr [32]byte
+ copy(serializedSchnorr[:], s[1:])
+ return serializedSchnorr
+}
+
+// CopyBytes returns a copy of the underlying array as a byte slice.
+func (s SerializedKey) CopyBytes() []byte {
+ c := make([]byte, PubKeyBytesLenCompressed)
+ copy(c, s[:])
+
+ return c
+}
+
+// ToSerialized serializes a public key into its compressed form.
+func ToSerialized(pubKey *PublicKey) SerializedKey {
+ var serialized SerializedKey
+ copy(serialized[:], pubKey.SerializeCompressed())
+
+ return serialized
+}
diff --git a/vendor/github.com/btcsuite/btcd/btcec/v2/schnorr/error.go b/vendor/github.com/btcsuite/btcd/btcec/v2/schnorr/error.go
new file mode 100644
index 0000000..4014339
--- /dev/null
+++ b/vendor/github.com/btcsuite/btcd/btcec/v2/schnorr/error.go
@@ -0,0 +1,25 @@
+// Copyright (c) 2013-2017 The btcsuite developers
+// Copyright (c) 2015-2021 The Decred developers
+// Use of this source code is governed by an ISC
+// license that can be found in the LICENSE file.
+
+package schnorr
+
+import (
+ ecdsa_schnorr "github.com/decred/dcrd/dcrec/secp256k1/v4/schnorr"
+)
+
+// ErrorKind identifies a kind of error. It has full support for errors.Is
+// and errors.As, so the caller can directly check against an error kind
+// when determining the reason for an error.
+type ErrorKind = ecdsa_schnorr.ErrorKind
+
+// Error identifies an error related to a schnorr signature. It has full
+// support for errors.Is and errors.As, so the caller can ascertain the
+// specific reason for the error by checking the underlying error.
+type Error = ecdsa_schnorr.Error
+
+// signatureError creates an Error given a set of arguments.
+func signatureError(kind ErrorKind, desc string) Error {
+ return Error{Err: kind, Description: desc}
+}
diff --git a/vendor/github.com/btcsuite/btcd/btcec/v2/schnorr/pubkey.go b/vendor/github.com/btcsuite/btcd/btcec/v2/schnorr/pubkey.go
new file mode 100644
index 0000000..f5d2ca4
--- /dev/null
+++ b/vendor/github.com/btcsuite/btcd/btcec/v2/schnorr/pubkey.go
@@ -0,0 +1,49 @@
+// Copyright (c) 2013-2017 The btcsuite developers
+// Copyright (c) 2015-2021 The Decred developers
+// Use of this source code is governed by an ISC
+// license that can be found in the LICENSE file.
+
+package schnorr
+
+import (
+ "fmt"
+
+ "github.com/btcsuite/btcd/btcec/v2"
+ secp "github.com/decred/dcrd/dcrec/secp256k1/v4"
+)
+
+// These constants define the lengths of serialized public keys.
+const (
+ PubKeyBytesLen = 32
+)
+
+// ParsePubKey parses a public key for a koblitz curve from a bytestring into a
+// btcec.Publickey, verifying that it is valid. It only supports public keys in
+// the BIP-340 32-byte format.
+func ParsePubKey(pubKeyStr []byte) (*btcec.PublicKey, error) {
+ if pubKeyStr == nil {
+ err := fmt.Errorf("nil pubkey byte string")
+ return nil, err
+ }
+ if len(pubKeyStr) != PubKeyBytesLen {
+ err := fmt.Errorf("bad pubkey byte string size (want %v, have %v)",
+ PubKeyBytesLen, len(pubKeyStr))
+ return nil, err
+ }
+
+ // We'll manually prepend the compressed byte so we can re-use the
+ // existing pubkey parsing routine of the main btcec package.
+ var keyCompressed [btcec.PubKeyBytesLenCompressed]byte
+ keyCompressed[0] = secp.PubKeyFormatCompressedEven
+ copy(keyCompressed[1:], pubKeyStr)
+
+ return btcec.ParsePubKey(keyCompressed[:])
+}
+
+// SerializePubKey serializes a public key as specified by BIP 340. Public keys
+// in this format are 32 bytes in length, and are assumed to have an even y
+// coordinate.
+func SerializePubKey(pub *btcec.PublicKey) []byte {
+ pBytes := pub.SerializeCompressed()
+ return pBytes[1:]
+}
diff --git a/vendor/github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go b/vendor/github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go
new file mode 100644
index 0000000..8876a60
--- /dev/null
+++ b/vendor/github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go
@@ -0,0 +1,538 @@
+// Copyright (c) 2013-2022 The btcsuite developers
+
+package schnorr
+
+import (
+ "fmt"
+
+ "github.com/btcsuite/btcd/btcec/v2"
+ "github.com/btcsuite/btcd/chaincfg/chainhash"
+ secp "github.com/decred/dcrd/dcrec/secp256k1/v4"
+ ecdsa_schnorr "github.com/decred/dcrd/dcrec/secp256k1/v4/schnorr"
+)
+
+const (
+ // SignatureSize is the size of an encoded Schnorr signature.
+ SignatureSize = 64
+
+ // scalarSize is the size of an encoded big endian scalar.
+ scalarSize = 32
+)
+
+var (
+ // rfc6979ExtraDataV0 is the extra data to feed to RFC6979 when
+ // generating the deterministic nonce for the BIP-340 scheme. This
+ // ensures the same nonce is not generated for the same message and key
+ // as for other signing algorithms such as ECDSA.
+ //
+ // It is equal to SHA-256([]byte("BIP-340")).
+ rfc6979ExtraDataV0 = [32]uint8{
+ 0xa3, 0xeb, 0x4c, 0x18, 0x2f, 0xae, 0x7e, 0xf4,
+ 0xe8, 0x10, 0xc6, 0xee, 0x13, 0xb0, 0xe9, 0x26,
+ 0x68, 0x6d, 0x71, 0xe8, 0x7f, 0x39, 0x4f, 0x79,
+ 0x9c, 0x00, 0xa5, 0x21, 0x03, 0xcb, 0x4e, 0x17,
+ }
+)
+
+// Signature is a type representing a Schnorr signature.
+type Signature struct {
+ r btcec.FieldVal
+ s btcec.ModNScalar
+}
+
+// NewSignature instantiates a new signature given some r and s values.
+func NewSignature(r *btcec.FieldVal, s *btcec.ModNScalar) *Signature {
+ var sig Signature
+ sig.r.Set(r).Normalize()
+ sig.s.Set(s)
+ return &sig
+}
+
+// Serialize returns the Schnorr signature in the more strict format.
+//
+// The signatures are encoded as
+//
+// sig[0:32] x coordinate of the point R, encoded as a big-endian uint256
+// sig[32:64] s, encoded also as big-endian uint256
+func (sig Signature) Serialize() []byte {
+ // Total length of returned signature is the length of r and s.
+ var b [SignatureSize]byte
+ sig.r.PutBytesUnchecked(b[0:32])
+ sig.s.PutBytesUnchecked(b[32:64])
+ return b[:]
+}
+
+// ParseSignature parses a signature according to the BIP-340 specification and
+// enforces the following additional restrictions specific to secp256k1:
+//
+// - The r component must be in the valid range for secp256k1 field elements
+// - The s component must be in the valid range for secp256k1 scalars
+func ParseSignature(sig []byte) (*Signature, error) {
+ // The signature must be the correct length.
+ sigLen := len(sig)
+ if sigLen < SignatureSize {
+ str := fmt.Sprintf("malformed signature: too short: %d < %d", sigLen,
+ SignatureSize)
+ return nil, signatureError(ecdsa_schnorr.ErrSigTooShort, str)
+ }
+ if sigLen > SignatureSize {
+ str := fmt.Sprintf("malformed signature: too long: %d > %d", sigLen,
+ SignatureSize)
+ return nil, signatureError(ecdsa_schnorr.ErrSigTooLong, str)
+ }
+
+ // The signature is validly encoded at this point, however, enforce
+ // additional restrictions to ensure r is in the range [0, p-1], and s is in
+ // the range [0, n-1] since valid Schnorr signatures are required to be in
+ // that range per spec.
+ var r btcec.FieldVal
+ if overflow := r.SetByteSlice(sig[0:32]); overflow {
+ str := "invalid signature: r >= field prime"
+ return nil, signatureError(ecdsa_schnorr.ErrSigRTooBig, str)
+ }
+ var s btcec.ModNScalar
+ s.SetByteSlice(sig[32:64])
+
+ // Return the signature.
+ return NewSignature(&r, &s), nil
+}
+
+// IsEqual compares this Signature instance to the one passed, returning true
+// if both Signatures are equivalent. A signature is equivalent to another, if
+// they both have the same scalar value for R and S.
+func (sig Signature) IsEqual(otherSig *Signature) bool {
+ return sig.r.Equals(&otherSig.r) && sig.s.Equals(&otherSig.s)
+}
+
+// schnorrVerify attempt to verify the signature for the provided hash and
+// secp256k1 public key and either returns nil if successful or a specific error
+// indicating why it failed if not successful.
+//
+// This differs from the exported Verify method in that it returns a specific
+// error to support better testing while the exported method simply returns a
+// bool indicating success or failure.
+func schnorrVerify(sig *Signature, hash []byte, pubKeyBytes []byte) error {
+ // The algorithm for producing a BIP-340 signature is described in
+ // README.md and is reproduced here for reference:
+ //
+ // 1. Fail if m is not 32 bytes
+ // 2. P = lift_x(int(pk)).
+ // 3. r = int(sig[0:32]); fail is r >= p.
+ // 4. s = int(sig[32:64]); fail if s >= n.
+ // 5. e = int(tagged_hash("BIP0340/challenge", bytes(r) || bytes(P) || M)) mod n.
+ // 6. R = s*G - e*P
+ // 7. Fail if is_infinite(R)
+ // 8. Fail if not hash_even_y(R)
+ // 9. Fail is x(R) != r.
+ // 10. Return success iff failure did not occur before reaching this point.
+
+ // Step 1.
+ //
+ // Fail if m is not 32 bytes
+ if len(hash) != scalarSize {
+ str := fmt.Sprintf("wrong size for message (got %v, want %v)",
+ len(hash), scalarSize)
+ return signatureError(ecdsa_schnorr.ErrInvalidHashLen, str)
+ }
+
+ // Step 2.
+ //
+ // P = lift_x(int(pk))
+ //
+ // Fail if P is not a point on the curve
+ pubKey, err := ParsePubKey(pubKeyBytes)
+ if err != nil {
+ return err
+ }
+ if !pubKey.IsOnCurve() {
+ str := "pubkey point is not on curve"
+ return signatureError(ecdsa_schnorr.ErrPubKeyNotOnCurve, str)
+ }
+
+ // Step 3.
+ //
+ // Fail if r >= p
+ //
+ // Note this is already handled by the fact r is a field element.
+
+ // Step 4.
+ //
+ // Fail if s >= n
+ //
+ // Note this is already handled by the fact s is a mod n scalar.
+
+ // Step 5.
+ //
+ // e = int(tagged_hash("BIP0340/challenge", bytes(r) || bytes(P) || M)) mod n.
+ var rBytes [32]byte
+ sig.r.PutBytesUnchecked(rBytes[:])
+ pBytes := SerializePubKey(pubKey)
+
+ commitment := chainhash.TaggedHash(
+ chainhash.TagBIP0340Challenge, rBytes[:], pBytes, hash,
+ )
+
+ var e btcec.ModNScalar
+ e.SetBytes((*[32]byte)(commitment))
+
+ // Negate e here so we can use AddNonConst below to subtract the s*G
+ // point from e*P.
+ e.Negate()
+
+ // Step 6.
+ //
+ // R = s*G - e*P
+ var P, R, sG, eP btcec.JacobianPoint
+ pubKey.AsJacobian(&P)
+ btcec.ScalarBaseMultNonConst(&sig.s, &sG)
+ btcec.ScalarMultNonConst(&e, &P, &eP)
+ btcec.AddNonConst(&sG, &eP, &R)
+
+ // Step 7.
+ //
+ // Fail if R is the point at infinity
+ if (R.X.IsZero() && R.Y.IsZero()) || R.Z.IsZero() {
+ str := "calculated R point is the point at infinity"
+ return signatureError(ecdsa_schnorr.ErrSigRNotOnCurve, str)
+ }
+
+ // Step 8.
+ //
+ // Fail if R.y is odd
+ //
+ // Note that R must be in affine coordinates for this check.
+ R.ToAffine()
+ if R.Y.IsOdd() {
+ str := "calculated R y-value is odd"
+ return signatureError(ecdsa_schnorr.ErrSigRYIsOdd, str)
+ }
+
+ // Step 9.
+ //
+ // Verified if R.x == r
+ //
+ // Note that R must be in affine coordinates for this check.
+ if !sig.r.Equals(&R.X) {
+ str := "calculated R point was not given R"
+ return signatureError(ecdsa_schnorr.ErrUnequalRValues, str)
+ }
+
+ // Step 10.
+ //
+ // Return success iff failure did not occur before reaching this point.
+ return nil
+}
+
+// Verify returns whether or not the signature is valid for the provided hash
+// and secp256k1 public key.
+func (sig *Signature) Verify(hash []byte, pubKey *btcec.PublicKey) bool {
+ pubkeyBytes := SerializePubKey(pubKey)
+ return schnorrVerify(sig, hash, pubkeyBytes) == nil
+}
+
+// zeroArray zeroes the memory of a scalar array.
+func zeroArray(a *[scalarSize]byte) {
+ for i := 0; i < scalarSize; i++ {
+ a[i] = 0x00
+ }
+}
+
+// schnorrSign generates a BIP-340 signature over the secp256k1 curve for the
+// provided hash (which should be the result of hashing a larger message) using
+// the given nonce and private key. The produced signature is deterministic
+// (same message, nonce, and key yield the same signature) and canonical.
+//
+// WARNING: The hash MUST be 32 bytes and both the nonce and private keys must
+// NOT be 0. Since this is an internal use function, these preconditions MUST
+// be satisfied by the caller.
+func schnorrSign(privKey, nonce *btcec.ModNScalar, pubKey *btcec.PublicKey, hash []byte,
+ opts *signOptions) (*Signature, error) {
+
+ // The algorithm for producing a BIP-340 signature is described in
+ // README.md and is reproduced here for reference:
+ //
+ // G = curve generator
+ // n = curve order
+ // d = private key
+ // m = message
+ // a = input randomness
+ // r, s = signature
+ //
+ // 1. d' = int(d)
+ // 2. Fail if m is not 32 bytes
+ // 3. Fail if d = 0 or d >= n
+ // 4. P = d'*G
+ // 5. Negate d if P.y is odd
+ // 6. t = bytes(d) xor tagged_hash("BIP0340/aux", t || bytes(P) || m)
+ // 7. rand = tagged_hash("BIP0340/nonce", a)
+ // 8. k' = int(rand) mod n
+ // 9. Fail if k' = 0
+ // 10. R = 'k*G
+ // 11. Negate k if R.y id odd
+ // 12. e = tagged_hash("BIP0340/challenge", bytes(R) || bytes(P) || m) mod n
+ // 13. sig = bytes(R) || bytes((k + e*d)) mod n
+ // 14. If Verify(bytes(P), m, sig) fails, abort.
+ // 15. return sig.
+ //
+ // Note that the set of functional options passed in may modify the
+ // above algorithm. Namely if CustomNonce is used, then steps 6-8 are
+ // replaced with a process that generates the nonce using rfc6979. If
+ // FastSign is passed, then we skip set 14.
+
+ // NOTE: Steps 1-9 are performed by the caller.
+
+ //
+ // Step 10.
+ //
+ // R = kG
+ var R btcec.JacobianPoint
+ k := *nonce
+ btcec.ScalarBaseMultNonConst(&k, &R)
+
+ // Step 11.
+ //
+ // Negate nonce k if R.y is odd (R.y is the y coordinate of the point R)
+ //
+ // Note that R must be in affine coordinates for this check.
+ R.ToAffine()
+ if R.Y.IsOdd() {
+ k.Negate()
+ }
+
+ // Step 12.
+ //
+ // e = tagged_hash("BIP0340/challenge", bytes(R) || bytes(P) || m) mod n
+ pBytes := SerializePubKey(pubKey)
+ commitment := chainhash.TaggedHash(
+ chainhash.TagBIP0340Challenge, R.X.Bytes()[:], pBytes, hash,
+ )
+
+ var e btcec.ModNScalar
+ if overflow := e.SetBytes((*[32]byte)(commitment)); overflow != 0 {
+ k.Zero()
+ str := "hash of (r || P || m) too big"
+ return nil, signatureError(ecdsa_schnorr.ErrSchnorrHashValue, str)
+ }
+
+ // Step 13.
+ //
+ // s = k + e*d mod n
+ s := new(btcec.ModNScalar).Mul2(&e, privKey).Add(&k)
+ k.Zero()
+
+ sig := NewSignature(&R.X, s)
+
+ // Step 14.
+ //
+ // If Verify(bytes(P), m, sig) fails, abort.
+ if !opts.fastSign {
+ if err := schnorrVerify(sig, hash, pBytes); err != nil {
+ return nil, err
+ }
+ }
+
+ // Step 15.
+ //
+ // Return (r, s)
+ return sig, nil
+}
+
+// SignOption is a functional option argument that allows callers to modify the
+// way we generate BIP-340 schnorr signatures.
+type SignOption func(*signOptions)
+
+// signOptions houses the set of functional options that can be used to modify
+// the method used to generate the BIP-340 signature.
+type signOptions struct {
+ // fastSign determines if we'll skip the check at the end of the routine
+ // where we attempt to verify the produced signature.
+ fastSign bool
+
+ // authNonce allows the user to pass in their own nonce information, which
+ // is useful for schemes like mu-sig.
+ authNonce *[32]byte
+}
+
+// defaultSignOptions returns the default set of signing operations.
+func defaultSignOptions() *signOptions {
+ return &signOptions{}
+}
+
+// FastSign forces signing to skip the extra verification step at the end.
+// Performance sensitive applications may opt to use this option to speed up the
+// signing operation.
+func FastSign() SignOption {
+ return func(o *signOptions) {
+ o.fastSign = true
+ }
+}
+
+// CustomNonce allows users to pass in a custom set of auxData that's used as
+// input randomness to generate the nonce used during signing. Users may want
+// to specify this custom value when using multi-signatures schemes such as
+// Mu-Sig2. If this option isn't set, then rfc6979 will be used to generate the
+// nonce material.
+func CustomNonce(auxData [32]byte) SignOption {
+ return func(o *signOptions) {
+ o.authNonce = &auxData
+ }
+}
+
+// Sign generates an BIP-340 signature over the secp256k1 curve for the
+// provided hash (which should be the result of hashing a larger message) using
+// the given private key. The produced signature is deterministic (same
+// message and same key yield the same signature) and canonical.
+//
+// Note that the current signing implementation has a few remaining variable
+// time aspects which make use of the private key and the generated nonce,
+// which can expose the signer to constant time attacks. As a result, this
+// function should not be used in situations where there is the possibility of
+// someone having EM field/cache/etc access.
+func Sign(privKey *btcec.PrivateKey, hash []byte,
+ signOpts ...SignOption) (*Signature, error) {
+
+ // First, parse the set of optional signing options.
+ opts := defaultSignOptions()
+ for _, option := range signOpts {
+ option(opts)
+ }
+
+ // The algorithm for producing a BIP-340 signature is described in
+ // README.md and is reproduced here for reference:
+ //
+ // G = curve generator
+ // n = curve order
+ // d = private key
+ // m = message
+ // a = input randomness
+ // r, s = signature
+ //
+ // 1. d' = int(d)
+ // 2. Fail if m is not 32 bytes
+ // 3. Fail if d = 0 or d >= n
+ // 4. P = d'*G
+ // 5. Negate d if P.y is odd
+ // 6. t = bytes(d) xor tagged_hash("BIP0340/aux", t || bytes(P) || m)
+ // 7. rand = tagged_hash("BIP0340/nonce", a)
+ // 8. k' = int(rand) mod n
+ // 9. Fail if k' = 0
+ // 10. R = 'k*G
+ // 11. Negate k if R.y id odd
+ // 12. e = tagged_hash("BIP0340/challenge", bytes(R) || bytes(P) || mod) mod n
+ // 13. sig = bytes(R) || bytes((k + e*d)) mod n
+ // 14. If Verify(bytes(P), m, sig) fails, abort.
+ // 15. return sig.
+ //
+ // Note that the set of functional options passed in may modify the
+ // above algorithm. Namely if CustomNonce is used, then steps 6-8 are
+ // replaced with a process that generates the nonce using rfc6979. If
+ // FastSign is passed, then we skip set 14.
+
+ // Step 1.
+ //
+ // d' = int(d)
+ var privKeyScalar btcec.ModNScalar
+ privKeyScalar.Set(&privKey.Key)
+
+ // Step 2.
+ //
+ // Fail if m is not 32 bytes
+ if len(hash) != scalarSize {
+ str := fmt.Sprintf("wrong size for message hash (got %v, want %v)",
+ len(hash), scalarSize)
+ return nil, signatureError(ecdsa_schnorr.ErrInvalidHashLen, str)
+ }
+
+ // Step 3.
+ //
+ // Fail if d = 0 or d >= n
+ if privKeyScalar.IsZero() {
+ str := "private key is zero"
+ return nil, signatureError(ecdsa_schnorr.ErrPrivateKeyIsZero, str)
+ }
+
+ // Step 4.
+ //
+ // P = 'd*G
+ pub := privKey.PubKey()
+
+ // Step 5.
+ //
+ // Negate d if P.y is odd.
+ pubKeyBytes := pub.SerializeCompressed()
+ if pubKeyBytes[0] == secp.PubKeyFormatCompressedOdd {
+ privKeyScalar.Negate()
+ }
+
+ // At this point, we check to see if a CustomNonce has been passed in,
+ // and if so, then we'll deviate from the main routine here by
+ // generating the nonce value as specified by BIP-0340.
+ if opts.authNonce != nil {
+ // Step 6.
+ //
+ // t = bytes(d) xor tagged_hash("BIP0340/aux", a)
+ privBytes := privKeyScalar.Bytes()
+ t := chainhash.TaggedHash(
+ chainhash.TagBIP0340Aux, (*opts.authNonce)[:],
+ )
+ for i := 0; i < len(t); i++ {
+ t[i] ^= privBytes[i]
+ }
+
+ // Step 7.
+ //
+ // rand = tagged_hash("BIP0340/nonce", t || bytes(P) || m)
+ //
+ // We snip off the first byte of the serialized pubkey, as we
+ // only need the x coordinate and not the market byte.
+ rand := chainhash.TaggedHash(
+ chainhash.TagBIP0340Nonce, t[:], pubKeyBytes[1:], hash,
+ )
+
+ // Step 8.
+ //
+ // k'= int(rand) mod n
+ var kPrime btcec.ModNScalar
+ kPrime.SetBytes((*[32]byte)(rand))
+
+ // Step 9.
+ //
+ // Fail if k' = 0
+ if kPrime.IsZero() {
+ str := fmt.Sprintf("generated nonce is zero")
+ return nil, signatureError(ecdsa_schnorr.ErrSchnorrHashValue, str)
+ }
+
+ sig, err := schnorrSign(&privKeyScalar, &kPrime, pub, hash, opts)
+ kPrime.Zero()
+ if err != nil {
+ return nil, err
+ }
+
+ return sig, nil
+ }
+
+ var privKeyBytes [scalarSize]byte
+ privKeyScalar.PutBytes(&privKeyBytes)
+ defer zeroArray(&privKeyBytes)
+ for iteration := uint32(0); ; iteration++ {
+ // Step 6-9.
+ //
+ // Use RFC6979 to generate a deterministic nonce k in [1, n-1]
+ // parameterized by the private key, message being signed, extra data
+ // that identifies the scheme, and an iteration count
+ k := btcec.NonceRFC6979(
+ privKeyBytes[:], hash, rfc6979ExtraDataV0[:], nil, iteration,
+ )
+
+ // Steps 10-15.
+ sig, err := schnorrSign(&privKeyScalar, k, pub, hash, opts)
+ k.Zero()
+ if err != nil {
+ // Try again with a new nonce.
+ continue
+ }
+
+ return sig, nil
+ }
+}
diff --git a/vendor/github.com/btcsuite/btcd/chaincfg/chainhash/LICENSE b/vendor/github.com/btcsuite/btcd/chaincfg/chainhash/LICENSE
new file mode 100644
index 0000000..46dcd39
--- /dev/null
+++ b/vendor/github.com/btcsuite/btcd/chaincfg/chainhash/LICENSE
@@ -0,0 +1,16 @@
+ISC License
+
+Copyright (c) 2013-2023 The btcsuite developers
+Copyright (c) 2015-2016 The Decred developers
+
+Permission to use, copy, modify, and distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
diff --git a/vendor/github.com/btcsuite/btcd/chaincfg/chainhash/README.md b/vendor/github.com/btcsuite/btcd/chaincfg/chainhash/README.md
new file mode 100644
index 0000000..b7ddf19
--- /dev/null
+++ b/vendor/github.com/btcsuite/btcd/chaincfg/chainhash/README.md
@@ -0,0 +1,41 @@
+chainhash
+=========
+
+[![Build Status](https://github.com/btcsuite/btcd/workflows/Build%20and%20Test/badge.svg)](https://github.com/btcsuite/btcd/actions)
+[![ISC License](http://img.shields.io/badge/license-ISC-blue.svg)](http://copyfree.org)
+[![GoDoc](https://img.shields.io/badge/godoc-reference-blue.svg)](https://pkg.go.dev/github.com/btcsuite/btcd/chaincfg/chainhash)
+=======
+
+chainhash provides a generic hash type and associated functions that allows the
+specific hash algorithm to be abstracted.
+
+## Installation and Updating
+
+```bash
+$ go get -u github.com/btcsuite/btcd/chaincfg/chainhash
+```
+
+## GPG Verification Key
+
+All official release tags are signed by Conformal so users can ensure the code
+has not been tampered with and is coming from the btcsuite developers. To
+verify the signature perform the following:
+
+- Download the public key from the Conformal website at
+ https://opensource.conformal.com/GIT-GPG-KEY-conformal.txt
+
+- Import the public key into your GPG keyring:
+ ```bash
+ gpg --import GIT-GPG-KEY-conformal.txt
+ ```
+
+- Verify the release tag with the following command where `TAG_NAME` is a
+ placeholder for the specific tag:
+ ```bash
+ git tag -v TAG_NAME
+ ```
+
+## License
+
+Package chainhash is licensed under the [copyfree](http://copyfree.org) ISC
+License.
diff --git a/vendor/github.com/btcsuite/btcd/chaincfg/chainhash/doc.go b/vendor/github.com/btcsuite/btcd/chaincfg/chainhash/doc.go
new file mode 100644
index 0000000..c3eb43d
--- /dev/null
+++ b/vendor/github.com/btcsuite/btcd/chaincfg/chainhash/doc.go
@@ -0,0 +1,5 @@
+// Package chainhash provides abstracted hash functionality.
+//
+// This package provides a generic hash type and associated functions that
+// allows the specific hash algorithm to be abstracted.
+package chainhash
diff --git a/vendor/github.com/btcsuite/btcd/chaincfg/chainhash/hash.go b/vendor/github.com/btcsuite/btcd/chaincfg/chainhash/hash.go
new file mode 100644
index 0000000..4aa7aeb
--- /dev/null
+++ b/vendor/github.com/btcsuite/btcd/chaincfg/chainhash/hash.go
@@ -0,0 +1,239 @@
+// Copyright (c) 2013-2016 The btcsuite developers
+// Copyright (c) 2015 The Decred developers
+// Use of this source code is governed by an ISC
+// license that can be found in the LICENSE file.
+
+package chainhash
+
+import (
+ "crypto/sha256"
+ "encoding/hex"
+ "encoding/json"
+ "fmt"
+)
+
+// HashSize of array used to store hashes. See Hash.
+const HashSize = 32
+
+// MaxHashStringSize is the maximum length of a Hash hash string.
+const MaxHashStringSize = HashSize * 2
+
+var (
+ // TagBIP0340Challenge is the BIP-0340 tag for challenges.
+ TagBIP0340Challenge = []byte("BIP0340/challenge")
+
+ // TagBIP0340Aux is the BIP-0340 tag for aux data.
+ TagBIP0340Aux = []byte("BIP0340/aux")
+
+ // TagBIP0340Nonce is the BIP-0340 tag for nonces.
+ TagBIP0340Nonce = []byte("BIP0340/nonce")
+
+ // TagTapSighash is the tag used by BIP 341 to generate the sighash
+ // flags.
+ TagTapSighash = []byte("TapSighash")
+
+ // TagTagTapLeaf is the message tag prefix used to compute the hash
+ // digest of a tapscript leaf.
+ TagTapLeaf = []byte("TapLeaf")
+
+ // TagTapBranch is the message tag prefix used to compute the
+ // hash digest of two tap leaves into a taproot branch node.
+ TagTapBranch = []byte("TapBranch")
+
+ // TagTapTweak is the message tag prefix used to compute the hash tweak
+ // used to enable a public key to commit to the taproot branch root
+ // for the witness program.
+ TagTapTweak = []byte("TapTweak")
+
+ // precomputedTags is a map containing the SHA-256 hash of the BIP-0340
+ // tags.
+ precomputedTags = map[string]Hash{
+ string(TagBIP0340Challenge): sha256.Sum256(TagBIP0340Challenge),
+ string(TagBIP0340Aux): sha256.Sum256(TagBIP0340Aux),
+ string(TagBIP0340Nonce): sha256.Sum256(TagBIP0340Nonce),
+ string(TagTapSighash): sha256.Sum256(TagTapSighash),
+ string(TagTapLeaf): sha256.Sum256(TagTapLeaf),
+ string(TagTapBranch): sha256.Sum256(TagTapBranch),
+ string(TagTapTweak): sha256.Sum256(TagTapTweak),
+ }
+)
+
+// ErrHashStrSize describes an error that indicates the caller specified a hash
+// string that has too many characters.
+var ErrHashStrSize = fmt.Errorf("max hash string length is %v bytes", MaxHashStringSize)
+
+// Hash is used in several of the bitcoin messages and common structures. It
+// typically represents the double sha256 of data.
+type Hash [HashSize]byte
+
+// String returns the Hash as the hexadecimal string of the byte-reversed
+// hash.
+func (hash Hash) String() string {
+ for i := 0; i < HashSize/2; i++ {
+ hash[i], hash[HashSize-1-i] = hash[HashSize-1-i], hash[i]
+ }
+ return hex.EncodeToString(hash[:])
+}
+
+// CloneBytes returns a copy of the bytes which represent the hash as a byte
+// slice.
+//
+// NOTE: It is generally cheaper to just slice the hash directly thereby reusing
+// the same bytes rather than calling this method.
+func (hash *Hash) CloneBytes() []byte {
+ newHash := make([]byte, HashSize)
+ copy(newHash, hash[:])
+
+ return newHash
+}
+
+// SetBytes sets the bytes which represent the hash. An error is returned if
+// the number of bytes passed in is not HashSize.
+func (hash *Hash) SetBytes(newHash []byte) error {
+ nhlen := len(newHash)
+ if nhlen != HashSize {
+ return fmt.Errorf("invalid hash length of %v, want %v", nhlen,
+ HashSize)
+ }
+ copy(hash[:], newHash)
+
+ return nil
+}
+
+// IsEqual returns true if target is the same as hash.
+func (hash *Hash) IsEqual(target *Hash) bool {
+ if hash == nil && target == nil {
+ return true
+ }
+ if hash == nil || target == nil {
+ return false
+ }
+ return *hash == *target
+}
+
+// MarshalJSON serialises the hash as a JSON appropriate string value.
+func (hash Hash) MarshalJSON() ([]byte, error) {
+ return json.Marshal(hash.String())
+}
+
+// UnmarshalJSON parses the hash with JSON appropriate string value.
+func (hash *Hash) UnmarshalJSON(input []byte) error {
+ // If the first byte indicates an array, the hash could have been marshalled
+ // using the legacy method and e.g. persisted.
+ if len(input) > 0 && input[0] == '[' {
+ return decodeLegacy(hash, input)
+ }
+
+ var sh string
+ err := json.Unmarshal(input, &sh)
+ if err != nil {
+ return err
+ }
+ newHash, err := NewHashFromStr(sh)
+ if err != nil {
+ return err
+ }
+
+ return hash.SetBytes(newHash[:])
+}
+
+// NewHash returns a new Hash from a byte slice. An error is returned if
+// the number of bytes passed in is not HashSize.
+func NewHash(newHash []byte) (*Hash, error) {
+ var sh Hash
+ err := sh.SetBytes(newHash)
+ if err != nil {
+ return nil, err
+ }
+ return &sh, err
+}
+
+// TaggedHash implements the tagged hash scheme described in BIP-340. We use
+// sha-256 to bind a message hash to a specific context using a tag:
+// sha256(sha256(tag) || sha256(tag) || msg).
+func TaggedHash(tag []byte, msgs ...[]byte) *Hash {
+ // Check to see if we've already pre-computed the hash of the tag. If
+ // so then this'll save us an extra sha256 hash.
+ shaTag, ok := precomputedTags[string(tag)]
+ if !ok {
+ shaTag = sha256.Sum256(tag)
+ }
+
+ // h = sha256(sha256(tag) || sha256(tag) || msg)
+ h := sha256.New()
+ h.Write(shaTag[:])
+ h.Write(shaTag[:])
+
+ for _, msg := range msgs {
+ h.Write(msg)
+ }
+
+ taggedHash := h.Sum(nil)
+
+ // The function can't error out since the above hash is guaranteed to
+ // be 32 bytes.
+ hash, _ := NewHash(taggedHash)
+
+ return hash
+}
+
+// NewHashFromStr creates a Hash from a hash string. The string should be
+// the hexadecimal string of a byte-reversed hash, but any missing characters
+// result in zero padding at the end of the Hash.
+func NewHashFromStr(hash string) (*Hash, error) {
+ ret := new(Hash)
+ err := Decode(ret, hash)
+ if err != nil {
+ return nil, err
+ }
+ return ret, nil
+}
+
+// Decode decodes the byte-reversed hexadecimal string encoding of a Hash to a
+// destination.
+func Decode(dst *Hash, src string) error {
+ // Return error if hash string is too long.
+ if len(src) > MaxHashStringSize {
+ return ErrHashStrSize
+ }
+
+ // Hex decoder expects the hash to be a multiple of two. When not, pad
+ // with a leading zero.
+ var srcBytes []byte
+ if len(src)%2 == 0 {
+ srcBytes = []byte(src)
+ } else {
+ srcBytes = make([]byte, 1+len(src))
+ srcBytes[0] = '0'
+ copy(srcBytes[1:], src)
+ }
+
+ // Hex decode the source bytes to a temporary destination.
+ var reversedHash Hash
+ _, err := hex.Decode(reversedHash[HashSize-hex.DecodedLen(len(srcBytes)):], srcBytes)
+ if err != nil {
+ return err
+ }
+
+ // Reverse copy from the temporary hash to destination. Because the
+ // temporary was zeroed, the written result will be correctly padded.
+ for i, b := range reversedHash[:HashSize/2] {
+ dst[i], dst[HashSize-1-i] = reversedHash[HashSize-1-i], b
+ }
+
+ return nil
+}
+
+// decodeLegacy decodes an Hash that has been encoded with the legacy method
+// (i.e. represented as a bytes array) to a destination.
+func decodeLegacy(dst *Hash, src []byte) error {
+ var hashBytes []byte
+ err := json.Unmarshal(src, &hashBytes)
+ if err != nil {
+ return err
+ }
+ if len(hashBytes) != HashSize {
+ return ErrHashStrSize
+ }
+ return dst.SetBytes(hashBytes)
+}
diff --git a/vendor/github.com/btcsuite/btcd/chaincfg/chainhash/hashfuncs.go b/vendor/github.com/btcsuite/btcd/chaincfg/chainhash/hashfuncs.go
new file mode 100644
index 0000000..5be8a4d
--- /dev/null
+++ b/vendor/github.com/btcsuite/btcd/chaincfg/chainhash/hashfuncs.go
@@ -0,0 +1,57 @@
+// Copyright (c) 2015 The Decred developers
+// Copyright (c) 2016-2017 The btcsuite developers
+// Use of this source code is governed by an ISC
+// license that can be found in the LICENSE file.
+
+package chainhash
+
+import (
+ "crypto/sha256"
+ "io"
+)
+
+// HashB calculates hash(b) and returns the resulting bytes.
+func HashB(b []byte) []byte {
+ hash := sha256.Sum256(b)
+ return hash[:]
+}
+
+// HashH calculates hash(b) and returns the resulting bytes as a Hash.
+func HashH(b []byte) Hash {
+ return Hash(sha256.Sum256(b))
+}
+
+// DoubleHashB calculates hash(hash(b)) and returns the resulting bytes.
+func DoubleHashB(b []byte) []byte {
+ first := sha256.Sum256(b)
+ second := sha256.Sum256(first[:])
+ return second[:]
+}
+
+// DoubleHashH calculates hash(hash(b)) and returns the resulting bytes as a
+// Hash.
+func DoubleHashH(b []byte) Hash {
+ first := sha256.Sum256(b)
+ return Hash(sha256.Sum256(first[:]))
+}
+
+// DoubleHashRaw calculates hash(hash(w)) where w is the resulting bytes from
+// the given serialize function and returns the resulting bytes as a Hash.
+func DoubleHashRaw(serialize func(w io.Writer) error) Hash {
+ // Encode the transaction into the hash. Ignore the error returns
+ // since the only way the encode could fail is being out of memory
+ // or due to nil pointers, both of which would cause a run-time panic.
+ h := sha256.New()
+ _ = serialize(h)
+
+ // This buf is here because Sum() will append the result to the passed
+ // in byte slice. Pre-allocating here saves an allocation on the second
+ // hash as we can reuse it. This allocation also does not escape to the
+ // heap, saving an allocation.
+ buf := make([]byte, 0, HashSize)
+ first := h.Sum(buf)
+ h.Reset()
+ h.Write(first)
+ res := h.Sum(buf)
+ return *(*Hash)(res)
+}
diff --git a/vendor/github.com/decred/dcrd/crypto/blake256/LICENSE b/vendor/github.com/decred/dcrd/crypto/blake256/LICENSE
new file mode 100644
index 0000000..fdf6d88
--- /dev/null
+++ b/vendor/github.com/decred/dcrd/crypto/blake256/LICENSE
@@ -0,0 +1,17 @@
+ISC License
+
+Copyright (c) 2013-2017 The btcsuite developers
+Copyright (c) 2015-2024 The Decred developers
+Copyright (c) 2017 The Lightning Network Developers
+
+Permission to use, copy, modify, and distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
diff --git a/vendor/github.com/decred/dcrd/crypto/blake256/README.md b/vendor/github.com/decred/dcrd/crypto/blake256/README.md
new file mode 100644
index 0000000..21280c0
--- /dev/null
+++ b/vendor/github.com/decred/dcrd/crypto/blake256/README.md
@@ -0,0 +1,190 @@
+blake256
+========
+
+[![Build Status](https://github.com/decred/dcrd/workflows/Build%20and%20Test/badge.svg)](https://github.com/decred/dcrd/actions)
+[![ISC License](https://img.shields.io/badge/license-ISC-blue.svg)](http://copyfree.org)
+[![Doc](https://img.shields.io/badge/doc-reference-blue.svg)](https://pkg.go.dev/github.com/decred/dcrd/crypto/blake256)
+
+## Overview
+
+Package `blake256` implements the [BLAKE-256 and BLAKE-224 cryptographic hash
+functions](https://www.aumasson.jp/blake/blake.pdf) (SHA-3 candidate) in pure Go
+along with highly optimized SSE2, SSE4.1, and AVX acceleration.
+
+It provides an API that enables zero allocations and the ability to save and
+restore the intermediate state (also often called the midstate). The design
+philosophy has a strong on emphasis correctness, readability, and efficiency
+while also aiming to provide an ergonomic API.
+
+In addition to the zero allocation API, it also implements the standard library
+interfaces `hash.Hash`, `encoding.BinaryMarshaler`, and
+`encoding.BinaryUnmarshaler` for callers that are not as concerned about
+avoiding allocations. No dependencies beyond the standard library are required.
+
+A full suite of tests with 100% branch coverage and benchmarks are provided to
+help ensure proper functionality and analyze performance characteristics.
+
+The core assembly code to take advantage of the `amd64` SIMD vector extensions
+is generated with Go via [avo](https://github.com/mmcloughlin/avo).
+
+[Show me the benchmarks already](#benchmarks)!
+
+[Example Usage?](#examples)
+
+## Hashing Data
+
+The simplest way to hash data that is already serialized into bytes is via the
+global `Sum224` (BLAKE-224) or `Sum256` (BLAKE-256) functions. This is
+demonstrated for BLAKE-256 via the "Basic Usage" example linked in the
+[Examples](#examples) section.
+
+However, since hashing typically involves writing various pieces of information
+that aren't already serialized, this package provides `NewHasher224` (BLAKE-224)
+and `NewHasher256` (BLAKE-256) (and their respective variants `NewHasher224Salt`
+and `NewHasher256Salt` that accept salt).
+
+These methods return rolling hasher instances that support writing an arbitrary
+amount of data along with several convenience methods for writing various data
+types in either big endian or little endian. For example, `WriteString` adds a
+string encoded as its UTF-8 byte sequence to the rolling hash and
+`WriteUint64BE` adds an unsigned 64-bit integer encoded as an 8-byte big-endian
+byte sequence to the rolling hash.
+
+The hash is then obtained via the `Sum224` (BLAKE-224) or `Sum256` (BLAKE-256)
+method on the respective hasher instance.
+
+See the "Rolling Hasher Usage" example linked in the [Examples](#examples)
+section to see rolling hashing in action.
+
+## Saving and Resuming Intermediate States
+
+Many applications involve hashing data that always starts with the same sequence
+of bytes (aka a shared prefix). Whenever that prefix is larger than the block
+size (`BlockSize`), or it is otherwise costly to generate and serialize, it is
+typically more efficient to save the intermediate state (midstate) after writing
+the shared prefix so that all future hashes can resume from that midstate and
+thereby avoid redoing work.
+
+To that end, the aforementioned rolling hasher instances support being copied to
+save and restore the current midstate within the same process. This is
+demonstrated via the "Same Process Save and Restore" example linked in the
+[Examples](#examples) section.
+
+Alternatively, when a simple copy of the instance is not possible, such as when
+the midstate is needed among multiple processes, perhaps on entirely different
+hardware, it can be serialized via `SaveState` and restored via
+`UnmarshalBinary`. Note that there is necessarily additional overhead involved
+with serializing and deserializing the intermediate state, so callers should be
+sure to compare that overhead with rehashing the shared data to see which
+approach yields better results for their particular application.
+
+## Hashing With Salt
+
+This implementation also provides `NewHasher224Salt` (BLAKE-224) and
+`NewHasher256Salt` (BLAKE-256) which accept a 16-byte salt input as described by
+the specification. Hashing with distinct salts effectively provides an
+efficient method to hash with different functions while using the same
+underlying algorithm. The salted variants behave exactly the same as the normal
+unsalted variants described throughout the documentation.
+
+## Benchmarks
+
+The following benchmarks are from a Ryzen 7 5800X3D processor on Linux and are
+the result of feeding `benchstat` 10 iterations of each. Benchmarks for both
+BLAKE-224 and BLAKE-256 are provided. They are essentialy identical (within the
+margin of error) as expected since the only notable difference as it pertains to
+performance is that the final output is 4 bytes shorter.
+
+### BLAKE-256 Hashing Benchmarks
+
+The following results demonstrate the performance of hashing various amounts of
+data for both small and larger inputs with the `Sum256` method.
+
+Operation | Pure Go | SSE2 | SSE4.1 | AVX
+-----------------|--------------|--------------|--------------|-------------
+`Sum256` (32b) | 168MB/s ± 1% | 188MB/s ± 1% | 232MB/s ± 0% | 234MB/s ± 1%
+`Sum256` (64b) | 187MB/s ± 0% | 208MB/s ± 0% | 270MB/s ± 1% | 271MB/s ± 1%
+`Sum256` (1KiB) | 378MB/s ± 1% | 421MB/s ± 1% | 536MB/s ± 1% | 539MB/s ± 1%
+`Sum256` (8KiB) | 405MB/s ± 1% | 448MB/s ± 0% | 573MB/s ± 0% | 573MB/s ± 0%
+`Sum256` (16KiB) | 402MB/s ± 1% | 449MB/s ± 0% | 575MB/s ± 0% | 575MB/s ± 0%
+
+Operation | Pure Go | SSE2 | SSE4.1 | AVX | Allocs / Op
+-----------------|-------------|-------------|-------------|-------------|------------
+`Sum256` (32b) | 190ns ± 1% | 170ns ± 1% | 138ns ± 0% | 137ns ± 1% | 0
+`Sum256` (64b) | 342ns ± 0% | 308ns ± 0% | 237ns ± 1% | 236ns ± 1% | 0
+`Sum256` (1KiB) | 2.71µs ± 1% | 2.43µs ± 1% | 1.91µs ± 1% | 1.90µs ± 1% | 0
+`Sum256` (8KiB) | 20.2µs ± 1% | 18.3µs ± 0% | 14.3µs ± 0% | 14.3µs ± 0% | 0
+`Sum256` (16KiB) | 40.8µs ± 1% | 36.5µs ± 0% | 28.5µs ± 0% | 28.5µs ± 0% | 0
+
+### BLAKE-224 Hashing Benchmarks
+
+The following results demonstrate the performance of hashing various amounts of
+data for both small and larger inputs with the `Sum224` method.
+
+Operation | Pure Go | SSE2 | SSE4.1 | AVX
+-----------------|--------------|--------------|--------------|-------------
+`Sum224` (32b) | 171MB/s ± 1% | 188MB/s ± 1% | 232MB/s ± 1% | 234MB/s ± 1%
+`Sum224` (64b) | 187MB/s ± 2% | 209MB/s ± 1% | 269MB/s ± 1% | 271MB/s ± 1%
+`Sum224` (1KiB) | 378MB/s ± 1% | 423MB/s ± 1% | 539MB/s ± 1% | 536MB/s ± 1%
+`Sum224` (8KiB) | 404MB/s ± 1% | 447MB/s ± 1% | 577MB/s ± 1% | 577MB/s ± 0%
+`Sum224` (16KiB) | 401MB/s ± 1% | 453MB/s ± 0% | 577MB/s ± 0% | 577MB/s ± 0%
+
+Operation | Pure Go | SSE2 | SSE4.1 | AVX | Allocs / Op
+-----------------|-------------|-------------|-------------|-------------|------------
+`Sum224` (32b) | 187ns ± 1% | 170ns ± 1% | 138ns ± 1% | 137ns ± 1% | 0
+`Sum224` (64b) | 342ns ± 2% | 306ns ± 1% | 238ns ± 1% | 236ns ± 1% | 0
+`Sum224` (1KiB) | 2.71µs ± 1% | 2.42µs ± 1% | 1.90µs ± 1% | 1.91µs ± 1% | 0
+`Sum224` (8KiB) | 20.3µs ± 1% | 18.3µs ± 1% | 14.2µs ± 1% | 14.2µs ± 0% | 0
+`Sum224` (16KiB) | 40.9µs ± 1% | 36.2µs ± 0% | 28.4µs ± 0% | 28.4µs ± 0% | 0
+
+### State Serialization Benchmarks
+
+The following results demonstrate the performance of serializing the
+intermediate state for both BLAKE-224 and BLAKE-256 using the zero-alloc
+`SaveState` method versus the standard library `encoding.MarshalBinary`
+interface.
+
+ Metric | `MarshalBinary` | `SaveState` | Delta
+------------|-----------------|-------------|---------------------------
+Time / Op | 40.6ns ± 1% | 16.0ns ± 0% | -60.60% (p=0.000 n=10+10)
+Allocs / Op | 1 | 0 | -100.00% (p=0.000 n=10+10)
+
+## Disabling Assembler Optimizations
+
+The `purego` build tag may be used to disable all assembly code.
+
+Additionally, when built normally without the `purego` build tag, the assembly
+optimizations for each of the supported vector extensions can individually be
+disabled at runtime by setting the following environment variables to `1`.
+
+* `BLAKE256_DISABLE_AVX=1`: Disable Advanced Vector Extensions (AVX) optimizations
+* `BLAKE256_DISABLE_SSE41=1`: Disable Streaming SIMD Extensions 4.1 (SSE4.1) optimizations
+* `BLAKE256_DISABLE_SSE2=1`: Disable Streaming SIMD Extensions 2 (SSE2) optimizations
+
+The package will automatically use the fastest available extensions that are not
+disabled.
+
+## Examples
+
+* [Basic Usage](https://pkg.go.dev/github.com/decred/dcrd/crypto/blake256#example-package-BasicUsage)
+ Demonstrates the simplest method of hashing an existing serialized data buffer
+ with BLAKE-256.
+* [Rolling Hasher Usage](https://pkg.go.dev/github.com/decred/dcrd/crypto/blake256#example-package-RollingHasherUsage)
+ Demonstrates creating a rolling BLAKE-256 hasher, writing various data types
+ to it, computing the hash, writing more data, and finally computing the
+ cumulative hash.
+* [Same Process Save and Restore](https://pkg.go.dev/github.com/decred/dcrd/crypto/blake256#example-package-SameProcessSaveRestore)
+ Demonstrates creating a rolling BLAKE-256 hasher, writing some data to it,
+ making a copy of the intermediate state, restoring the intermediate state in
+ multiple goroutines, writing more data to each of those restored copies, and
+ computing the final hashes.
+
+## Installation and Updating
+
+This package is part of the `github.com/decred/dcrd/crypto/blake256` module.
+Use the standard go tooling for working with modules to incorporate it.
+
+## License
+
+Package blake256 is licensed under the [copyfree](http://copyfree.org) ISC
+License.
diff --git a/vendor/github.com/decred/dcrd/crypto/blake256/error.go b/vendor/github.com/decred/dcrd/crypto/blake256/error.go
new file mode 100644
index 0000000..1a695af
--- /dev/null
+++ b/vendor/github.com/decred/dcrd/crypto/blake256/error.go
@@ -0,0 +1,50 @@
+// Copyright (c) 2024 The Decred developers
+// Use of this source code is governed by an ISC
+// license that can be found in the LICENSE file.
+
+package blake256
+
+// ErrorKind identifies a kind of error.
+type ErrorKind string
+
+// These constants are used to identify a specific ErrorKind.
+const (
+ // ErrMalformedState indicates a serialized intermediate state is malformed
+ // in some way such as not having at least the expected number of bytes.
+ ErrMalformedState = ErrorKind("ErrMalformedState")
+
+ // ErrMismatchedState indicates a serialized intermediate state is not for
+ // the hash type that is attempting to restore it. For example, it will be
+ // returned when attempting to restore a BLAKE-256 intermediate state with
+ // a BLAKE-224 hasher.
+ ErrMismatchedState = ErrorKind("ErrMismatchedState")
+)
+
+// Error satisfies the error interface and prints human-readable errors.
+func (e ErrorKind) Error() string {
+ return string(e)
+}
+
+// Error identifies an error related to restoring an intermediate hashing state.
+//
+// It has full support for [errors.Is] and [errors.As], so the caller can
+// ascertain the specific reason for the error by checking the underlying error.
+type Error struct {
+ Err error
+ Description string
+}
+
+// Error satisfies the error interface and prints human-readable errors.
+func (e Error) Error() string {
+ return e.Description
+}
+
+// Unwrap returns the underlying wrapped error.
+func (e Error) Unwrap() error {
+ return e.Err
+}
+
+// makeError creates an [Error] given a set of arguments.
+func makeError(kind ErrorKind, desc string) Error {
+ return Error{Err: kind, Description: desc}
+}
diff --git a/vendor/github.com/decred/dcrd/crypto/blake256/hasher.go b/vendor/github.com/decred/dcrd/crypto/blake256/hasher.go
new file mode 100644
index 0000000..2d37ef8
--- /dev/null
+++ b/vendor/github.com/decred/dcrd/crypto/blake256/hasher.go
@@ -0,0 +1,415 @@
+// Copyright (c) 2024 The Decred developers
+// Use of this source code is governed by an ISC
+// license that can be found in the LICENSE file.
+//
+// Main Go code originally written and optimized by Dave Collins May 2020.
+// Additional cleanup and comments added July 2024.
+
+// Package blake256 implements BLAKE-256 and BLAKE-224 with SSE2, SSE4.1, and
+// AVX acceleration and zero allocations.
+package blake256
+
+import (
+ "encoding/binary"
+ "fmt"
+
+ "github.com/decred/dcrd/crypto/blake256/internal/compress"
+)
+
+const (
+ // BlockSize is the block size of the hash algorithm in bytes.
+ BlockSize = 64
+
+ // Size is the size of a BLAKE-256 hash in bytes.
+ Size = 32
+
+ // Size224 is the size of a BLAKE-224 hash in bytes.
+ Size224 = 28
+
+ // SavedStateSize is the number of bytes of a serialized intermediate state.
+ SavedStateSize = 128
+)
+
+// pad provides an efficient means to pad a message.
+var pad = [64]byte{0x80}
+
+// hasher implements a zero-allocation rolling BLAKE checksum. It can safely be
+// copied at any point to save its internal state for use in additional
+// processing later, without having to write the previously written data again.
+//
+// It contains the common logic between BLAKE-224 and BLAKE-256.
+type hasher struct {
+ state compress.State // the current chain value and salt
+ count uint64 // running total of message bits hashed
+ buf [BlockSize]byte // partial block data buffer
+ nbuf uint32 // number of bytes written to data buffer
+}
+
+// makeHasher returns an instance of a rolling hasher initialized with the
+// provided chain value.
+func makeHasher(cv [8]uint32) hasher {
+ return hasher{state: compress.State{CV: cv}}
+}
+
+// reset resets the state of the rolling hash.
+func (h *hasher) reset(iv [8]uint32) {
+ h.state.CV = iv
+ h.count = 0
+ h.nbuf = 0
+}
+
+// initializeSalt initialize the hasher state with the provided salt. Note that
+// this must only be done when first creating the hasher state for correct
+// results.
+//
+// It will panic if the provided salt is not 16 bytes.
+func (h *hasher) initializeSalt(salt []byte) {
+ if len(salt) != 16 {
+ panic("salt length must be 16 bytes")
+ }
+ h.state.S[0] = binary.BigEndian.Uint32(salt)
+ h.state.S[1] = binary.BigEndian.Uint32(salt[4:])
+ h.state.S[2] = binary.BigEndian.Uint32(salt[8:])
+ h.state.S[3] = binary.BigEndian.Uint32(salt[12:])
+}
+
+// write adds the given bytes to the rolling hash.
+//
+// NOTE: This method only returns an error in order to satisfy the [io.Writer]
+// and [hash.Hash] interfaces. However, it will never error, meaning the error
+// will always be nil, so it is safe to ignore.
+func (h *hasher) write(b []byte) (int, error) {
+ // All bytes will be written.
+ totalWritten := len(b)
+
+ // When a partial block exists and adding the new data would meet or exceed
+ // the size of a block, fill up the partial block and compress it.
+ if h.nbuf > 0 && h.nbuf+uint32(len(b)) >= BlockSize {
+ written := uint32(copy(h.buf[h.nbuf:], b))
+ h.count += BlockSize << 3
+ compress.Blocks(&h.state, h.buf[:], h.count)
+ b = b[written:]
+ h.nbuf = 0
+ }
+
+ // The previous section ensures there is no partial block data remaining.
+ //
+ // Use that fact to compress full blocks directly when the remaining number
+ // of bytes to write will completely fill one or more additional blocks.
+ //
+ // It is perhaps also worth noting that this approach is used over having a
+ // compression function that only accepts a single block because it provides
+ // a rather significant speed advantage on inputs that are larger than the
+ // size of a couple of blocks while only having a negligible impact on small
+ // inputs.
+ if len(b) >= BlockSize {
+ h.count += BlockSize << 3
+ compress.Blocks(&h.state, b, h.count)
+
+ // Update the count of message bits hashed and slice of remaining
+ // unwritten bytes to account for the total number of blocks compressed.
+ bytesHashed := uint64(len(b) &^ (BlockSize - 1))
+ h.count += (bytesHashed - BlockSize) << 3
+ b = b[bytesHashed:]
+ }
+
+ // Write any remaining bytes to the next partial block. Note the number of
+ // remaining bytes is guaranteed to be less than the size of a full block
+ // due to the previous sections.
+ if len(b) > 0 {
+ h.nbuf += uint32(copy(h.buf[h.nbuf:], b))
+ }
+
+ return totalWritten, nil
+}
+
+// writeByte adds the given byte to the rolling hash.
+func (h *hasher) writeByte(b byte) {
+ var buf [1]byte
+ buf[0] = b
+ h.write(buf[:])
+}
+
+// writeString adds the given string to the rolling hash.
+func (h *hasher) writeString(s string) {
+ h.write([]byte(s))
+}
+
+// writeUint16LE encodes the given unsigned 16-bit integer as a 2-byte
+// little-endian byte sequence and adds it to the rolling hash.
+func (h *hasher) writeUint16LE(v uint16) {
+ var buf [2]byte
+ binary.LittleEndian.PutUint16(buf[:], v)
+ h.write(buf[:])
+}
+
+// writeUint16BE encodes the given unsigned 16-bit integer as a 2-byte
+// big-endian byte sequence and adds it to the rolling hash.
+func (h *hasher) writeUint16BE(v uint16) {
+ var buf [2]byte
+ binary.BigEndian.PutUint16(buf[:], v)
+ h.write(buf[:])
+}
+
+// writeUint32LE encodes the given unsigned 32-bit integer as a 4-byte
+// little-endian byte sequence and adds it to the rolling hash.
+func (h *hasher) writeUint32LE(v uint32) {
+ var buf [4]byte
+ binary.LittleEndian.PutUint32(buf[:], v)
+ h.write(buf[:])
+}
+
+// writeUint32BE encodes the given unsigned 32-bit integer as a 4-byte
+// big-endian byte sequence and adds it to the rolling hash.
+func (h *hasher) writeUint32BE(v uint32) {
+ var buf [4]byte
+ binary.BigEndian.PutUint32(buf[:], v)
+ h.write(buf[:])
+}
+
+// writeUint64LE encodes the given unsigned 64-bit integer as an 8-byte
+// little-endian byte sequence and adds it to the rolling hash.
+func (h *hasher) writeUint64LE(v uint64) {
+ var buf [8]byte
+ binary.LittleEndian.PutUint64(buf[:], v)
+ h.write(buf[:])
+}
+
+// writeUint64BE encodes the given unsigned 64-bit integer as an 8-byte
+// big-endian byte sequence and adds it to the rolling hash.
+func (h *hasher) writeUint64BE(v uint64) {
+ var buf [8]byte
+ binary.BigEndian.PutUint64(buf[:], v)
+ h.write(buf[:])
+}
+
+// finalize finalizes of the rolling hash by writing any remaining partial block
+// data and appending the necessary padding.
+//
+// The hasher may no longer be used after invoking this method. Callers always
+// run finalize on a copy of the hasher so the original hasher state is not
+// modified.
+//
+// The length preamble bit MUST be 0 (for BLAKE-224) or 1 (for BLAKE-256).
+func (h *hasher) finalize(lenPreambleBit uint8) {
+ // Hashing a message consists of padding the message to a multiple of the
+ // block size and processing it block per block by the compression function.
+ //
+ // Padding the message consists of first extending the message so that its
+ // bit length is congruent to 447 modulo 512 by appending a 1 bit followed
+ // by enough 0s to reach the required congruence. Then a length preamble
+ // bit is added (1 for BLAKE-256, 0 for BLAKE-224) followed by the length
+ // of original message encoded as a 64-bit unsigned big-endian integer.
+ // This ensures the message length is a multiple of the block size since
+ // 447+1+64 = 512.
+ //
+ // Note that a special case occurs when the final block contains no original
+ // message bit. In that case, the message bit counter provided to the
+ // compression function is set to zero for that final block. This
+ // guarantees unique blocks.
+ //
+ // This implementation performs iterated hashing by compressing full blocks
+ // as data is written and storing the resulting chain value, total number of
+ // message bits compressed, and any remaining partial block data in the
+ // state.
+ //
+ // Thus, finalization consists of writing any remaining partial block data
+ // that hasn't already been compressed and padding the message out per the
+ // above.
+ //
+ // Since this implementation only allows writing full 8-bit bytes at a time,
+ // the following is optimized to only consider message bit lengths that are
+ // multiples of 8. Concretely, note that floor(447/8) = 55. Therefore, as
+ // long as the remaining partial block data is <= 55, only one compression
+ // is needed. Otherwise a second compression is needed.
+ msgBitLen := h.count + uint64(h.nbuf)<<3
+ switch {
+ // Exactly one padding byte is needed.
+ case h.nbuf == 55:
+ h.buf[55] = 0x80 | lenPreambleBit
+ binary.BigEndian.PutUint64(h.buf[56:], msgBitLen)
+ compress.Blocks(&h.state, h.buf[:], msgBitLen)
+ return
+
+ // Appending the padding to the remaining partial block data will fit
+ // without needing another block.
+ case h.nbuf < 55:
+ copy(h.buf[h.nbuf:55], pad[:])
+ h.buf[55] = lenPreambleBit
+ binary.BigEndian.PutUint64(h.buf[56:], msgBitLen)
+
+ // Per the specification, the counter is set to zero for the final
+ // compression when the final block contains no bits from the original
+ // message.
+ if h.nbuf == 0 {
+ msgBitLen = 0
+ }
+ compress.Blocks(&h.state, h.buf[:], msgBitLen)
+ return
+ }
+
+ // The partial block data plus the padding and message bit length exceed the
+ // size of a block, so two compressions are needed where the second one is
+ // a padding block (all zeros except for the final 8 bytes which house the
+ // original message length encoded as a 64-bit unsigned big-endian integer).
+
+ // Pad the remaining partial block data and compress it.
+ copy(h.buf[h.nbuf:], pad[:])
+ compress.Blocks(&h.state, h.buf[:], msgBitLen)
+
+ // Create the final padding block and compress it.
+ //
+ // Note that since the padding block does not contain any bits from the
+ // original message, the counter is set to zero when performing compression
+ // per the specification.
+ copy(h.buf[:], pad[1:56])
+ h.buf[55] = lenPreambleBit
+ binary.BigEndian.PutUint64(h.buf[56:], msgBitLen)
+ compress.Blocks(&h.state, h.buf[:], 0)
+}
+
+// wordsToBytes224 converts an array of 8 32-bit unsigned big-endian words to an
+// array of 28 bytes. The final word is truncated.
+func wordsToBytes224(cv [8]uint32) (out [28]byte) {
+ binary.BigEndian.PutUint32(out[24:], cv[6])
+ binary.BigEndian.PutUint32(out[20:], cv[5])
+ binary.BigEndian.PutUint32(out[16:], cv[4])
+ binary.BigEndian.PutUint32(out[12:], cv[3])
+ binary.BigEndian.PutUint32(out[8:], cv[2])
+ binary.BigEndian.PutUint32(out[4:], cv[1])
+ binary.BigEndian.PutUint32(out[0:], cv[0])
+ return out
+}
+
+// finalize224 finalizes of the rolling hash by writing any remaining partial
+// block data and appending the necessary padding for BLAKE-224.
+//
+// The hasher may no longer be used after invoking this method. Callers always
+// run finalize on a copy of the hasher so the original hasher state is not
+// modified.
+func (h *hasher) finalize224() [Size224]byte {
+ const lenPreambleBit = 0x00
+ h.finalize(lenPreambleBit)
+ return wordsToBytes224(h.state.CV)
+}
+
+// wordsToBytes256 converts an array of 8 32-bit unsigned big-endian words to an
+// array of 32 bytes.
+func wordsToBytes256(cv [8]uint32) (out [32]byte) {
+ binary.BigEndian.PutUint32(out[28:], cv[7])
+ binary.BigEndian.PutUint32(out[24:], cv[6])
+ binary.BigEndian.PutUint32(out[20:], cv[5])
+ binary.BigEndian.PutUint32(out[16:], cv[4])
+ binary.BigEndian.PutUint32(out[12:], cv[3])
+ binary.BigEndian.PutUint32(out[8:], cv[2])
+ binary.BigEndian.PutUint32(out[4:], cv[1])
+ binary.BigEndian.PutUint32(out[0:], cv[0])
+ return out
+}
+
+// finalize256 finalizes of the rolling hash by writing any remaining partial
+// block data and appending the necessary padding for BLAKE-256.
+//
+// The hasher may no longer be used after invoking this method. Callers always
+// run finalize on a copy of the hasher so the original hasher state is not
+// modified.
+func (h *hasher) finalize256() [Size]byte {
+ const lenPreambleBit = 0x01
+ h.finalize(lenPreambleBit)
+ return wordsToBytes256(h.state.CV)
+}
+
+// putSavedState serializes the intermediate state directly into the passed byte
+// slice. The target slice MUST have at least [SavedStateSize] bytes available
+// or it will panic.
+func (h *hasher) putSavedState(target []byte, prefix uint32) {
+ var offset uint32
+ binary.BigEndian.PutUint32(target[offset:], prefix)
+ offset += 4
+ for _, cv := range h.state.CV {
+ binary.BigEndian.PutUint32(target[offset:], cv)
+ offset += 4
+ }
+ for _, s := range h.state.S {
+ binary.BigEndian.PutUint32(target[offset:], s)
+ offset += 4
+ }
+ binary.BigEndian.PutUint64(target[offset:], h.count)
+ offset += 8
+ offset += uint32(copy(target[offset:], h.buf[:]))
+ binary.BigEndian.PutUint32(target[offset:], h.nbuf)
+}
+
+// saveState appends the current intermediate state of the rolling hash prefixed
+// by the passed value to the provided slice and returns the resulting slice.
+// It does not change the underlying hash state.
+//
+// The provided prefix is expected to either be [statePrefix224] or
+// [statePrefix256] depending on which hash variant is being saved.
+//
+// As described by the [hasher] documentation, the hasher instance can simply be
+// copied to achieve the same result much more efficiently when the caller is
+// able to keep a copy. Therefore, that approach should be preferred when
+// possible.
+//
+// However, the ability to serialize the state is also provided to enable
+// sharing it across process boundaries.
+func (h *hasher) saveState(target []byte, prefix uint32) []byte {
+ // Create a new array and append it to the target when there is not enough
+ // space remaining in the slice. Otherwise, write directly into it.
+ //
+ // Note that this could alternatively just grow the slice if needed and then
+ // write directly into it unconditionally, but this approach is faster for
+ // the two much more common cases of the caller providing a slice that is
+ // already big enough or a nil slice.
+ if needed := SavedStateSize - (cap(target) - len(target)); needed > 0 {
+ var state [SavedStateSize]byte
+ h.putSavedState(state[:], prefix)
+ return append(target, state[:]...)
+ }
+ h.putSavedState(target[len(target):len(target)+SavedStateSize], prefix)
+ return target[:len(target)+SavedStateSize]
+}
+
+// loadState restores the rolling hash to the provided serialized intermediate
+// state. See [hasher.saveState] for more details.
+//
+// The provided prefix is expected to either be [statePrefix224] or
+// [statePrefix256] depending on which hash variant is being loaded.
+//
+// [ErrMalformedState] will be returned when the provided serialized state is
+// not at least the required [SavedStateSize] number of bytes.
+//
+// [ErrMismatchedState] will be returned if the prefix in the serialized state
+// does not match the given required prefix.
+func (h *hasher) loadState(state []byte, requiredPrefix uint32) error {
+ if len(state) < SavedStateSize {
+ str := fmt.Sprintf("malformed intermediate state - must be at least "+
+ "%d bytes", SavedStateSize)
+ return makeError(ErrMalformedState, str)
+ }
+ var offset uint32
+ if pre := binary.BigEndian.Uint32(state[offset:]); pre != requiredPrefix {
+ hashType := "BLAKE-256"
+ if requiredPrefix != statePrefix256 {
+ hashType = "BLAKE-224"
+ }
+ str := fmt.Sprintf("the provided intermediate state is not for %s",
+ hashType)
+ return makeError(ErrMismatchedState, str)
+ }
+ offset += 4
+ for i := range h.state.CV {
+ h.state.CV[i] = binary.BigEndian.Uint32(state[offset:])
+ offset += 4
+ }
+ for i := range h.state.S {
+ h.state.S[i] = binary.BigEndian.Uint32(state[offset:])
+ offset += 4
+ }
+ h.count = binary.BigEndian.Uint64(state[offset:])
+ offset += 8
+ offset += uint32(copy(h.buf[:], state[offset:]))
+ h.nbuf = binary.BigEndian.Uint32(state[offset:])
+ return nil
+}
diff --git a/vendor/github.com/decred/dcrd/crypto/blake256/hasher224.go b/vendor/github.com/decred/dcrd/crypto/blake256/hasher224.go
new file mode 100644
index 0000000..07f3d67
--- /dev/null
+++ b/vendor/github.com/decred/dcrd/crypto/blake256/hasher224.go
@@ -0,0 +1,278 @@
+// Copyright (c) 2024 The Decred developers
+// Use of this source code is governed by an ISC
+// license that can be found in the LICENSE file.
+//
+// Main Go code originally written and optimized by Dave Collins May 2020.
+// Additional cleanup and comments added in July 2024.
+
+package blake256
+
+import (
+ "hash"
+)
+
+// iv224 is the BLAKE-224 initialization vector.
+var iv224 = [8]uint32{
+ 0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939,
+ 0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4,
+}
+
+// statePrefix224 is the prefix used when serializing the intermediate state to
+// identify the state as belonging to a BLAKE-224 rolling hash. It is the
+// second value in iv224.
+const statePrefix224 = 0x367cd507
+
+// Hasher224 provides a zero-allocation implementation to compute a rolling
+// BLAKE-224 checksum.
+//
+// It can safely be copied at any point to save its intermediate state for use
+// in additional processing later, without having to write the previously
+// written data again.
+//
+// In addition to the aforementioned in-process state saving capability, it also
+// supports serializing the intermediate state to enable sharing across process
+// boundaries.
+//
+// It is effectively a mix of a [hash.Hash], [encoding.BinaryMarshaler], and
+// [encoding.BinaryUnmarshaler] with a modified API that enables zero
+// allocations and also provides additional convenience funcs for writing
+// integers encoded with both big and little endian as well as writing
+// individual bytes.
+//
+// However, it also implements [hash.Hash], [encoding.BinaryMarshaler], and
+// [encoding.BinaryUnmarshaler] for callers that aren't as concerned about
+// reducing allocations and would prefer to use it with the aforementioned
+// standard library interfaces.
+//
+// NOTE: The zero value is NOT safe to use. It must be initialized via
+// NewHasher224 or NewHasher224Salt.
+type Hasher224 struct {
+ h hasher
+}
+
+// Write adds the given bytes to the rolling hash.
+//
+// NOTE: This method only returns an error in order to satisfy the [io.Writer]
+// and [hash.Hash] interfaces. However, it will never error, meaning the error
+// will always be nil, so it is safe to ignore.
+//
+// Callers may optionally choose to call [WriteBytes] which does not return an
+// error to make the fact writing can never fail.
+func (h *Hasher224) Write(b []byte) (int, error) {
+ return h.h.write(b)
+}
+
+// WriteByte adds the given byte to the rolling hash.
+func (h *Hasher224) WriteByte(b byte) {
+ h.h.writeByte(b)
+}
+
+// WriteBytes adds the given bytes to the rolling hash.
+//
+// This method is identical to [Write] except it does not return an error in
+// order to make it clear that writing can never fail.
+func (h *Hasher224) WriteBytes(b []byte) {
+ h.h.write(b)
+}
+
+// WriteString adds the given string to the rolling hash.
+func (h *Hasher224) WriteString(s string) {
+ h.h.writeString(s)
+}
+
+// WriteUint16LE encodes the given unsigned 16-bit integer as a 2-byte
+// little-endian byte sequence and adds it to the rolling hash.
+func (h *Hasher224) WriteUint16LE(val uint16) {
+ h.h.writeUint16LE(val)
+}
+
+// WriteUint16BE encodes the given unsigned 16-bit integer as a 2-byte
+// big-endian byte sequence and adds it to the rolling hash.
+func (h *Hasher224) WriteUint16BE(val uint16) {
+ h.h.writeUint16BE(val)
+}
+
+// WriteUint32LE encodes the given unsigned 32-bit integer as a 4-byte
+// little-endian byte sequence and adds it to the rolling hash.
+func (h *Hasher224) WriteUint32LE(val uint32) {
+ h.h.writeUint32LE(val)
+}
+
+// WriteUint32BE encodes the given unsigned 32-bit integer as a 4-byte
+// big-endian byte sequence and adds it to the rolling hash.
+func (h *Hasher224) WriteUint32BE(val uint32) {
+ h.h.writeUint32BE(val)
+}
+
+// WriteUint64LE encodes the given unsigned 64-bit integer as an 8-byte
+// little-endian byte sequence and adds it to the rolling hash.
+func (h *Hasher224) WriteUint64LE(val uint64) {
+ h.h.writeUint64LE(val)
+}
+
+// WriteUint64BE encodes the given unsigned 64-bit integer as an 8-byte
+// big-endian byte sequence and adds it to the rolling hash.
+func (h *Hasher224) WriteUint64BE(val uint64) {
+ h.h.writeUint64BE(val)
+}
+
+// Reset resets the state of the rolling hash.
+//
+// This is part of the [hash.Hash] interface.
+func (h *Hasher224) Reset() {
+ h.h.reset(iv224)
+}
+
+// Size returns the size of a BLAKE-224 hash in bytes.
+//
+// This is part of the [hash.Hash] interface.
+func (h *Hasher224) Size() int {
+ return Size224
+}
+
+// BlockSize returns the underlying block size of the BLAKE-224 hashing
+// algorithm.
+//
+// This is part of the [hash.Hash] interface.
+func (h *Hasher224) BlockSize() int {
+ return BlockSize
+}
+
+// Sum finalizes the rolling hash, appends the resulting checksum to the
+// provided slice and returns the resulting slice. It does not change the
+// underlying hash state.
+//
+// Note that allocations can often be avoided by providing a slice that has
+// enough capacity to house the resulting checksum. For example:
+//
+// digest := make([]byte, blake256.Size224)
+// h := blake256.NewHasher224()
+// h.WriteUint64LE(1)
+// digest = h.Sum(digest[:0])
+//
+// This is part of the [hash.Hash] interface.
+func (h Hasher224) Sum(b []byte) []byte {
+ // Note h is a copy so that the caller can keep writing and summing.
+ sum := h.h.finalize224()
+ return append(b, sum[:]...)
+}
+
+// Sum224 finalizes the rolling hash and returns the resulting checksum. It
+// does not change the underlying hash state.
+func (h Hasher224) Sum224() [Size224]byte {
+ // Note h is a copy so that the caller can keep writing and summing.
+ return h.h.finalize224()
+}
+
+// SaveState appends the current intermediate state of the rolling hash, as
+// generated by [Hasher224.MarshalBinary], to the provided slice and returns the
+// resulting slice. It does not change the underlying hash state.
+//
+// The resulting serialized data may be used to resume from the current
+// intermediate state later without having to write the previously written data
+// again by providing it to [Hasher224.UnmarshalBinary].
+//
+// As described by the [Hasher224] documentation, the hasher instance can simply
+// be copied to achieve the same result much more efficiently when the caller is
+// able to keep a copy. Therefore, that approach should be preferred when
+// possible.
+//
+// However, the ability to serialize the state is also provided to enable
+// sharing it across process boundaries.
+//
+// Note that allocations can typically be avoided by providing a slice that has
+// enough capacity to house the resulting state as defined by the
+// [SavedStateSize] constant. For example:
+//
+// state := make([]byte, blake256.SavedStateSize)
+// h := blake256.NewHasher224()
+// h.WriteUint64LE(1)
+// state = h.SaveState(state[:0])
+func (h *Hasher224) SaveState(target []byte) []byte {
+ return h.h.saveState(target, statePrefix224)
+}
+
+// MarshalBinary returns the intermediate state of the rolling hash serialized
+// into a binary form that may be used to resume from the current state later
+// without having to write the previously written data again. It does not
+// change the underlying hash state.
+//
+// As described by the [Hasher224] documentation, the hasher instance can simply
+// be copied to achieve the same result much more efficiently when the caller is
+// able to keep a copy. Therefore, that approach should be preferred when
+// possible.
+//
+// However, the ability to serialize the state is also provided to enable
+// sharing it across process boundaries.
+//
+// NOTE: This method only returns an error in order to satisfy the
+// [encoding.BinaryMarshaler] interface. However, it will never error, meaning
+// the error will always be nil, so it is safe to ignore.
+//
+// Callers that wish to avoid allocations should prefer [Hasher224.SaveState]
+// instead.
+func (h *Hasher224) MarshalBinary() ([]byte, error) {
+ var state [SavedStateSize]byte
+ h.h.putSavedState(state[:], statePrefix224)
+ return state[:], nil
+}
+
+// UnmarshalBinary restores the rolling hash to the provided serialized
+// intermediate state. See [Hasher224.MarshalBinary] for more details.
+//
+// [ErrMalformedState] will be returned when the provided serialized state is
+// not at least the required [SavedStateSize] number of bytes.
+//
+// [ErrMismatchedState] will be returned if the provided state is not for a
+// BLAKE-224 hash. For example, it will be returned when attempting to restore
+// a BLAKE-256 intermediate state.
+//
+// This implements the [encoding.BinaryUnmarshaler] interface.
+func (h *Hasher224) UnmarshalBinary(state []byte) error {
+ return h.h.loadState(state, statePrefix224)
+}
+
+// NewHasher224 returns a zero-allocation hasher for computing a rolling
+// BLAKE-224 checksum.
+func NewHasher224() *Hasher224 {
+ h := Hasher224{makeHasher(iv224)}
+ return &h
+}
+
+// NewHasher224Salt returns a zero-allocation hasher for computing a rolling
+// BLAKE-224 checksum initialized with the given 16-byte salt slice.
+//
+// It will panic if the provided salt is not 16 bytes.
+func NewHasher224Salt(salt []byte) *Hasher224 {
+ h := Hasher224{makeHasher(iv224)}
+ h.h.initializeSalt(salt)
+ return &h
+}
+
+// New224 returns a new [hash.Hash] computing the BLAKE-224 checksum.
+//
+// Callers should prefer [NewHasher224] instead since it returns a concrete type
+// that has more functionality and allows avoiding additional allocations. It
+// can also be used as a [hash.Hash] if desired.
+func New224() hash.Hash {
+ return NewHasher224()
+}
+
+// New224Salt returns a new [hash.Hash] computing the BLAKE-224 checksum
+// initialized with the given 16-byte salt.
+//
+// It will panic if the provided salt is not 16 bytes.
+//
+// Callers should prefer [NewHasher224Salt] instead since it returns a concrete
+// type that has more functionality and allows avoiding additional allocations.
+// It can also be used as a [hash.Hash] if desired.
+func New224Salt(salt []byte) hash.Hash {
+ return NewHasher224Salt(salt)
+}
+
+// Sum224 returns the BLAKE-224 checksum of the data.
+func Sum224(data []byte) [Size224]byte {
+ h := makeHasher(iv224)
+ h.write(data)
+ return h.finalize224()
+}
diff --git a/vendor/github.com/decred/dcrd/crypto/blake256/hasher256.go b/vendor/github.com/decred/dcrd/crypto/blake256/hasher256.go
new file mode 100644
index 0000000..5ad5c12
--- /dev/null
+++ b/vendor/github.com/decred/dcrd/crypto/blake256/hasher256.go
@@ -0,0 +1,278 @@
+// Copyright (c) 2024 The Decred developers
+// Use of this source code is governed by an ISC
+// license that can be found in the LICENSE file.
+//
+// Main Go code originally written and optimized by Dave Collins May 2020.
+// Additional cleanup and comments added July 2024.
+
+package blake256
+
+import (
+ "hash"
+)
+
+// iv256 is the BLAKE-256 initialization vector.
+var iv256 = [8]uint32{
+ 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
+ 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19,
+}
+
+// statePrefix256 is the prefix used when serializing the intermediate state to
+// identify the state as belonging to a BLAKE-256 rolling hash. It is the
+// second value in iv256.
+const statePrefix256 = 0xbb67ae85
+
+// Hasher256 provides a zero-allocation implementation to compute a rolling
+// BLAKE-256 checksum.
+//
+// It can safely be copied at any point to save its intermediate state for use
+// in additional processing later, without having to write the previously
+// written data again.
+//
+// In addition to the aforementioned in-process state saving capability, it also
+// supports serializing the intermediate state to enable sharing across process
+// boundaries.
+//
+// It is effectively a mix of a [hash.Hash], [encoding.BinaryMarshaler], and
+// [encoding.BinaryUnmarshaler] with a modified API that enables zero
+// allocations and also provides additional convenience funcs for writing
+// integers encoded with both big and little endian as well as writing
+// individual bytes.
+//
+// However, it also implements [hash.Hash], [encoding.BinaryMarshaler], and
+// [encoding.BinaryUnmarshaler] for callers that aren't as concerned about
+// reducing allocations and would prefer to use it with the aforementioned
+// standard library interfaces.
+//
+// NOTE: The zero value is NOT safe to use. It must be initialized via
+// NewHasher256.
+type Hasher256 struct {
+ h hasher
+}
+
+// Write adds the given bytes to the rolling hash.
+//
+// NOTE: This method only returns an error in order to satisfy the [io.Writer]
+// and [hash.Hash] interfaces. However, it will never error, meaning the error
+// will always be nil, so it is safe to ignore.
+//
+// Callers may optionally choose to call [WriteBytes] which does not return an
+// error to make the fact writing can never fail.
+func (h *Hasher256) Write(b []byte) (int, error) {
+ return h.h.write(b)
+}
+
+// WriteBytes adds the given bytes to the rolling hash.
+//
+// This method is identical to [Write] except it does not return an error in
+// order to make it clear that writing can never fail.
+func (h *Hasher256) WriteBytes(b []byte) {
+ h.h.write(b)
+}
+
+// WriteByte adds the given byte to the rolling hash.
+func (h *Hasher256) WriteByte(b byte) {
+ h.h.writeByte(b)
+}
+
+// WriteString adds the given string to the rolling hash.
+func (h *Hasher256) WriteString(s string) {
+ h.h.writeString(s)
+}
+
+// WriteUint16LE encodes the given unsigned 16-bit integer as a 2-byte
+// little-endian byte sequence and adds it to the rolling hash.
+func (h *Hasher256) WriteUint16LE(val uint16) {
+ h.h.writeUint16LE(val)
+}
+
+// WriteUint16BE encodes the given unsigned 16-bit integer as a 2-byte
+// big-endian byte sequence and adds it to the rolling hash.
+func (h *Hasher256) WriteUint16BE(val uint16) {
+ h.h.writeUint16BE(val)
+}
+
+// WriteUint32LE encodes the given unsigned 32-bit integer as a 4-byte
+// little-endian byte sequence and adds it to the rolling hash.
+func (h *Hasher256) WriteUint32LE(val uint32) {
+ h.h.writeUint32LE(val)
+}
+
+// WriteUint32BE encodes the given unsigned 32-bit integer as a 4-byte
+// big-endian byte sequence and adds it to the rolling hash.
+func (h *Hasher256) WriteUint32BE(val uint32) {
+ h.h.writeUint32BE(val)
+}
+
+// WriteUint64LE encodes the given unsigned 64-bit integer as an 8-byte
+// little-endian byte sequence and adds it to the rolling hash.
+func (h *Hasher256) WriteUint64LE(val uint64) {
+ h.h.writeUint64LE(val)
+}
+
+// WriteUint64BE encodes the given unsigned 64-bit integer as an 8-byte
+// big-endian byte sequence and adds it to the rolling hash.
+func (h *Hasher256) WriteUint64BE(val uint64) {
+ h.h.writeUint64BE(val)
+}
+
+// Reset resets the state of the rolling hash.
+//
+// This is part of the [hash.Hash] interface.
+func (h *Hasher256) Reset() {
+ h.h.reset(iv256)
+}
+
+// Size returns the size of a BLAKE-256 hash in bytes.
+//
+// This is part of the [hash.Hash] interface.
+func (h *Hasher256) Size() int {
+ return Size
+}
+
+// BlockSize returns the underlying block size of the BLAKE-256 hashing
+// algorithm.
+//
+// This is part of the [hash.Hash] interface.
+func (h *Hasher256) BlockSize() int {
+ return BlockSize
+}
+
+// Sum finalizes the rolling hash, appends the resulting checksum to the
+// provided slice and returns the resulting slice. It does not change the
+// underlying hash state.
+//
+// Note that allocations can often be avoided by providing a slice that has
+// enough capacity to house the resulting checksum. For example:
+//
+// digest := make([]byte, blake256.Size)
+// h := blake256.NewHasher256()
+// h.WriteUint64LE(1)
+// digest = h.Sum(digest[:0])
+//
+// This is part of the [hash.Hash] interface.
+func (h Hasher256) Sum(b []byte) []byte {
+ // Note h is a copy so that the caller can keep writing and summing.
+ sum := h.h.finalize256()
+ return append(b, sum[:]...)
+}
+
+// Sum256 finalizes the rolling hash and returns the resulting checksum. It
+// does not change the underlying hash state.
+func (h Hasher256) Sum256() [Size]byte {
+ // Note h is a copy so that the caller can keep writing and summing.
+ return h.h.finalize256()
+}
+
+// SaveState appends the current intermediate state of the rolling hash, as
+// generated by [Hasher256.MarshalBinary], to the provided slice and returns the
+// resulting slice. It does not change the underlying hash state.
+//
+// The resulting serialized data may be used to resume from the current
+// intermediate state later without having to write the previously written data
+// again by providing it to [Hasher256.UnmarshalBinary].
+//
+// As described by the [Hasher256] documentation, the hasher instance can simply
+// be copied to achieve the same result much more efficiently when the caller is
+// able to keep a copy. Therefore, that approach should be preferred when
+// possible.
+//
+// However, the ability to serialize the state is also provided to enable
+// sharing it across process boundaries.
+//
+// Note that allocations can typically be avoided by providing a slice that has
+// enough capacity to house the resulting state as defined by the
+// [SavedStateSize] constant. For example:
+//
+// state := make([]byte, blake256.SavedStateSize)
+// h := blake256.NewHasher256()
+// h.WriteUint64LE(1)
+// state = h.SaveState(state[:0])
+func (h *Hasher256) SaveState(target []byte) []byte {
+ return h.h.saveState(target, statePrefix256)
+}
+
+// MarshalBinary returns the intermediate state of the rolling hash serialized
+// into a binary form that may be used to resume from the current state later
+// without having to write the previously written data again. It does not
+// change the underlying hash state.
+//
+// As described by the [Hasher256] documentation, the hasher instance can simply
+// be copied to achieve the same result much more efficiently when the caller is
+// able to keep a copy. Therefore, that approach should be preferred when
+// possible.
+//
+// However, the ability to serialize the state is also provided to enable
+// sharing it across process boundaries.
+//
+// NOTE: This method only returns an error in order to satisfy the
+// [encoding.BinaryMarshaler] interface. However, it will never error, meaning
+// the error will always be nil, so it is safe to ignore.
+//
+// Callers that wish to avoid allocations should prefer [Hasher256.SaveState]
+// instead.
+func (h *Hasher256) MarshalBinary() ([]byte, error) {
+ var state [SavedStateSize]byte
+ h.h.putSavedState(state[:], statePrefix256)
+ return state[:], nil
+}
+
+// UnmarshalBinary restores the rolling hash to the provided serialized
+// intermediate state. See [Hasher256.MarshalBinary] for more details.
+//
+// [ErrMalformedState] will be returned when the provided serialized state is
+// not at least the required [SavedStateSize] number of bytes.
+//
+// [ErrMismatchedState] will be returned if the provided state is not for a
+// BLAKE-256 hash. For example, it will be returned when attempting to restore
+// a BLAKE-224 intermediate state.
+//
+// This implements the [encoding.BinaryUnmarshaler] interface.
+func (h *Hasher256) UnmarshalBinary(state []byte) error {
+ return h.h.loadState(state, statePrefix256)
+}
+
+// NewHasher256 returns a zero-allocation hasher for computing a rolling
+// BLAKE-256 checksum.
+func NewHasher256() *Hasher256 {
+ h := Hasher256{makeHasher(iv256)}
+ return &h
+}
+
+// NewHasher256Salt returns a zero-allocation hasher for computing a rolling
+// BLAKE-256 checksum initialized with the given 16-byte salt slice.
+//
+// It will panic if the provided salt is not 16 bytes.
+func NewHasher256Salt(salt []byte) *Hasher256 {
+ h := Hasher256{makeHasher(iv256)}
+ h.h.initializeSalt(salt)
+ return &h
+}
+
+// New returns a new [hash.Hash] computing the BLAKE-256 checksum.
+//
+// Callers should prefer [NewHasher256] instead since it returns a concrete type
+// that has more functionality and allows avoiding additional allocations. It
+// can also be used as a [hash.Hash] if desired.
+func New() hash.Hash {
+ return NewHasher256()
+}
+
+// NewSalt returns a new [hash.Hash] computing the BLAKE-256 checksum
+// initialized with the given 16-byte salt.
+//
+// It will panic if the provided salt is not 16 bytes.
+//
+// Callers should prefer [NewHasher256Salt] instead since it returns a concrete
+// type that has more functionality and allows avoiding additional allocations.
+// It can also be used as a [hash.Hash] if desired.
+func NewSalt(salt []byte) hash.Hash {
+ return NewHasher256Salt(salt)
+}
+
+// Sum256 returns the BLAKE-256 checksum of the data.
+func Sum256(data []byte) [Size]byte {
+ h := makeHasher(iv256)
+ h.write(data)
+ return h.finalize256()
+}
diff --git a/vendor/github.com/decred/dcrd/crypto/blake256/internal/compress/README.md b/vendor/github.com/decred/dcrd/crypto/blake256/internal/compress/README.md
new file mode 100644
index 0000000..15b0c20
--- /dev/null
+++ b/vendor/github.com/decred/dcrd/crypto/blake256/internal/compress/README.md
@@ -0,0 +1,55 @@
+compress
+========
+
+[![Build Status](https://github.com/decred/dcrd/workflows/Build%20and%20Test/badge.svg)](https://github.com/decred/dcrd/actions)
+[![ISC License](https://img.shields.io/badge/license-ISC-blue.svg)](http://copyfree.org)
+[![Doc](https://img.shields.io/badge/doc-reference-blue.svg)](https://pkg.go.dev/github.com/decred/dcrd/crypto/blake256/internal/compress)
+
+## Overview
+
+Package `compress` implements the BLAKE-224 and BLAKE-256 block compression
+function. It provides a pure Go implementation as well as specialized
+implementations that take advantage of vector extensions (SSE2, SSE4.1, and AVX)
+on the `amd64` architecture when they are supported.
+
+The package detects hardware support and arranges for the exported `Blocks`
+function to automatically use the fastest available supported hardware
+extensions that are not disabled.
+
+## Tests and Benchmarks
+
+The package also provides full tests for all implementations as well as
+benchmarks. However, do note that since the specialized implementations require
+hardware support, the tests and benchmarks for them will be skipped when running
+on hardware that does not support the required extensions.
+
+It is possible to test all implementations without hardware support by using
+software such as the [Intel Software Development Emulator](https://www.intel.com/content/www/us/en/developer/articles/tool/software-development-emulator.html).
+
+Some relevant flags for testing purposes with the Intel SDE are:
+
+* SSE2: `-p4p Set chip-check and CPUID for Intel(R) Pentium4 Prescott CPU`
+* SSE41: `-pnr Set chip-check and CPUID for Intel(R) Penryn CPU`
+* AVX: `-snb Set chip-check and CPUID for Intel(R) Sandy Bridge CPU`
+
+## Disabling Assembler Optimizations
+
+The `purego` build tag may be used to disable all assembly code.
+
+Additionally, when built normally without the `purego` build tag, the assembly
+optimizations for each of the supported vector extensions can individually be
+disabled at runtime by setting the following environment variables to `1`.
+
+* `BLAKE256_DISABLE_AVX=1`: Disable Advanced Vector Extensions (AVX) optimizations
+* `BLAKE256_DISABLE_SSE41=1`: Disable Streaming SIMD Extensions 4.1 (SSE4.1) optimizations
+* `BLAKE256_DISABLE_SSE2=1`: Disable Streaming SIMD Extensions 2 (SSE2) optimizations
+
+## Installation and Updating
+
+This package is internal and therefore is neither directly installed nor needs
+to be manually updated.
+
+## License
+
+Package compress is licensed under the [copyfree](http://copyfree.org) ISC
+License.
diff --git a/vendor/github.com/decred/dcrd/crypto/blake256/internal/compress/blocks_amd64.go b/vendor/github.com/decred/dcrd/crypto/blake256/internal/compress/blocks_amd64.go
new file mode 100644
index 0000000..77a05e3
--- /dev/null
+++ b/vendor/github.com/decred/dcrd/crypto/blake256/internal/compress/blocks_amd64.go
@@ -0,0 +1,26 @@
+// Code generated by command: go run gen_amd64_compress_asm.go -out ../compress/blocks_amd64.s -stubs ../compress/blocks_amd64.go -pkg compress. DO NOT EDIT.
+
+//go:build !purego
+
+package compress
+
+// blocksSSE2 performs BLAKE-224 and BLAKE-256 block compression
+// using SSE2 extensions. See [Blocks] in blocksisa_amd64.go for
+// parameter details.
+//
+//go:noescape
+func blocksSSE2(state *State, msg []byte, counter uint64)
+
+// blocksSSE41 performs BLAKE-224 and BLAKE-256 block compression
+// using SSE41 extensions. See [Blocks] in blocksisa_amd64.go for
+// parameter details. The scratch parameter is not used.
+//
+//go:noescape
+func blocksSSE41(state *State, msg []byte, counter uint64)
+
+// blocksAVX performs BLAKE-224 and BLAKE-256 block compression
+// using AVX extensions. See [Blocks] in blocksisa_amd64.go for
+// parameter details.
+//
+//go:noescape
+func blocksAVX(state *State, msg []byte, counter uint64)
diff --git a/vendor/github.com/decred/dcrd/crypto/blake256/internal/compress/blocks_amd64.s b/vendor/github.com/decred/dcrd/crypto/blake256/internal/compress/blocks_amd64.s
new file mode 100644
index 0000000..6b14b20
--- /dev/null
+++ b/vendor/github.com/decred/dcrd/crypto/blake256/internal/compress/blocks_amd64.s
@@ -0,0 +1,4072 @@
+// Code generated by command: go run gen_amd64_compress_asm.go -out ../compress/blocks_amd64.s -stubs ../compress/blocks_amd64.go -pkg compress. DO NOT EDIT.
+
+//go:build !purego
+
+#include "textflag.h"
+
+DATA first_8_blake_consts<>+0(SB)/8, $0x85a308d3243f6a88
+DATA first_8_blake_consts<>+8(SB)/8, $0x0370734413198a2e
+DATA first_8_blake_consts<>+16(SB)/8, $0x299f31d0a4093822
+DATA first_8_blake_consts<>+24(SB)/8, $0xec4e6c89082efa98
+GLOBL first_8_blake_consts<>(SB), RODATA|NOPTR, $32
+
+DATA permuted_blake_consts<>+0(SB)/8, $0x0370734485a308d3
+DATA permuted_blake_consts<>+8(SB)/8, $0xec4e6c89299f31d0
+DATA permuted_blake_consts<>+16(SB)/8, $0x13198a2e243f6a88
+DATA permuted_blake_consts<>+24(SB)/8, $0x082efa98a4093822
+DATA permuted_blake_consts<>+32(SB)/8, $0x34e90c6c38d01377
+DATA permuted_blake_consts<>+40(SB)/8, $0xb5470917c97c50dd
+DATA permuted_blake_consts<>+48(SB)/8, $0xbe5466cf452821e6
+DATA permuted_blake_consts<>+56(SB)/8, $0x3f84d5b5c0ac29b7
+DATA permuted_blake_consts<>+64(SB)/8, $0x452821e6be5466cf
+DATA permuted_blake_consts<>+72(SB)/8, $0x082efa98b5470917
+DATA permuted_blake_consts<>+80(SB)/8, $0xa40938223f84d5b5
+DATA permuted_blake_consts<>+88(SB)/8, $0xc97c50dd38d01377
+DATA permuted_blake_consts<>+96(SB)/8, $0x13198a2ec0ac29b7
+DATA permuted_blake_consts<>+104(SB)/8, $0x03707344ec4e6c89
+DATA permuted_blake_consts<>+112(SB)/8, $0x243f6a8885a308d3
+DATA permuted_blake_consts<>+120(SB)/8, $0x299f31d034e90c6c
+DATA permuted_blake_consts<>+128(SB)/8, $0x243f6a88452821e6
+DATA permuted_blake_consts<>+136(SB)/8, $0xc97c50dd13198a2e
+DATA permuted_blake_consts<>+144(SB)/8, $0xc0ac29b734e90c6c
+DATA permuted_blake_consts<>+152(SB)/8, $0xb5470917299f31d0
+DATA permuted_blake_consts<>+160(SB)/8, $0x082efa983f84d5b5
+DATA permuted_blake_consts<>+168(SB)/8, $0xa409382285a308d3
+DATA permuted_blake_consts<>+176(SB)/8, $0x03707344be5466cf
+DATA permuted_blake_consts<>+184(SB)/8, $0x38d01377ec4e6c89
+DATA permuted_blake_consts<>+192(SB)/8, $0x85a308d338d01377
+DATA permuted_blake_consts<>+200(SB)/8, $0x3f84d5b5c0ac29b7
+DATA permuted_blake_consts<>+208(SB)/8, $0x03707344ec4e6c89
+DATA permuted_blake_consts<>+216(SB)/8, $0x34e90c6cc97c50dd
+DATA permuted_blake_consts<>+224(SB)/8, $0xbe5466cf082efa98
+DATA permuted_blake_consts<>+232(SB)/8, $0x452821e6243f6a88
+DATA permuted_blake_consts<>+240(SB)/8, $0x299f31d013198a2e
+DATA permuted_blake_consts<>+248(SB)/8, $0xb5470917a4093822
+DATA permuted_blake_consts<>+256(SB)/8, $0xec4e6c89243f6a88
+DATA permuted_blake_consts<>+264(SB)/8, $0xb5470917a4093822
+DATA permuted_blake_consts<>+272(SB)/8, $0x299f31d038d01377
+DATA permuted_blake_consts<>+280(SB)/8, $0xbe5466cf13198a2e
+DATA permuted_blake_consts<>+288(SB)/8, $0xc0ac29b785a308d3
+DATA permuted_blake_consts<>+296(SB)/8, $0xc97c50dd452821e6
+DATA permuted_blake_consts<>+304(SB)/8, $0x34e90c6c3f84d5b5
+DATA permuted_blake_consts<>+312(SB)/8, $0x03707344082efa98
+DATA permuted_blake_consts<>+320(SB)/8, $0xbe5466cfc0ac29b7
+DATA permuted_blake_consts<>+328(SB)/8, $0x0370734434e90c6c
+DATA permuted_blake_consts<>+336(SB)/8, $0x082efa9813198a2e
+DATA permuted_blake_consts<>+344(SB)/8, $0x452821e6243f6a88
+DATA permuted_blake_consts<>+352(SB)/8, $0x299f31d0c97c50dd
+DATA permuted_blake_consts<>+360(SB)/8, $0x38d013773f84d5b5
+DATA permuted_blake_consts<>+368(SB)/8, $0xec4e6c89a4093822
+DATA permuted_blake_consts<>+376(SB)/8, $0x85a308d3b5470917
+DATA permuted_blake_consts<>+384(SB)/8, $0xb5470917299f31d0
+DATA permuted_blake_consts<>+392(SB)/8, $0xbe5466cfc97c50dd
+DATA permuted_blake_consts<>+400(SB)/8, $0x85a308d3c0ac29b7
+DATA permuted_blake_consts<>+408(SB)/8, $0xa40938223f84d5b5
+DATA permuted_blake_consts<>+416(SB)/8, $0x03707344ec4e6c89
+DATA permuted_blake_consts<>+424(SB)/8, $0x34e90c6c13198a2e
+DATA permuted_blake_consts<>+432(SB)/8, $0x082efa98243f6a88
+DATA permuted_blake_consts<>+440(SB)/8, $0x452821e638d01377
+DATA permuted_blake_consts<>+448(SB)/8, $0x3f84d5b534e90c6c
+DATA permuted_blake_consts<>+456(SB)/8, $0x38d0137785a308d3
+DATA permuted_blake_consts<>+464(SB)/8, $0xec4e6c89c97c50dd
+DATA permuted_blake_consts<>+472(SB)/8, $0x03707344c0ac29b7
+DATA permuted_blake_consts<>+480(SB)/8, $0xa4093822243f6a88
+DATA permuted_blake_consts<>+488(SB)/8, $0xbe5466cf082efa98
+DATA permuted_blake_consts<>+496(SB)/8, $0xb5470917299f31d0
+DATA permuted_blake_consts<>+504(SB)/8, $0x13198a2e452821e6
+DATA permuted_blake_consts<>+512(SB)/8, $0x38d01377b5470917
+DATA permuted_blake_consts<>+520(SB)/8, $0x452821e603707344
+DATA permuted_blake_consts<>+528(SB)/8, $0x3f84d5b5082efa98
+DATA permuted_blake_consts<>+536(SB)/8, $0x243f6a8834e90c6c
+DATA permuted_blake_consts<>+544(SB)/8, $0xec4e6c8913198a2e
+DATA permuted_blake_consts<>+552(SB)/8, $0x299f31d0a4093822
+DATA permuted_blake_consts<>+560(SB)/8, $0xc97c50ddc0ac29b7
+DATA permuted_blake_consts<>+568(SB)/8, $0xbe5466cf85a308d3
+DATA permuted_blake_consts<>+576(SB)/8, $0xa409382213198a2e
+DATA permuted_blake_consts<>+584(SB)/8, $0x299f31d0082efa98
+DATA permuted_blake_consts<>+592(SB)/8, $0x452821e6be5466cf
+DATA permuted_blake_consts<>+600(SB)/8, $0x85a308d3ec4e6c89
+DATA permuted_blake_consts<>+608(SB)/8, $0x3f84d5b534e90c6c
+DATA permuted_blake_consts<>+616(SB)/8, $0x243f6a88c0ac29b7
+DATA permuted_blake_consts<>+624(SB)/8, $0x38d01377b5470917
+DATA permuted_blake_consts<>+632(SB)/8, $0xc97c50dd03707344
+GLOBL permuted_blake_consts<>(SB), RODATA|NOPTR, $640
+
+DATA shuffle_rotr8_4x32<>+0(SB)/8, $0x0407060500030201
+DATA shuffle_rotr8_4x32<>+8(SB)/8, $0x0c0f0e0d080b0a09
+GLOBL shuffle_rotr8_4x32<>(SB), RODATA|NOPTR, $16
+
+DATA shuffle_rotr16_4x32<>+0(SB)/8, $0x0504070601000302
+DATA shuffle_rotr16_4x32<>+8(SB)/8, $0x0d0c0f0e09080b0a
+GLOBL shuffle_rotr16_4x32<>(SB), RODATA|NOPTR, $16
+
+DATA shuffle_le_to_be_4x32<>+0(SB)/8, $0x0405060700010203
+DATA shuffle_le_to_be_4x32<>+8(SB)/8, $0x0c0d0e0f08090a0b
+GLOBL shuffle_le_to_be_4x32<>(SB), RODATA|NOPTR, $16
+
+// func blocksSSE2(state *State, msg []byte, counter uint64)
+// Requires: SSE2
+TEXT ·blocksSSE2(SB), $64-40
+ MOVQ state+0(FP), AX
+ MOVQ counter+32(FP), CX
+ MOVQ msg_base+8(FP), DX
+ MOVQ msg_len+16(FP), BX
+
+ // Convert message len to number of blocks for loop counter.
+ SHRQ $0x06, BX
+
+ // Initialize state matrix.
+ // row0 = |v0 v1 v2 v3| | h0 h1 h2 h3 |
+ // row1 = |v4 v5 v6 v7| | h4 h5 h6 h7 |
+ MOVOU 32(AX), X0
+ MOVOU (AX), X1
+ MOVOU 16(AX), X2
+
+compressLoop:
+ // row2 = |v8 v9 va vb| = |s0^c0 s1^c1 s2^c2 s3^c3|
+ // row3 = |vc vd ve vf| |t0^c4 t0^c5 t1^c6 t1^c7|
+ MOVOU first_8_blake_consts<>+0(SB), X3
+ PXOR X0, X3
+ MOVD CX, X4
+ PSHUFD $0x50, X4, X4
+ PXOR first_8_blake_consts<>+16(SB), X4
+ MOVO X1, X5
+ MOVO X2, X6
+
+ // Convert message to big endian.
+ MOVL (DX), SI
+ MOVL 4(DX), DI
+ MOVL 8(DX), R8
+ MOVL 12(DX), R9
+ MOVL 16(DX), R10
+ MOVL 20(DX), R11
+ MOVL 24(DX), R12
+ MOVL 28(DX), R13
+ BSWAPL SI
+ MOVL SI, (SP)
+ BSWAPL DI
+ MOVL DI, 4(SP)
+ BSWAPL R8
+ MOVL R8, 8(SP)
+ BSWAPL R9
+ MOVL R9, 12(SP)
+ BSWAPL R10
+ MOVL R10, 16(SP)
+ BSWAPL R11
+ MOVL R11, 20(SP)
+ BSWAPL R12
+ MOVL R12, 24(SP)
+ BSWAPL R13
+ MOVL R13, 28(SP)
+ MOVL 32(DX), SI
+ MOVL 36(DX), DI
+ MOVL 40(DX), R8
+ MOVL 44(DX), R9
+ MOVL 48(DX), R10
+ MOVL 52(DX), R11
+ MOVL 56(DX), R12
+ MOVL 60(DX), R13
+ BSWAPL SI
+ MOVL SI, 32(SP)
+ BSWAPL DI
+ MOVL DI, 36(SP)
+ BSWAPL R8
+ MOVL R8, 40(SP)
+ BSWAPL R9
+ MOVL R9, 44(SP)
+ BSWAPL R10
+ MOVL R10, 48(SP)
+ BSWAPL R11
+ MOVL R11, 52(SP)
+ BSWAPL R12
+ MOVL R12, 56(SP)
+ BSWAPL R13
+ MOVL R13, 60(SP)
+
+ // Round 1 column step.
+ MOVD 24(SP), X9
+ MOVD 16(SP), X7
+ MOVOA X7, X8
+ PUNPCKLLQ X9, X8
+ MOVD 8(SP), X7
+ MOVD (SP), X9
+ PUNPCKLLQ X7, X9
+ PUNPCKLQDQ X8, X9
+ MOVOU permuted_blake_consts<>+0(SB), X8
+ PXOR X9, X8
+ PADDD X8, X1
+ MOVD 28(SP), X9
+ MOVD 20(SP), X7
+ MOVOA X7, X8
+ PUNPCKLLQ X9, X8
+ MOVD 12(SP), X7
+ MOVD 4(SP), X9
+ PUNPCKLLQ X7, X9
+ PUNPCKLQDQ X8, X9
+ MOVOU permuted_blake_consts<>+16(SB), X8
+ PXOR X9, X8
+ PADDD X2, X1
+ PXOR X1, X4
+ MOVO X4, X7
+ PSRLL $0x10, X7
+ PSLLL $0x10, X4
+ PXOR X7, X4
+ PADDD X4, X3
+ PXOR X3, X2
+ MOVO X2, X7
+ PSRLL $0x0c, X7
+ PSLLL $0x14, X2
+ PXOR X7, X2
+ PADDD X8, X1
+ PADDD X2, X1
+ PXOR X1, X4
+ MOVO X4, X7
+ PSRLL $0x08, X7
+ PSLLL $0x18, X4
+ PXOR X7, X4
+ PADDD X4, X3
+ PXOR X3, X2
+ MOVO X2, X7
+ PSRLL $0x07, X7
+ PSLLL $0x19, X2
+ PXOR X7, X2
+
+ // Round 1 diagonal step part 1: diagonalize.
+ PSHUFD $0x39, X2, X2
+ PSHUFD $0x4e, X3, X3
+ PSHUFD $0x93, X4, X4
+
+ // Round 1 diagonal step part 2: column step.
+ MOVD 56(SP), X9
+ MOVD 48(SP), X7
+ MOVOA X7, X8
+ PUNPCKLLQ X9, X8
+ MOVD 40(SP), X7
+ MOVD 32(SP), X9
+ PUNPCKLLQ X7, X9
+ PUNPCKLQDQ X8, X9
+ MOVOU permuted_blake_consts<>+32(SB), X8
+ PXOR X9, X8
+ PADDD X8, X1
+ MOVD 60(SP), X9
+ MOVD 52(SP), X7
+ MOVOA X7, X8
+ PUNPCKLLQ X9, X8
+ MOVD 44(SP), X7
+ MOVD 36(SP), X9
+ PUNPCKLLQ X7, X9
+ PUNPCKLQDQ X8, X9
+ MOVOU permuted_blake_consts<>+48(SB), X8
+ PXOR X9, X8
+ PADDD X2, X1
+ PXOR X1, X4
+ MOVO X4, X7
+ PSRLL $0x10, X7
+ PSLLL $0x10, X4
+ PXOR X7, X4
+ PADDD X4, X3
+ PXOR X3, X2
+ MOVO X2, X7
+ PSRLL $0x0c, X7
+ PSLLL $0x14, X2
+ PXOR X7, X2
+ PADDD X8, X1
+ PADDD X2, X1
+ PXOR X1, X4
+ MOVO X4, X7
+ PSRLL $0x08, X7
+ PSLLL $0x18, X4
+ PXOR X7, X4
+ PADDD X4, X3
+ PXOR X3, X2
+ MOVO X2, X7
+ PSRLL $0x07, X7
+ PSLLL $0x19, X2
+ PXOR X7, X2
+
+ // Round 1 diagonal step part 3: undiagonalize.
+ PSHUFD $0x93, X2, X2
+ PSHUFD $0x4e, X3, X3
+ PSHUFD $0x39, X4, X4
+
+ // Round 2 column step.
+ MOVD 52(SP), X9
+ MOVD 36(SP), X7
+ MOVOA X7, X8
+ PUNPCKLLQ X9, X8
+ MOVD 16(SP), X7
+ MOVD 56(SP), X9
+ PUNPCKLLQ X7, X9
+ PUNPCKLQDQ X8, X9
+ MOVOU permuted_blake_consts<>+64(SB), X8
+ PXOR X9, X8
+ PADDD X8, X1
+ MOVD 24(SP), X9
+ MOVD 60(SP), X7
+ MOVOA X7, X8
+ PUNPCKLLQ X9, X8
+ MOVD 32(SP), X7
+ MOVD 40(SP), X9
+ PUNPCKLLQ X7, X9
+ PUNPCKLQDQ X8, X9
+ MOVOU permuted_blake_consts<>+80(SB), X8
+ PXOR X9, X8
+ PADDD X2, X1
+ PXOR X1, X4
+ MOVO X4, X7
+ PSRLL $0x10, X7
+ PSLLL $0x10, X4
+ PXOR X7, X4
+ PADDD X4, X3
+ PXOR X3, X2
+ MOVO X2, X7
+ PSRLL $0x0c, X7
+ PSLLL $0x14, X2
+ PXOR X7, X2
+ PADDD X8, X1
+ PADDD X2, X1
+ PXOR X1, X4
+ MOVO X4, X7
+ PSRLL $0x08, X7
+ PSLLL $0x18, X4
+ PXOR X7, X4
+ PADDD X4, X3
+ PXOR X3, X2
+ MOVO X2, X7
+ PSRLL $0x07, X7
+ PSLLL $0x19, X2
+ PXOR X7, X2
+
+ // Round 2 diagonal step part 1: diagonalize.
+ PSHUFD $0x39, X2, X2
+ PSHUFD $0x4e, X3, X3
+ PSHUFD $0x93, X4, X4
+
+ // Round 2 diagonal step part 2: column step.
+ MOVD 20(SP), X9
+ MOVD 44(SP), X7
+ MOVOA X7, X8
+ PUNPCKLLQ X9, X8
+ MOVD (SP), X7
+ MOVD 4(SP), X9
+ PUNPCKLLQ X7, X9
+ PUNPCKLQDQ X8, X9
+ MOVOU permuted_blake_consts<>+96(SB), X8
+ PXOR X9, X8
+ PADDD X8, X1
+ MOVD 12(SP), X9
+ MOVD 28(SP), X7
+ MOVOA X7, X8
+ PUNPCKLLQ X9, X8
+ MOVD 8(SP), X7
+ MOVD 48(SP), X9
+ PUNPCKLLQ X7, X9
+ PUNPCKLQDQ X8, X9
+ MOVOU permuted_blake_consts<>+112(SB), X8
+ PXOR X9, X8
+ PADDD X2, X1
+ PXOR X1, X4
+ MOVO X4, X7
+ PSRLL $0x10, X7
+ PSLLL $0x10, X4
+ PXOR X7, X4
+ PADDD X4, X3
+ PXOR X3, X2
+ MOVO X2, X7
+ PSRLL $0x0c, X7
+ PSLLL $0x14, X2
+ PXOR X7, X2
+ PADDD X8, X1
+ PADDD X2, X1
+ PXOR X1, X4
+ MOVO X4, X7
+ PSRLL $0x08, X7
+ PSLLL $0x18, X4
+ PXOR X7, X4
+ PADDD X4, X3
+ PXOR X3, X2
+ MOVO X2, X7
+ PSRLL $0x07, X7
+ PSLLL $0x19, X2
+ PXOR X7, X2
+
+ // Round 2 diagonal step part 3: undiagonalize.
+ PSHUFD $0x93, X2, X2
+ PSHUFD $0x4e, X3, X3
+ PSHUFD $0x39, X4, X4
+
+ // Round 3 column step.
+ MOVD 60(SP), X9
+ MOVD 20(SP), X7
+ MOVOA X7, X8
+ PUNPCKLLQ X9, X8
+ MOVD 48(SP), X7
+ MOVD 44(SP), X9
+ PUNPCKLLQ X7, X9
+ PUNPCKLQDQ X8, X9
+ MOVOU permuted_blake_consts<>+128(SB), X8
+ PXOR X9, X8
+ PADDD X8, X1
+ MOVD 52(SP), X9
+ MOVD 8(SP), X7
+ MOVOA X7, X8
+ PUNPCKLLQ X9, X8
+ MOVD (SP), X7
+ MOVD 32(SP), X9
+ PUNPCKLLQ X7, X9
+ PUNPCKLQDQ X8, X9
+ MOVOU permuted_blake_consts<>+144(SB), X8
+ PXOR X9, X8
+ PADDD X2, X1
+ PXOR X1, X4
+ MOVO X4, X7
+ PSRLL $0x10, X7
+ PSLLL $0x10, X4
+ PXOR X7, X4
+ PADDD X4, X3
+ PXOR X3, X2
+ MOVO X2, X7
+ PSRLL $0x0c, X7
+ PSLLL $0x14, X2
+ PXOR X7, X2
+ PADDD X8, X1
+ PADDD X2, X1
+ PXOR X1, X4
+ MOVO X4, X7
+ PSRLL $0x08, X7
+ PSLLL $0x18, X4
+ PXOR X7, X4
+ PADDD X4, X3
+ PXOR X3, X2
+ MOVO X2, X7
+ PSRLL $0x07, X7
+ PSLLL $0x19, X2
+ PXOR X7, X2
+
+ // Round 3 diagonal step part 1: diagonalize.
+ PSHUFD $0x39, X2, X2
+ PSHUFD $0x4e, X3, X3
+ PSHUFD $0x93, X4, X4
+
+ // Round 3 diagonal step part 2: column step.
+ MOVD 36(SP), X9
+ MOVD 28(SP), X7
+ MOVOA X7, X8
+ PUNPCKLLQ X9, X8
+ MOVD 12(SP), X7
+ MOVD 40(SP), X9
+ PUNPCKLLQ X7, X9
+ PUNPCKLQDQ X8, X9
+ MOVOU permuted_blake_consts<>+160(SB), X8
+ PXOR X9, X8
+ PADDD X8, X1
+ MOVD 16(SP), X9
+ MOVD 4(SP), X7
+ MOVOA X7, X8
+ PUNPCKLLQ X9, X8
+ MOVD 24(SP), X7
+ MOVD 56(SP), X9
+ PUNPCKLLQ X7, X9
+ PUNPCKLQDQ X8, X9
+ MOVOU permuted_blake_consts<>+176(SB), X8
+ PXOR X9, X8
+ PADDD X2, X1
+ PXOR X1, X4
+ MOVO X4, X7
+ PSRLL $0x10, X7
+ PSLLL $0x10, X4
+ PXOR X7, X4
+ PADDD X4, X3
+ PXOR X3, X2
+ MOVO X2, X7
+ PSRLL $0x0c, X7
+ PSLLL $0x14, X2
+ PXOR X7, X2
+ PADDD X8, X1
+ PADDD X2, X1
+ PXOR X1, X4
+ MOVO X4, X7
+ PSRLL $0x08, X7
+ PSLLL $0x18, X4
+ PXOR X7, X4
+ PADDD X4, X3
+ PXOR X3, X2
+ MOVO X2, X7
+ PSRLL $0x07, X7
+ PSLLL $0x19, X2
+ PXOR X7, X2
+
+ // Round 3 diagonal step part 3: undiagonalize.
+ PSHUFD $0x93, X2, X2
+ PSHUFD $0x4e, X3, X3
+ PSHUFD $0x39, X4, X4
+
+ // Round 4 column step.
+ MOVD 44(SP), X9
+ MOVD 52(SP), X7
+ MOVOA X7, X8
+ PUNPCKLLQ X9, X8
+ MOVD 12(SP), X7
+ MOVD 28(SP), X9
+ PUNPCKLLQ X7, X9
+ PUNPCKLQDQ X8, X9
+ MOVOU permuted_blake_consts<>+192(SB), X8
+ PXOR X9, X8
+ PADDD X8, X1
+ MOVD 56(SP), X9
+ MOVD 48(SP), X7
+ MOVOA X7, X8
+ PUNPCKLLQ X9, X8
+ MOVD 4(SP), X7
+ MOVD 36(SP), X9
+ PUNPCKLLQ X7, X9
+ PUNPCKLQDQ X8, X9
+ MOVOU permuted_blake_consts<>+208(SB), X8
+ PXOR X9, X8
+ PADDD X2, X1
+ PXOR X1, X4
+ MOVO X4, X7
+ PSRLL $0x10, X7
+ PSLLL $0x10, X4
+ PXOR X7, X4
+ PADDD X4, X3
+ PXOR X3, X2
+ MOVO X2, X7
+ PSRLL $0x0c, X7
+ PSLLL $0x14, X2
+ PXOR X7, X2
+ PADDD X8, X1
+ PADDD X2, X1
+ PXOR X1, X4
+ MOVO X4, X7
+ PSRLL $0x08, X7
+ PSLLL $0x18, X4
+ PXOR X7, X4
+ PADDD X4, X3
+ PXOR X3, X2
+ MOVO X2, X7
+ PSRLL $0x07, X7
+ PSLLL $0x19, X2
+ PXOR X7, X2
+
+ // Round 4 diagonal step part 1: diagonalize.
+ PSHUFD $0x39, X2, X2
+ PSHUFD $0x4e, X3, X3
+ PSHUFD $0x93, X4, X4
+
+ // Round 4 diagonal step part 2: column step.
+ MOVD 60(SP), X9
+ MOVD 16(SP), X7
+ MOVOA X7, X8
+ PUNPCKLLQ X9, X8
+ MOVD 20(SP), X7
+ MOVD 8(SP), X9
+ PUNPCKLLQ X7, X9
+ PUNPCKLQDQ X8, X9
+ MOVOU permuted_blake_consts<>+224(SB), X8
+ PXOR X9, X8
+ PADDD X8, X1
+ MOVD 32(SP), X9
+ MOVD (SP), X7
+ MOVOA X7, X8
+ PUNPCKLLQ X9, X8
+ MOVD 40(SP), X7
+ MOVD 24(SP), X9
+ PUNPCKLLQ X7, X9
+ PUNPCKLQDQ X8, X9
+ MOVOU permuted_blake_consts<>+240(SB), X8
+ PXOR X9, X8
+ PADDD X2, X1
+ PXOR X1, X4
+ MOVO X4, X7
+ PSRLL $0x10, X7
+ PSLLL $0x10, X4
+ PXOR X7, X4
+ PADDD X4, X3
+ PXOR X3, X2
+ MOVO X2, X7
+ PSRLL $0x0c, X7
+ PSLLL $0x14, X2
+ PXOR X7, X2
+ PADDD X8, X1
+ PADDD X2, X1
+ PXOR X1, X4
+ MOVO X4, X7
+ PSRLL $0x08, X7
+ PSLLL $0x18, X4
+ PXOR X7, X4
+ PADDD X4, X3
+ PXOR X3, X2
+ MOVO X2, X7
+ PSRLL $0x07, X7
+ PSLLL $0x19, X2
+ PXOR X7, X2
+
+ // Round 4 diagonal step part 3: undiagonalize.
+ PSHUFD $0x93, X2, X2
+ PSHUFD $0x4e, X3, X3
+ PSHUFD $0x39, X4, X4
+
+ // Round 5 column step.
+ MOVD 40(SP), X9
+ MOVD 8(SP), X7
+ MOVOA X7, X8
+ PUNPCKLLQ X9, X8
+ MOVD 20(SP), X7
+ MOVD 36(SP), X9
+ PUNPCKLLQ X7, X9
+ PUNPCKLQDQ X8, X9
+ MOVOU permuted_blake_consts<>+256(SB), X8
+ PXOR X9, X8
+ PADDD X8, X1
+ MOVD 60(SP), X9
+ MOVD 16(SP), X7
+ MOVOA X7, X8
+ PUNPCKLLQ X9, X8
+ MOVD 28(SP), X7
+ MOVD (SP), X9
+ PUNPCKLLQ X7, X9
+ PUNPCKLQDQ X8, X9
+ MOVOU permuted_blake_consts<>+272(SB), X8
+ PXOR X9, X8
+ PADDD X2, X1
+ PXOR X1, X4
+ MOVO X4, X7
+ PSRLL $0x10, X7
+ PSLLL $0x10, X4
+ PXOR X7, X4
+ PADDD X4, X3
+ PXOR X3, X2
+ MOVO X2, X7
+ PSRLL $0x0c, X7
+ PSLLL $0x14, X2
+ PXOR X7, X2
+ PADDD X8, X1
+ PADDD X2, X1
+ PXOR X1, X4
+ MOVO X4, X7
+ PSRLL $0x08, X7
+ PSLLL $0x18, X4
+ PXOR X7, X4
+ PADDD X4, X3
+ PXOR X3, X2
+ MOVO X2, X7
+ PSRLL $0x07, X7
+ PSLLL $0x19, X2
+ PXOR X7, X2
+
+ // Round 5 diagonal step part 1: diagonalize.
+ PSHUFD $0x39, X2, X2
+ PSHUFD $0x4e, X3, X3
+ PSHUFD $0x93, X4, X4
+
+ // Round 5 diagonal step part 2: column step.
+ MOVD 12(SP), X9
+ MOVD 24(SP), X7
+ MOVOA X7, X8
+ PUNPCKLLQ X9, X8
+ MOVD 44(SP), X7
+ MOVD 56(SP), X9
+ PUNPCKLLQ X7, X9
+ PUNPCKLQDQ X8, X9
+ MOVOU permuted_blake_consts<>+288(SB), X8
+ PXOR X9, X8
+ PADDD X8, X1
+ MOVD 52(SP), X9
+ MOVD 32(SP), X7
+ MOVOA X7, X8
+ PUNPCKLLQ X9, X8
+ MOVD 48(SP), X7
+ MOVD 4(SP), X9
+ PUNPCKLLQ X7, X9
+ PUNPCKLQDQ X8, X9
+ MOVOU permuted_blake_consts<>+304(SB), X8
+ PXOR X9, X8
+ PADDD X2, X1
+ PXOR X1, X4
+ MOVO X4, X7
+ PSRLL $0x10, X7
+ PSLLL $0x10, X4
+ PXOR X7, X4
+ PADDD X4, X3
+ PXOR X3, X2
+ MOVO X2, X7
+ PSRLL $0x0c, X7
+ PSLLL $0x14, X2
+ PXOR X7, X2
+ PADDD X8, X1
+ PADDD X2, X1
+ PXOR X1, X4
+ MOVO X4, X7
+ PSRLL $0x08, X7
+ PSLLL $0x18, X4
+ PXOR X7, X4
+ PADDD X4, X3
+ PXOR X3, X2
+ MOVO X2, X7
+ PSRLL $0x07, X7
+ PSLLL $0x19, X2
+ PXOR X7, X2
+
+ // Round 5 diagonal step part 3: undiagonalize.
+ PSHUFD $0x93, X2, X2
+ PSHUFD $0x4e, X3, X3
+ PSHUFD $0x39, X4, X4
+
+ // Round 6 column step.
+ MOVD 32(SP), X9
+ MOVD (SP), X7
+ MOVOA X7, X8
+ PUNPCKLLQ X9, X8
+ MOVD 24(SP), X7
+ MOVD 8(SP), X9
+ PUNPCKLLQ X7, X9
+ PUNPCKLQDQ X8, X9
+ MOVOU permuted_blake_consts<>+320(SB), X8
+ PXOR X9, X8
+ PADDD X8, X1
+ MOVD 12(SP), X9
+ MOVD 44(SP), X7
+ MOVOA X7, X8
+ PUNPCKLLQ X9, X8
+ MOVD 40(SP), X7
+ MOVD 48(SP), X9
+ PUNPCKLLQ X7, X9
+ PUNPCKLQDQ X8, X9
+ MOVOU permuted_blake_consts<>+336(SB), X8
+ PXOR X9, X8
+ PADDD X2, X1
+ PXOR X1, X4
+ MOVO X4, X7
+ PSRLL $0x10, X7
+ PSLLL $0x10, X4
+ PXOR X7, X4
+ PADDD X4, X3
+ PXOR X3, X2
+ MOVO X2, X7
+ PSRLL $0x0c, X7
+ PSLLL $0x14, X2
+ PXOR X7, X2
+ PADDD X8, X1
+ PADDD X2, X1
+ PXOR X1, X4
+ MOVO X4, X7
+ PSRLL $0x08, X7
+ PSLLL $0x18, X4
+ PXOR X7, X4
+ PADDD X4, X3
+ PXOR X3, X2
+ MOVO X2, X7
+ PSRLL $0x07, X7
+ PSLLL $0x19, X2
+ PXOR X7, X2
+
+ // Round 6 diagonal step part 1: diagonalize.
+ PSHUFD $0x39, X2, X2
+ PSHUFD $0x4e, X3, X3
+ PSHUFD $0x93, X4, X4
+
+ // Round 6 diagonal step part 2: column step.
+ MOVD 4(SP), X9
+ MOVD 60(SP), X7
+ MOVOA X7, X8
+ PUNPCKLLQ X9, X8
+ MOVD 28(SP), X7
+ MOVD 16(SP), X9
+ PUNPCKLLQ X7, X9
+ PUNPCKLQDQ X8, X9
+ MOVOU permuted_blake_consts<>+352(SB), X8
+ PXOR X9, X8
+ PADDD X8, X1
+ MOVD 36(SP), X9
+ MOVD 56(SP), X7
+ MOVOA X7, X8
+ PUNPCKLLQ X9, X8
+ MOVD 20(SP), X7
+ MOVD 52(SP), X9
+ PUNPCKLLQ X7, X9
+ PUNPCKLQDQ X8, X9
+ MOVOU permuted_blake_consts<>+368(SB), X8
+ PXOR X9, X8
+ PADDD X2, X1
+ PXOR X1, X4
+ MOVO X4, X7
+ PSRLL $0x10, X7
+ PSLLL $0x10, X4
+ PXOR X7, X4
+ PADDD X4, X3
+ PXOR X3, X2
+ MOVO X2, X7
+ PSRLL $0x0c, X7
+ PSLLL $0x14, X2
+ PXOR X7, X2
+ PADDD X8, X1
+ PADDD X2, X1
+ PXOR X1, X4
+ MOVO X4, X7
+ PSRLL $0x08, X7
+ PSLLL $0x18, X4
+ PXOR X7, X4
+ PADDD X4, X3
+ PXOR X3, X2
+ MOVO X2, X7
+ PSRLL $0x07, X7
+ PSLLL $0x19, X2
+ PXOR X7, X2
+
+ // Round 6 diagonal step part 3: undiagonalize.
+ PSHUFD $0x93, X2, X2
+ PSHUFD $0x4e, X3, X3
+ PSHUFD $0x39, X4, X4
+
+ // Round 7 column step.
+ MOVD 16(SP), X9
+ MOVD 56(SP), X7
+ MOVOA X7, X8
+ PUNPCKLLQ X9, X8
+ MOVD 4(SP), X7
+ MOVD 48(SP), X9
+ PUNPCKLLQ X7, X9
+ PUNPCKLQDQ X8, X9
+ MOVOU permuted_blake_consts<>+384(SB), X8
+ PXOR X9, X8
+ PADDD X8, X1
+ MOVD 40(SP), X9
+ MOVD 52(SP), X7
+ MOVOA X7, X8
+ PUNPCKLLQ X9, X8
+ MOVD 60(SP), X7
+ MOVD 20(SP), X9
+ PUNPCKLLQ X7, X9
+ PUNPCKLQDQ X8, X9
+ MOVOU permuted_blake_consts<>+400(SB), X8
+ PXOR X9, X8
+ PADDD X2, X1
+ PXOR X1, X4
+ MOVO X4, X7
+ PSRLL $0x10, X7
+ PSLLL $0x10, X4
+ PXOR X7, X4
+ PADDD X4, X3
+ PXOR X3, X2
+ MOVO X2, X7
+ PSRLL $0x0c, X7
+ PSLLL $0x14, X2
+ PXOR X7, X2
+ PADDD X8, X1
+ PADDD X2, X1
+ PXOR X1, X4
+ MOVO X4, X7
+ PSRLL $0x08, X7
+ PSLLL $0x18, X4
+ PXOR X7, X4
+ PADDD X4, X3
+ PXOR X3, X2
+ MOVO X2, X7
+ PSRLL $0x07, X7
+ PSLLL $0x19, X2
+ PXOR X7, X2
+
+ // Round 7 diagonal step part 1: diagonalize.
+ PSHUFD $0x39, X2, X2
+ PSHUFD $0x4e, X3, X3
+ PSHUFD $0x93, X4, X4
+
+ // Round 7 diagonal step part 2: column step.
+ MOVD 32(SP), X9
+ MOVD 36(SP), X7
+ MOVOA X7, X8
+ PUNPCKLLQ X9, X8
+ MOVD 24(SP), X7
+ MOVD (SP), X9
+ PUNPCKLLQ X7, X9
+ PUNPCKLQDQ X8, X9
+ MOVOU permuted_blake_consts<>+416(SB), X8
+ PXOR X9, X8
+ PADDD X8, X1
+ MOVD 44(SP), X9
+ MOVD 8(SP), X7
+ MOVOA X7, X8
+ PUNPCKLLQ X9, X8
+ MOVD 12(SP), X7
+ MOVD 28(SP), X9
+ PUNPCKLLQ X7, X9
+ PUNPCKLQDQ X8, X9
+ MOVOU permuted_blake_consts<>+432(SB), X8
+ PXOR X9, X8
+ PADDD X2, X1
+ PXOR X1, X4
+ MOVO X4, X7
+ PSRLL $0x10, X7
+ PSLLL $0x10, X4
+ PXOR X7, X4
+ PADDD X4, X3
+ PXOR X3, X2
+ MOVO X2, X7
+ PSRLL $0x0c, X7
+ PSLLL $0x14, X2
+ PXOR X7, X2
+ PADDD X8, X1
+ PADDD X2, X1
+ PXOR X1, X4
+ MOVO X4, X7
+ PSRLL $0x08, X7
+ PSLLL $0x18, X4
+ PXOR X7, X4
+ PADDD X4, X3
+ PXOR X3, X2
+ MOVO X2, X7
+ PSRLL $0x07, X7
+ PSLLL $0x19, X2
+ PXOR X7, X2
+
+ // Round 7 diagonal step part 3: undiagonalize.
+ PSHUFD $0x93, X2, X2
+ PSHUFD $0x4e, X3, X3
+ PSHUFD $0x39, X4, X4
+
+ // Round 8 column step.
+ MOVD 12(SP), X9
+ MOVD 48(SP), X7
+ MOVOA X7, X8
+ PUNPCKLLQ X9, X8
+ MOVD 28(SP), X7
+ MOVD 52(SP), X9
+ PUNPCKLLQ X7, X9
+ PUNPCKLQDQ X8, X9
+ MOVOU permuted_blake_consts<>+448(SB), X8
+ PXOR X9, X8
+ PADDD X8, X1
+ MOVD 36(SP), X9
+ MOVD 4(SP), X7
+ MOVOA X7, X8
+ PUNPCKLLQ X9, X8
+ MOVD 56(SP), X7
+ MOVD 44(SP), X9
+ PUNPCKLLQ X7, X9
+ PUNPCKLQDQ X8, X9
+ MOVOU permuted_blake_consts<>+464(SB), X8
+ PXOR X9, X8
+ PADDD X2, X1
+ PXOR X1, X4
+ MOVO X4, X7
+ PSRLL $0x10, X7
+ PSLLL $0x10, X4
+ PXOR X7, X4
+ PADDD X4, X3
+ PXOR X3, X2
+ MOVO X2, X7
+ PSRLL $0x0c, X7
+ PSLLL $0x14, X2
+ PXOR X7, X2
+ PADDD X8, X1
+ PADDD X2, X1
+ PXOR X1, X4
+ MOVO X4, X7
+ PSRLL $0x08, X7
+ PSLLL $0x18, X4
+ PXOR X7, X4
+ PADDD X4, X3
+ PXOR X3, X2
+ MOVO X2, X7
+ PSRLL $0x07, X7
+ PSLLL $0x19, X2
+ PXOR X7, X2
+
+ // Round 8 diagonal step part 1: diagonalize.
+ PSHUFD $0x39, X2, X2
+ PSHUFD $0x4e, X3, X3
+ PSHUFD $0x93, X4, X4
+
+ // Round 8 diagonal step part 2: column step.
+ MOVD 8(SP), X9
+ MOVD 32(SP), X7
+ MOVOA X7, X8
+ PUNPCKLLQ X9, X8
+ MOVD 60(SP), X7
+ MOVD 20(SP), X9
+ PUNPCKLLQ X7, X9
+ PUNPCKLQDQ X8, X9
+ MOVOU permuted_blake_consts<>+480(SB), X8
+ PXOR X9, X8
+ PADDD X8, X1
+ MOVD 40(SP), X9
+ MOVD 24(SP), X7
+ MOVOA X7, X8
+ PUNPCKLLQ X9, X8
+ MOVD 16(SP), X7
+ MOVD (SP), X9
+ PUNPCKLLQ X7, X9
+ PUNPCKLQDQ X8, X9
+ MOVOU permuted_blake_consts<>+496(SB), X8
+ PXOR X9, X8
+ PADDD X2, X1
+ PXOR X1, X4
+ MOVO X4, X7
+ PSRLL $0x10, X7
+ PSLLL $0x10, X4
+ PXOR X7, X4
+ PADDD X4, X3
+ PXOR X3, X2
+ MOVO X2, X7
+ PSRLL $0x0c, X7
+ PSLLL $0x14, X2
+ PXOR X7, X2
+ PADDD X8, X1
+ PADDD X2, X1
+ PXOR X1, X4
+ MOVO X4, X7
+ PSRLL $0x08, X7
+ PSLLL $0x18, X4
+ PXOR X7, X4
+ PADDD X4, X3
+ PXOR X3, X2
+ MOVO X2, X7
+ PSRLL $0x07, X7
+ PSLLL $0x19, X2
+ PXOR X7, X2
+
+ // Round 8 diagonal step part 3: undiagonalize.
+ PSHUFD $0x93, X2, X2
+ PSHUFD $0x4e, X3, X3
+ PSHUFD $0x39, X4, X4
+
+ // Round 9 column step.
+ MOVD (SP), X9
+ MOVD 44(SP), X7
+ MOVOA X7, X8
+ PUNPCKLLQ X9, X8
+ MOVD 56(SP), X7
+ MOVD 24(SP), X9
+ PUNPCKLLQ X7, X9
+ PUNPCKLQDQ X8, X9
+ MOVOU permuted_blake_consts<>+512(SB), X8
+ PXOR X9, X8
+ PADDD X8, X1
+ MOVD 32(SP), X9
+ MOVD 12(SP), X7
+ MOVOA X7, X8
+ PUNPCKLLQ X9, X8
+ MOVD 36(SP), X7
+ MOVD 60(SP), X9
+ PUNPCKLLQ X7, X9
+ PUNPCKLQDQ X8, X9
+ MOVOU permuted_blake_consts<>+528(SB), X8
+ PXOR X9, X8
+ PADDD X2, X1
+ PXOR X1, X4
+ MOVO X4, X7
+ PSRLL $0x10, X7
+ PSLLL $0x10, X4
+ PXOR X7, X4
+ PADDD X4, X3
+ PXOR X3, X2
+ MOVO X2, X7
+ PSRLL $0x0c, X7
+ PSLLL $0x14, X2
+ PXOR X7, X2
+ PADDD X8, X1
+ PADDD X2, X1
+ PXOR X1, X4
+ MOVO X4, X7
+ PSRLL $0x08, X7
+ PSLLL $0x18, X4
+ PXOR X7, X4
+ PADDD X4, X3
+ PXOR X3, X2
+ MOVO X2, X7
+ PSRLL $0x07, X7
+ PSLLL $0x19, X2
+ PXOR X7, X2
+
+ // Round 9 diagonal step part 1: diagonalize.
+ PSHUFD $0x39, X2, X2
+ PSHUFD $0x4e, X3, X3
+ PSHUFD $0x93, X4, X4
+
+ // Round 9 diagonal step part 2: column step.
+ MOVD 40(SP), X9
+ MOVD 4(SP), X7
+ MOVOA X7, X8
+ PUNPCKLLQ X9, X8
+ MOVD 52(SP), X7
+ MOVD 48(SP), X9
+ PUNPCKLLQ X7, X9
+ PUNPCKLQDQ X8, X9
+ MOVOU permuted_blake_consts<>+544(SB), X8
+ PXOR X9, X8
+ PADDD X8, X1
+ MOVD 20(SP), X9
+ MOVD 16(SP), X7
+ MOVOA X7, X8
+ PUNPCKLLQ X9, X8
+ MOVD 28(SP), X7
+ MOVD 8(SP), X9
+ PUNPCKLLQ X7, X9
+ PUNPCKLQDQ X8, X9
+ MOVOU permuted_blake_consts<>+560(SB), X8
+ PXOR X9, X8
+ PADDD X2, X1
+ PXOR X1, X4
+ MOVO X4, X7
+ PSRLL $0x10, X7
+ PSLLL $0x10, X4
+ PXOR X7, X4
+ PADDD X4, X3
+ PXOR X3, X2
+ MOVO X2, X7
+ PSRLL $0x0c, X7
+ PSLLL $0x14, X2
+ PXOR X7, X2
+ PADDD X8, X1
+ PADDD X2, X1
+ PXOR X1, X4
+ MOVO X4, X7
+ PSRLL $0x08, X7
+ PSLLL $0x18, X4
+ PXOR X7, X4
+ PADDD X4, X3
+ PXOR X3, X2
+ MOVO X2, X7
+ PSRLL $0x07, X7
+ PSLLL $0x19, X2
+ PXOR X7, X2
+
+ // Round 9 diagonal step part 3: undiagonalize.
+ PSHUFD $0x93, X2, X2
+ PSHUFD $0x4e, X3, X3
+ PSHUFD $0x39, X4, X4
+
+ // Round 10 column step.
+ MOVD 4(SP), X9
+ MOVD 28(SP), X7
+ MOVOA X7, X8
+ PUNPCKLLQ X9, X8
+ MOVD 32(SP), X7
+ MOVD 40(SP), X9
+ PUNPCKLLQ X7, X9
+ PUNPCKLQDQ X8, X9
+ MOVOU permuted_blake_consts<>+576(SB), X8
+ PXOR X9, X8
+ PADDD X8, X1
+ MOVD 20(SP), X9
+ MOVD 24(SP), X7
+ MOVOA X7, X8
+ PUNPCKLLQ X9, X8
+ MOVD 16(SP), X7
+ MOVD 8(SP), X9
+ PUNPCKLLQ X7, X9
+ PUNPCKLQDQ X8, X9
+ MOVOU permuted_blake_consts<>+592(SB), X8
+ PXOR X9, X8
+ PADDD X2, X1
+ PXOR X1, X4
+ MOVO X4, X7
+ PSRLL $0x10, X7
+ PSLLL $0x10, X4
+ PXOR X7, X4
+ PADDD X4, X3
+ PXOR X3, X2
+ MOVO X2, X7
+ PSRLL $0x0c, X7
+ PSLLL $0x14, X2
+ PXOR X7, X2
+ PADDD X8, X1
+ PADDD X2, X1
+ PXOR X1, X4
+ MOVO X4, X7
+ PSRLL $0x08, X7
+ PSLLL $0x18, X4
+ PXOR X7, X4
+ PADDD X4, X3
+ PXOR X3, X2
+ MOVO X2, X7
+ PSRLL $0x07, X7
+ PSLLL $0x19, X2
+ PXOR X7, X2
+
+ // Round 10 diagonal step part 1: diagonalize.
+ PSHUFD $0x39, X2, X2
+ PSHUFD $0x4e, X3, X3
+ PSHUFD $0x93, X4, X4
+
+ // Round 10 diagonal step part 2: column step.
+ MOVD 52(SP), X9
+ MOVD 12(SP), X7
+ MOVOA X7, X8
+ PUNPCKLLQ X9, X8
+ MOVD 36(SP), X7
+ MOVD 60(SP), X9
+ PUNPCKLLQ X7, X9
+ PUNPCKLQDQ X8, X9
+ MOVOU permuted_blake_consts<>+608(SB), X8
+ PXOR X9, X8
+ PADDD X8, X1
+ MOVD (SP), X9
+ MOVD 48(SP), X7
+ MOVOA X7, X8
+ PUNPCKLLQ X9, X8
+ MOVD 56(SP), X7
+ MOVD 44(SP), X9
+ PUNPCKLLQ X7, X9
+ PUNPCKLQDQ X8, X9
+ MOVOU permuted_blake_consts<>+624(SB), X8
+ PXOR X9, X8
+ PADDD X2, X1
+ PXOR X1, X4
+ MOVO X4, X7
+ PSRLL $0x10, X7
+ PSLLL $0x10, X4
+ PXOR X7, X4
+ PADDD X4, X3
+ PXOR X3, X2
+ MOVO X2, X7
+ PSRLL $0x0c, X7
+ PSLLL $0x14, X2
+ PXOR X7, X2
+ PADDD X8, X1
+ PADDD X2, X1
+ PXOR X1, X4
+ MOVO X4, X7
+ PSRLL $0x08, X7
+ PSLLL $0x18, X4
+ PXOR X7, X4
+ PADDD X4, X3
+ PXOR X3, X2
+ MOVO X2, X7
+ PSRLL $0x07, X7
+ PSLLL $0x19, X2
+ PXOR X7, X2
+
+ // Round 10 diagonal step part 3: undiagonalize.
+ PSHUFD $0x93, X2, X2
+ PSHUFD $0x4e, X3, X3
+ PSHUFD $0x39, X4, X4
+
+ // Round 11 column step.
+ MOVD 24(SP), X9
+ MOVD 16(SP), X7
+ MOVOA X7, X8
+ PUNPCKLLQ X9, X8
+ MOVD 8(SP), X7
+ MOVD (SP), X9
+ PUNPCKLLQ X7, X9
+ PUNPCKLQDQ X8, X9
+ MOVOU permuted_blake_consts<>+0(SB), X8
+ PXOR X9, X8
+ PADDD X8, X1
+ MOVD 28(SP), X9
+ MOVD 20(SP), X7
+ MOVOA X7, X8
+ PUNPCKLLQ X9, X8
+ MOVD 12(SP), X7
+ MOVD 4(SP), X9
+ PUNPCKLLQ X7, X9
+ PUNPCKLQDQ X8, X9
+ MOVOU permuted_blake_consts<>+16(SB), X8
+ PXOR X9, X8
+ PADDD X2, X1
+ PXOR X1, X4
+ MOVO X4, X7
+ PSRLL $0x10, X7
+ PSLLL $0x10, X4
+ PXOR X7, X4
+ PADDD X4, X3
+ PXOR X3, X2
+ MOVO X2, X7
+ PSRLL $0x0c, X7
+ PSLLL $0x14, X2
+ PXOR X7, X2
+ PADDD X8, X1
+ PADDD X2, X1
+ PXOR X1, X4
+ MOVO X4, X7
+ PSRLL $0x08, X7
+ PSLLL $0x18, X4
+ PXOR X7, X4
+ PADDD X4, X3
+ PXOR X3, X2
+ MOVO X2, X7
+ PSRLL $0x07, X7
+ PSLLL $0x19, X2
+ PXOR X7, X2
+
+ // Round 11 diagonal step part 1: diagonalize.
+ PSHUFD $0x39, X2, X2
+ PSHUFD $0x4e, X3, X3
+ PSHUFD $0x93, X4, X4
+
+ // Round 11 diagonal step part 2: column step.
+ MOVD 56(SP), X9
+ MOVD 48(SP), X7
+ MOVOA X7, X8
+ PUNPCKLLQ X9, X8
+ MOVD 40(SP), X7
+ MOVD 32(SP), X9
+ PUNPCKLLQ X7, X9
+ PUNPCKLQDQ X8, X9
+ MOVOU permuted_blake_consts<>+32(SB), X8
+ PXOR X9, X8
+ PADDD X8, X1
+ MOVD 60(SP), X9
+ MOVD 52(SP), X7
+ MOVOA X7, X8
+ PUNPCKLLQ X9, X8
+ MOVD 44(SP), X7
+ MOVD 36(SP), X9
+ PUNPCKLLQ X7, X9
+ PUNPCKLQDQ X8, X9
+ MOVOU permuted_blake_consts<>+48(SB), X8
+ PXOR X9, X8
+ PADDD X2, X1
+ PXOR X1, X4
+ MOVO X4, X7
+ PSRLL $0x10, X7
+ PSLLL $0x10, X4
+ PXOR X7, X4
+ PADDD X4, X3
+ PXOR X3, X2
+ MOVO X2, X7
+ PSRLL $0x0c, X7
+ PSLLL $0x14, X2
+ PXOR X7, X2
+ PADDD X8, X1
+ PADDD X2, X1
+ PXOR X1, X4
+ MOVO X4, X7
+ PSRLL $0x08, X7
+ PSLLL $0x18, X4
+ PXOR X7, X4
+ PADDD X4, X3
+ PXOR X3, X2
+ MOVO X2, X7
+ PSRLL $0x07, X7
+ PSLLL $0x19, X2
+ PXOR X7, X2
+
+ // Round 11 diagonal step part 3: undiagonalize.
+ PSHUFD $0x93, X2, X2
+ PSHUFD $0x4e, X3, X3
+ PSHUFD $0x39, X4, X4
+
+ // Round 12 column step.
+ MOVD 52(SP), X9
+ MOVD 36(SP), X7
+ MOVOA X7, X8
+ PUNPCKLLQ X9, X8
+ MOVD 16(SP), X7
+ MOVD 56(SP), X9
+ PUNPCKLLQ X7, X9
+ PUNPCKLQDQ X8, X9
+ MOVOU permuted_blake_consts<>+64(SB), X8
+ PXOR X9, X8
+ PADDD X8, X1
+ MOVD 24(SP), X9
+ MOVD 60(SP), X7
+ MOVOA X7, X8
+ PUNPCKLLQ X9, X8
+ MOVD 32(SP), X7
+ MOVD 40(SP), X9
+ PUNPCKLLQ X7, X9
+ PUNPCKLQDQ X8, X9
+ MOVOU permuted_blake_consts<>+80(SB), X8
+ PXOR X9, X8
+ PADDD X2, X1
+ PXOR X1, X4
+ MOVO X4, X7
+ PSRLL $0x10, X7
+ PSLLL $0x10, X4
+ PXOR X7, X4
+ PADDD X4, X3
+ PXOR X3, X2
+ MOVO X2, X7
+ PSRLL $0x0c, X7
+ PSLLL $0x14, X2
+ PXOR X7, X2
+ PADDD X8, X1
+ PADDD X2, X1
+ PXOR X1, X4
+ MOVO X4, X7
+ PSRLL $0x08, X7
+ PSLLL $0x18, X4
+ PXOR X7, X4
+ PADDD X4, X3
+ PXOR X3, X2
+ MOVO X2, X7
+ PSRLL $0x07, X7
+ PSLLL $0x19, X2
+ PXOR X7, X2
+
+ // Round 12 diagonal step part 1: diagonalize.
+ PSHUFD $0x39, X2, X2
+ PSHUFD $0x4e, X3, X3
+ PSHUFD $0x93, X4, X4
+
+ // Round 12 diagonal step part 2: column step.
+ MOVD 20(SP), X9
+ MOVD 44(SP), X7
+ MOVOA X7, X8
+ PUNPCKLLQ X9, X8
+ MOVD (SP), X7
+ MOVD 4(SP), X9
+ PUNPCKLLQ X7, X9
+ PUNPCKLQDQ X8, X9
+ MOVOU permuted_blake_consts<>+96(SB), X8
+ PXOR X9, X8
+ PADDD X8, X1
+ MOVD 12(SP), X9
+ MOVD 28(SP), X7
+ MOVOA X7, X8
+ PUNPCKLLQ X9, X8
+ MOVD 8(SP), X7
+ MOVD 48(SP), X9
+ PUNPCKLLQ X7, X9
+ PUNPCKLQDQ X8, X9
+ MOVOU permuted_blake_consts<>+112(SB), X8
+ PXOR X9, X8
+ PADDD X2, X1
+ PXOR X1, X4
+ MOVO X4, X7
+ PSRLL $0x10, X7
+ PSLLL $0x10, X4
+ PXOR X7, X4
+ PADDD X4, X3
+ PXOR X3, X2
+ MOVO X2, X7
+ PSRLL $0x0c, X7
+ PSLLL $0x14, X2
+ PXOR X7, X2
+ PADDD X8, X1
+ PADDD X2, X1
+ PXOR X1, X4
+ MOVO X4, X7
+ PSRLL $0x08, X7
+ PSLLL $0x18, X4
+ PXOR X7, X4
+ PADDD X4, X3
+ PXOR X3, X2
+ MOVO X2, X7
+ PSRLL $0x07, X7
+ PSLLL $0x19, X2
+ PXOR X7, X2
+
+ // Round 12 diagonal step part 3: undiagonalize.
+ PSHUFD $0x93, X2, X2
+ PSHUFD $0x4e, X3, X3
+ PSHUFD $0x39, X4, X4
+
+ // Round 13 column step.
+ MOVD 60(SP), X9
+ MOVD 20(SP), X7
+ MOVOA X7, X8
+ PUNPCKLLQ X9, X8
+ MOVD 48(SP), X7
+ MOVD 44(SP), X9
+ PUNPCKLLQ X7, X9
+ PUNPCKLQDQ X8, X9
+ MOVOU permuted_blake_consts<>+128(SB), X8
+ PXOR X9, X8
+ PADDD X8, X1
+ MOVD 52(SP), X9
+ MOVD 8(SP), X7
+ MOVOA X7, X8
+ PUNPCKLLQ X9, X8
+ MOVD (SP), X7
+ MOVD 32(SP), X9
+ PUNPCKLLQ X7, X9
+ PUNPCKLQDQ X8, X9
+ MOVOU permuted_blake_consts<>+144(SB), X8
+ PXOR X9, X8
+ PADDD X2, X1
+ PXOR X1, X4
+ MOVO X4, X7
+ PSRLL $0x10, X7
+ PSLLL $0x10, X4
+ PXOR X7, X4
+ PADDD X4, X3
+ PXOR X3, X2
+ MOVO X2, X7
+ PSRLL $0x0c, X7
+ PSLLL $0x14, X2
+ PXOR X7, X2
+ PADDD X8, X1
+ PADDD X2, X1
+ PXOR X1, X4
+ MOVO X4, X7
+ PSRLL $0x08, X7
+ PSLLL $0x18, X4
+ PXOR X7, X4
+ PADDD X4, X3
+ PXOR X3, X2
+ MOVO X2, X7
+ PSRLL $0x07, X7
+ PSLLL $0x19, X2
+ PXOR X7, X2
+
+ // Round 13 diagonal step part 1: diagonalize.
+ PSHUFD $0x39, X2, X2
+ PSHUFD $0x4e, X3, X3
+ PSHUFD $0x93, X4, X4
+
+ // Round 13 diagonal step part 2: column step.
+ MOVD 36(SP), X9
+ MOVD 28(SP), X7
+ MOVOA X7, X8
+ PUNPCKLLQ X9, X8
+ MOVD 12(SP), X7
+ MOVD 40(SP), X9
+ PUNPCKLLQ X7, X9
+ PUNPCKLQDQ X8, X9
+ MOVOU permuted_blake_consts<>+160(SB), X8
+ PXOR X9, X8
+ PADDD X8, X1
+ MOVD 16(SP), X9
+ MOVD 4(SP), X7
+ MOVOA X7, X8
+ PUNPCKLLQ X9, X8
+ MOVD 24(SP), X7
+ MOVD 56(SP), X9
+ PUNPCKLLQ X7, X9
+ PUNPCKLQDQ X8, X9
+ MOVOU permuted_blake_consts<>+176(SB), X8
+ PXOR X9, X8
+ PADDD X2, X1
+ PXOR X1, X4
+ MOVO X4, X7
+ PSRLL $0x10, X7
+ PSLLL $0x10, X4
+ PXOR X7, X4
+ PADDD X4, X3
+ PXOR X3, X2
+ MOVO X2, X7
+ PSRLL $0x0c, X7
+ PSLLL $0x14, X2
+ PXOR X7, X2
+ PADDD X8, X1
+ PADDD X2, X1
+ PXOR X1, X4
+ MOVO X4, X7
+ PSRLL $0x08, X7
+ PSLLL $0x18, X4
+ PXOR X7, X4
+ PADDD X4, X3
+ PXOR X3, X2
+ MOVO X2, X7
+ PSRLL $0x07, X7
+ PSLLL $0x19, X2
+ PXOR X7, X2
+
+ // Round 13 diagonal step part 3: undiagonalize.
+ PSHUFD $0x93, X2, X2
+ PSHUFD $0x4e, X3, X3
+ PSHUFD $0x39, X4, X4
+
+ // Round 14 column step.
+ MOVD 44(SP), X9
+ MOVD 52(SP), X7
+ MOVOA X7, X8
+ PUNPCKLLQ X9, X8
+ MOVD 12(SP), X7
+ MOVD 28(SP), X9
+ PUNPCKLLQ X7, X9
+ PUNPCKLQDQ X8, X9
+ MOVOU permuted_blake_consts<>+192(SB), X8
+ PXOR X9, X8
+ PADDD X8, X1
+ MOVD 56(SP), X9
+ MOVD 48(SP), X7
+ MOVOA X7, X8
+ PUNPCKLLQ X9, X8
+ MOVD 4(SP), X7
+ MOVD 36(SP), X9
+ PUNPCKLLQ X7, X9
+ PUNPCKLQDQ X8, X9
+ MOVOU permuted_blake_consts<>+208(SB), X8
+ PXOR X9, X8
+ PADDD X2, X1
+ PXOR X1, X4
+ MOVO X4, X7
+ PSRLL $0x10, X7
+ PSLLL $0x10, X4
+ PXOR X7, X4
+ PADDD X4, X3
+ PXOR X3, X2
+ MOVO X2, X7
+ PSRLL $0x0c, X7
+ PSLLL $0x14, X2
+ PXOR X7, X2
+ PADDD X8, X1
+ PADDD X2, X1
+ PXOR X1, X4
+ MOVO X4, X7
+ PSRLL $0x08, X7
+ PSLLL $0x18, X4
+ PXOR X7, X4
+ PADDD X4, X3
+ PXOR X3, X2
+ MOVO X2, X7
+ PSRLL $0x07, X7
+ PSLLL $0x19, X2
+ PXOR X7, X2
+
+ // Round 14 diagonal step part 1: diagonalize.
+ PSHUFD $0x39, X2, X2
+ PSHUFD $0x4e, X3, X3
+ PSHUFD $0x93, X4, X4
+
+ // Round 14 diagonal step part 2: column step.
+ MOVD 60(SP), X9
+ MOVD 16(SP), X7
+ MOVOA X7, X8
+ PUNPCKLLQ X9, X8
+ MOVD 20(SP), X7
+ MOVD 8(SP), X9
+ PUNPCKLLQ X7, X9
+ PUNPCKLQDQ X8, X9
+ MOVOU permuted_blake_consts<>+224(SB), X8
+ PXOR X9, X8
+ PADDD X8, X1
+ MOVD 32(SP), X9
+ MOVD (SP), X7
+ MOVOA X7, X8
+ PUNPCKLLQ X9, X8
+ MOVD 40(SP), X7
+ MOVD 24(SP), X9
+ PUNPCKLLQ X7, X9
+ PUNPCKLQDQ X8, X9
+ MOVOU permuted_blake_consts<>+240(SB), X8
+ PXOR X9, X8
+ PADDD X2, X1
+ PXOR X1, X4
+ MOVO X4, X7
+ PSRLL $0x10, X7
+ PSLLL $0x10, X4
+ PXOR X7, X4
+ PADDD X4, X3
+ PXOR X3, X2
+ MOVO X2, X7
+ PSRLL $0x0c, X7
+ PSLLL $0x14, X2
+ PXOR X7, X2
+ PADDD X8, X1
+ PADDD X2, X1
+ PXOR X1, X4
+ MOVO X4, X7
+ PSRLL $0x08, X7
+ PSLLL $0x18, X4
+ PXOR X7, X4
+ PADDD X4, X3
+ PXOR X3, X2
+ MOVO X2, X7
+ PSRLL $0x07, X7
+ PSLLL $0x19, X2
+ PXOR X7, X2
+
+ // Round 14 diagonal step part 3: undiagonalize.
+ PSHUFD $0x93, X2, X2
+ PSHUFD $0x4e, X3, X3
+ PSHUFD $0x39, X4, X4
+
+ // Finally the chain value is defined as:
+ // h'0 = h0^s0^v0^v8
+ // h'1 = h1^s1^v1^v9
+ // h'2 = h2^s2^v2^va
+ // h'3 = h3^s3^v3^vb
+ // h'4 = h4^s0^v4^vc
+ // h'5 = h5^s1^v5^vd
+ // h'6 = h6^s2^v6^ve
+ // h'7 = h7^s3^v7^vf
+ PXOR X5, X1
+ PXOR X0, X1
+ PXOR X3, X1
+ PXOR X6, X2
+ PXOR X0, X2
+ PXOR X4, X2
+
+ // Either terminate the loop when there are no more full blocks
+ // to compress or move the message pointer to the next block of
+ // bytes to compress, increment the message bits counter
+ // accordingly, and loop back around to compress it.
+ DECQ BX
+ JZ done
+ LEAQ 64(DX), DX
+ ADDQ $0x00000200, CX
+ JMP compressLoop
+
+done:
+ // Output the resulting chain value.
+ MOVOU X1, (AX)
+ MOVOU X2, 16(AX)
+ RET
+
+// func blocksSSE41(state *State, msg []byte, counter uint64)
+// Requires: SSE2, SSE4.1, SSSE3
+TEXT ·blocksSSE41(SB), NOSPLIT, $0-40
+ MOVQ state+0(FP), AX
+ MOVQ counter+32(FP), CX
+ MOVQ msg_base+8(FP), DX
+ MOVQ msg_len+16(FP), BX
+
+ // Populate registers for faster right rotations.
+ MOVOU shuffle_rotr8_4x32<>+0(SB), X4
+ MOVOU shuffle_rotr16_4x32<>+0(SB), X5
+
+ // Convert message len to number of blocks for loop counter.
+ SHRQ $0x06, BX
+
+ // Initialize state matrix.
+ // row0 = |v0 v1 v2 v3| | h0 h1 h2 h3 |
+ // row1 = |v4 v5 v6 v7| | h4 h5 h6 h7 |
+ MOVOU 32(AX), X6
+ MOVOU (AX), X7
+ MOVOU 16(AX), X8
+
+compressLoop:
+ // row2 = |v8 v9 va vb| = |s0^c0 s1^c1 s2^c2 s3^c3|
+ // row3 = |vc vd ve vf| |t0^c4 t0^c5 t1^c6 t1^c7|
+ MOVOU first_8_blake_consts<>+0(SB), X9
+ PXOR X6, X9
+ MOVD CX, X10
+ PSHUFD $0x50, X10, X10
+ PXOR first_8_blake_consts<>+16(SB), X10
+ MOVO X7, X11
+ MOVO X8, X12
+
+ // Convert message to big endian.
+ MOVOU shuffle_le_to_be_4x32<>+0(SB), X13
+ MOVOU (DX), X0
+ PSHUFB X13, X0
+ MOVOU 16(DX), X1
+ PSHUFB X13, X1
+ MOVOU 32(DX), X2
+ PSHUFB X13, X2
+ MOVOU 48(DX), X3
+ PSHUFB X13, X3
+
+ // Round 1 column step.
+ PSHUFD $0x08, X0, X14
+ PSHUFD $0x80, X1, X13
+ PBLENDW $0xf0, X13, X14
+ MOVOU permuted_blake_consts<>+0(SB), X15
+ PXOR X14, X15
+ PADDD X15, X7
+ PSHUFD $0x0d, X0, X14
+ PSHUFD $0xd0, X1, X13
+ PBLENDW $0xf0, X13, X14
+ MOVOU permuted_blake_consts<>+16(SB), X15
+ PXOR X14, X15
+ PADDD X8, X7
+ PXOR X7, X10
+ PSHUFB X5, X10
+ PADDD X10, X9
+ PXOR X9, X8
+ MOVO X8, X13
+ PSRLL $0x0c, X13
+ PSLLL $0x14, X8
+ PXOR X13, X8
+ PADDD X15, X7
+ PADDD X8, X7
+ PXOR X7, X10
+ PSHUFB X4, X10
+ PADDD X10, X9
+ PXOR X9, X8
+ MOVO X8, X13
+ PSRLL $0x07, X13
+ PSLLL $0x19, X8
+ PXOR X13, X8
+
+ // Round 1 diagonal step part 1: diagonalize.
+ PSHUFD $0x39, X8, X8
+ PSHUFD $0x4e, X9, X9
+ PSHUFD $0x93, X10, X10
+
+ // Round 1 diagonal step part 2: column step.
+ PSHUFD $0x08, X2, X14
+ PSHUFD $0x80, X3, X13
+ PBLENDW $0xf0, X13, X14
+ MOVOU permuted_blake_consts<>+32(SB), X15
+ PXOR X14, X15
+ PADDD X15, X7
+ PSHUFD $0x0d, X2, X14
+ PSHUFD $0xd0, X3, X13
+ PBLENDW $0xf0, X13, X14
+ MOVOU permuted_blake_consts<>+48(SB), X15
+ PXOR X14, X15
+ PADDD X8, X7
+ PXOR X7, X10
+ PSHUFB X5, X10
+ PADDD X10, X9
+ PXOR X9, X8
+ MOVO X8, X13
+ PSRLL $0x0c, X13
+ PSLLL $0x14, X8
+ PXOR X13, X8
+ PADDD X15, X7
+ PADDD X8, X7
+ PXOR X7, X10
+ PSHUFB X4, X10
+ PADDD X10, X9
+ PXOR X9, X8
+ MOVO X8, X13
+ PSRLL $0x07, X13
+ PSLLL $0x19, X8
+ PXOR X13, X8
+
+ // Round 1 diagonal step part 3: undiagonalize.
+ PSHUFD $0x93, X8, X8
+ PSHUFD $0x4e, X9, X9
+ PSHUFD $0x39, X10, X10
+
+ // Round 2 column step.
+ PSHUFD $0x00, X1, X14
+ PSHUFD $0x10, X2, X13
+ PBLENDW $0x30, X13, X14
+ PSHUFD $0x42, X3, X13
+ PBLENDW $0xc3, X13, X14
+ MOVOU permuted_blake_consts<>+64(SB), X15
+ PXOR X14, X15
+ PADDD X15, X7
+ PSHUFD $0x80, X1, X14
+ PSHUFD $0x02, X2, X13
+ PBLENDW $0x0f, X13, X14
+ PSHUFD $0x30, X3, X13
+ PBLENDW $0x30, X13, X14
+ MOVOU permuted_blake_consts<>+80(SB), X15
+ PXOR X14, X15
+ PADDD X8, X7
+ PXOR X7, X10
+ PSHUFB X5, X10
+ PADDD X10, X9
+ PXOR X9, X8
+ MOVO X8, X13
+ PSRLL $0x0c, X13
+ PSLLL $0x14, X8
+ PXOR X13, X8
+ PADDD X15, X7
+ PADDD X8, X7
+ PXOR X7, X10
+ PSHUFB X4, X10
+ PADDD X10, X9
+ PXOR X9, X8
+ MOVO X8, X13
+ PSRLL $0x07, X13
+ PSLLL $0x19, X8
+ PXOR X13, X8
+
+ // Round 2 diagonal step part 1: diagonalize.
+ PSHUFD $0x39, X8, X8
+ PSHUFD $0x4e, X9, X9
+ PSHUFD $0x93, X10, X10
+
+ // Round 2 diagonal step part 2: column step.
+ PSHUFD $0x01, X0, X14
+ PSHUFD $0x40, X1, X13
+ PBLENDW $0xc0, X13, X14
+ PSHUFD $0x30, X2, X13
+ PBLENDW $0x30, X13, X14
+ MOVOU permuted_blake_consts<>+96(SB), X15
+ PXOR X14, X15
+ PADDD X15, X7
+ PSHUFD $0xc8, X0, X14
+ PSHUFD $0x30, X1, X13
+ PBLENDW $0x30, X13, X14
+ PSHUFD $0x00, X3, X13
+ PBLENDW $0x03, X13, X14
+ MOVOU permuted_blake_consts<>+112(SB), X15
+ PXOR X14, X15
+ PADDD X8, X7
+ PXOR X7, X10
+ PSHUFB X5, X10
+ PADDD X10, X9
+ PXOR X9, X8
+ MOVO X8, X13
+ PSRLL $0x0c, X13
+ PSLLL $0x14, X8
+ PXOR X13, X8
+ PADDD X15, X7
+ PADDD X8, X7
+ PXOR X7, X10
+ PSHUFB X4, X10
+ PADDD X10, X9
+ PXOR X9, X8
+ MOVO X8, X13
+ PSRLL $0x07, X13
+ PSLLL $0x19, X8
+ PXOR X13, X8
+
+ // Round 2 diagonal step part 3: undiagonalize.
+ PSHUFD $0x93, X8, X8
+ PSHUFD $0x4e, X9, X9
+ PSHUFD $0x39, X10, X10
+
+ // Round 3 column step.
+ PSHUFD $0x10, X1, X14
+ PSHUFD $0x03, X2, X13
+ PBLENDW $0x03, X13, X14
+ PSHUFD $0xc0, X3, X13
+ PBLENDW $0xcc, X13, X14
+ MOVOU permuted_blake_consts<>+128(SB), X15
+ PXOR X14, X15
+ PADDD X15, X7
+ PSHUFD $0x20, X0, X14
+ PSHUFD $0x00, X2, X13
+ PBLENDW $0x03, X13, X14
+ PSHUFD $0x40, X3, X13
+ PBLENDW $0xc0, X13, X14
+ MOVOU permuted_blake_consts<>+144(SB), X15
+ PXOR X14, X15
+ PADDD X8, X7
+ PXOR X7, X10
+ PSHUFB X5, X10
+ PADDD X10, X9
+ PXOR X9, X8
+ MOVO X8, X13
+ PSRLL $0x0c, X13
+ PSLLL $0x14, X8
+ PXOR X13, X8
+ PADDD X15, X7
+ PADDD X8, X7
+ PXOR X7, X10
+ PSHUFB X4, X10
+ PADDD X10, X9
+ PXOR X9, X8
+ MOVO X8, X13
+ PSRLL $0x07, X13
+ PSLLL $0x19, X8
+ PXOR X13, X8
+
+ // Round 3 diagonal step part 1: diagonalize.
+ PSHUFD $0x39, X8, X8
+ PSHUFD $0x4e, X9, X9
+ PSHUFD $0x93, X10, X10
+
+ // Round 3 diagonal step part 2: column step.
+ PSHUFD $0x0c, X0, X14
+ PSHUFD $0x30, X1, X13
+ PBLENDW $0x30, X13, X14
+ PSHUFD $0x42, X2, X13
+ PBLENDW $0xc3, X13, X14
+ MOVOU permuted_blake_consts<>+160(SB), X15
+ PXOR X14, X15
+ PADDD X15, X7
+ PSHUFD $0x10, X0, X14
+ PSHUFD $0x08, X1, X13
+ PBLENDW $0xcc, X13, X14
+ PSHUFD $0x02, X3, X13
+ PBLENDW $0x03, X13, X14
+ MOVOU permuted_blake_consts<>+176(SB), X15
+ PXOR X14, X15
+ PADDD X8, X7
+ PXOR X7, X10
+ PSHUFB X5, X10
+ PADDD X10, X9
+ PXOR X9, X8
+ MOVO X8, X13
+ PSRLL $0x0c, X13
+ PSLLL $0x14, X8
+ PXOR X13, X8
+ PADDD X15, X7
+ PADDD X8, X7
+ PXOR X7, X10
+ PSHUFB X4, X10
+ PADDD X10, X9
+ PXOR X9, X8
+ MOVO X8, X13
+ PSRLL $0x07, X13
+ PSLLL $0x19, X8
+ PXOR X13, X8
+
+ // Round 3 diagonal step part 3: undiagonalize.
+ PSHUFD $0x93, X8, X8
+ PSHUFD $0x4e, X9, X9
+ PSHUFD $0x39, X10, X10
+
+ // Round 4 column step.
+ PSHUFD $0x0c, X0, X14
+ PSHUFD $0x03, X1, X13
+ PBLENDW $0x03, X13, X14
+ PSHUFD $0xc0, X2, X13
+ PBLENDW $0xc0, X13, X14
+ PSHUFD $0x10, X3, X13
+ PBLENDW $0x30, X13, X14
+ MOVOU permuted_blake_consts<>+192(SB), X15
+ PXOR X14, X15
+ PADDD X15, X7
+ PSHUFD $0x04, X0, X14
+ PSHUFD $0x01, X2, X13
+ PBLENDW $0x03, X13, X14
+ PSHUFD $0x80, X3, X13
+ PBLENDW $0xf0, X13, X14
+ MOVOU permuted_blake_consts<>+208(SB), X15
+ PXOR X14, X15
+ PADDD X8, X7
+ PXOR X7, X10
+ PSHUFB X5, X10
+ PADDD X10, X9
+ PXOR X9, X8
+ MOVO X8, X13
+ PSRLL $0x0c, X13
+ PSLLL $0x14, X8
+ PXOR X13, X8
+ PADDD X15, X7
+ PADDD X8, X7
+ PXOR X7, X10
+ PSHUFB X4, X10
+ PADDD X10, X9
+ PXOR X9, X8
+ MOVO X8, X13
+ PSRLL $0x07, X13
+ PSLLL $0x19, X8
+ PXOR X13, X8
+
+ // Round 4 diagonal step part 1: diagonalize.
+ PSHUFD $0x39, X8, X8
+ PSHUFD $0x4e, X9, X9
+ PSHUFD $0x93, X10, X10
+
+ // Round 4 diagonal step part 2: column step.
+ PSHUFD $0x02, X0, X14
+ PSHUFD $0x04, X1, X13
+ PBLENDW $0x3c, X13, X14
+ PSHUFD $0xc0, X3, X13
+ PBLENDW $0xc0, X13, X14
+ MOVOU permuted_blake_consts<>+224(SB), X15
+ PXOR X14, X15
+ PADDD X15, X7
+ PSHUFD $0x00, X0, X14
+ PSHUFD $0x02, X1, X13
+ PBLENDW $0x03, X13, X14
+ PSHUFD $0x08, X2, X13
+ PBLENDW $0xcc, X13, X14
+ MOVOU permuted_blake_consts<>+240(SB), X15
+ PXOR X14, X15
+ PADDD X8, X7
+ PXOR X7, X10
+ PSHUFB X5, X10
+ PADDD X10, X9
+ PXOR X9, X8
+ MOVO X8, X13
+ PSRLL $0x0c, X13
+ PSLLL $0x14, X8
+ PXOR X13, X8
+ PADDD X15, X7
+ PADDD X8, X7
+ PXOR X7, X10
+ PSHUFB X4, X10
+ PADDD X10, X9
+ PXOR X9, X8
+ MOVO X8, X13
+ PSRLL $0x07, X13
+ PSLLL $0x19, X8
+ PXOR X13, X8
+
+ // Round 4 diagonal step part 3: undiagonalize.
+ PSHUFD $0x93, X8, X8
+ PSHUFD $0x4e, X9, X9
+ PSHUFD $0x39, X10, X10
+
+ // Round 5 column step.
+ PSHUFD $0x20, X0, X14
+ PSHUFD $0x04, X1, X13
+ PBLENDW $0x0c, X13, X14
+ PSHUFD $0x81, X2, X13
+ PBLENDW $0xc3, X13, X14
+ MOVOU permuted_blake_consts<>+256(SB), X15
+ PXOR X14, X15
+ PADDD X15, X7
+ PSHUFD $0x00, X0, X14
+ PSHUFD $0x0c, X1, X13
+ PBLENDW $0x3c, X13, X14
+ PSHUFD $0xc0, X3, X13
+ PBLENDW $0xc0, X13, X14
+ MOVOU permuted_blake_consts<>+272(SB), X15
+ PXOR X14, X15
+ PADDD X8, X7
+ PXOR X7, X10
+ PSHUFB X5, X10
+ PADDD X10, X9
+ PXOR X9, X8
+ MOVO X8, X13
+ PSRLL $0x0c, X13
+ PSLLL $0x14, X8
+ PXOR X13, X8
+ PADDD X15, X7
+ PADDD X8, X7
+ PXOR X7, X10
+ PSHUFB X4, X10
+ PADDD X10, X9
+ PXOR X9, X8
+ MOVO X8, X13
+ PSRLL $0x07, X13
+ PSLLL $0x19, X8
+ PXOR X13, X8
+
+ // Round 5 diagonal step part 1: diagonalize.
+ PSHUFD $0x39, X8, X8
+ PSHUFD $0x4e, X9, X9
+ PSHUFD $0x93, X10, X10
+
+ // Round 5 diagonal step part 2: column step.
+ PSHUFD $0xc0, X0, X14
+ PSHUFD $0x20, X1, X13
+ PBLENDW $0x30, X13, X14
+ PSHUFD $0x0c, X2, X13
+ PBLENDW $0x0c, X13, X14
+ PSHUFD $0x02, X3, X13
+ PBLENDW $0x03, X13, X14
+ MOVOU permuted_blake_consts<>+288(SB), X15
+ PXOR X14, X15
+ PADDD X15, X7
+ PSHUFD $0x01, X0, X14
+ PSHUFD $0x00, X2, X13
+ PBLENDW $0x30, X13, X14
+ PSHUFD $0x40, X3, X13
+ PBLENDW $0xcc, X13, X14
+ MOVOU permuted_blake_consts<>+304(SB), X15
+ PXOR X14, X15
+ PADDD X8, X7
+ PXOR X7, X10
+ PSHUFB X5, X10
+ PADDD X10, X9
+ PXOR X9, X8
+ MOVO X8, X13
+ PSRLL $0x0c, X13
+ PSLLL $0x14, X8
+ PXOR X13, X8
+ PADDD X15, X7
+ PADDD X8, X7
+ PXOR X7, X10
+ PSHUFB X4, X10
+ PADDD X10, X9
+ PXOR X9, X8
+ MOVO X8, X13
+ PSRLL $0x07, X13
+ PSLLL $0x19, X8
+ PXOR X13, X8
+
+ // Round 5 diagonal step part 3: undiagonalize.
+ PSHUFD $0x93, X8, X8
+ PSHUFD $0x4e, X9, X9
+ PSHUFD $0x39, X10, X10
+
+ // Round 6 column step.
+ PSHUFD $0x02, X0, X14
+ PSHUFD $0x08, X1, X13
+ PBLENDW $0x0c, X13, X14
+ PSHUFD $0x00, X2, X13
+ PBLENDW $0xc0, X13, X14
+ MOVOU permuted_blake_consts<>+320(SB), X15
+ PXOR X14, X15
+ PADDD X15, X7
+ PSHUFD $0xc0, X0, X14
+ PSHUFD $0x38, X2, X13
+ PBLENDW $0x3c, X13, X14
+ PSHUFD $0x00, X3, X13
+ PBLENDW $0x03, X13, X14
+ MOVOU permuted_blake_consts<>+336(SB), X15
+ PXOR X14, X15
+ PADDD X8, X7
+ PXOR X7, X10
+ PSHUFB X5, X10
+ PADDD X10, X9
+ PXOR X9, X8
+ MOVO X8, X13
+ PSRLL $0x0c, X13
+ PSLLL $0x14, X8
+ PXOR X13, X8
+ PADDD X15, X7
+ PADDD X8, X7
+ PXOR X7, X10
+ PSHUFB X4, X10
+ PADDD X10, X9
+ PXOR X9, X8
+ MOVO X8, X13
+ PSRLL $0x07, X13
+ PSLLL $0x19, X8
+ PXOR X13, X8
+
+ // Round 6 diagonal step part 1: diagonalize.
+ PSHUFD $0x39, X8, X8
+ PSHUFD $0x4e, X9, X9
+ PSHUFD $0x93, X10, X10
+
+ // Round 6 diagonal step part 2: column step.
+ PSHUFD $0x40, X0, X14
+ PSHUFD $0x0c, X1, X13
+ PBLENDW $0x0f, X13, X14
+ PSHUFD $0x30, X3, X13
+ PBLENDW $0x30, X13, X14
+ MOVOU permuted_blake_consts<>+352(SB), X15
+ PXOR X14, X15
+ PADDD X15, X7
+ PSHUFD $0x04, X1, X14
+ PSHUFD $0x40, X2, X13
+ PBLENDW $0xc0, X13, X14
+ PSHUFD $0x21, X3, X13
+ PBLENDW $0x33, X13, X14
+ MOVOU permuted_blake_consts<>+368(SB), X15
+ PXOR X14, X15
+ PADDD X8, X7
+ PXOR X7, X10
+ PSHUFB X5, X10
+ PADDD X10, X9
+ PXOR X9, X8
+ MOVO X8, X13
+ PSRLL $0x0c, X13
+ PSLLL $0x14, X8
+ PXOR X13, X8
+ PADDD X15, X7
+ PADDD X8, X7
+ PXOR X7, X10
+ PSHUFB X4, X10
+ PADDD X10, X9
+ PXOR X9, X8
+ MOVO X8, X13
+ PSRLL $0x07, X13
+ PSLLL $0x19, X8
+ PXOR X13, X8
+
+ // Round 6 diagonal step part 3: undiagonalize.
+ PSHUFD $0x93, X8, X8
+ PSHUFD $0x4e, X9, X9
+ PSHUFD $0x39, X10, X10
+
+ // Round 7 column step.
+ PSHUFD $0x04, X0, X14
+ PSHUFD $0x00, X1, X13
+ PBLENDW $0xc0, X13, X14
+ PSHUFD $0x20, X3, X13
+ PBLENDW $0x33, X13, X14
+ MOVOU permuted_blake_consts<>+384(SB), X15
+ PXOR X14, X15
+ PADDD X15, X7
+ PSHUFD $0x01, X1, X14
+ PSHUFD $0x80, X2, X13
+ PBLENDW $0xc0, X13, X14
+ PSHUFD $0x1c, X3, X13
+ PBLENDW $0x3c, X13, X14
+ MOVOU permuted_blake_consts<>+400(SB), X15
+ PXOR X14, X15
+ PADDD X8, X7
+ PXOR X7, X10
+ PSHUFB X5, X10
+ PADDD X10, X9
+ PXOR X9, X8
+ MOVO X8, X13
+ PSRLL $0x0c, X13
+ PSLLL $0x14, X8
+ PXOR X13, X8
+ PADDD X15, X7
+ PADDD X8, X7
+ PXOR X7, X10
+ PSHUFB X4, X10
+ PADDD X10, X9
+ PXOR X9, X8
+ MOVO X8, X13
+ PSRLL $0x07, X13
+ PSLLL $0x19, X8
+ PXOR X13, X8
+
+ // Round 7 diagonal step part 1: diagonalize.
+ PSHUFD $0x39, X8, X8
+ PSHUFD $0x4e, X9, X9
+ PSHUFD $0x93, X10, X10
+
+ // Round 7 diagonal step part 2: column step.
+ PSHUFD $0x00, X0, X14
+ PSHUFD $0x08, X1, X13
+ PBLENDW $0x0c, X13, X14
+ PSHUFD $0x10, X2, X13
+ PBLENDW $0xf0, X13, X14
+ MOVOU permuted_blake_consts<>+416(SB), X15
+ PXOR X14, X15
+ PADDD X15, X7
+ PSHUFD $0x2c, X0, X14
+ PSHUFD $0x03, X1, X13
+ PBLENDW $0x03, X13, X14
+ PSHUFD $0xc0, X2, X13
+ PBLENDW $0xc0, X13, X14
+ MOVOU permuted_blake_consts<>+432(SB), X15
+ PXOR X14, X15
+ PADDD X8, X7
+ PXOR X7, X10
+ PSHUFB X5, X10
+ PADDD X10, X9
+ PXOR X9, X8
+ MOVO X8, X13
+ PSRLL $0x0c, X13
+ PSLLL $0x14, X8
+ PXOR X13, X8
+ PADDD X15, X7
+ PADDD X8, X7
+ PXOR X7, X10
+ PSHUFB X4, X10
+ PADDD X10, X9
+ PXOR X9, X8
+ MOVO X8, X13
+ PSRLL $0x07, X13
+ PSLLL $0x19, X8
+ PXOR X13, X8
+
+ // Round 7 diagonal step part 3: undiagonalize.
+ PSHUFD $0x93, X8, X8
+ PSHUFD $0x4e, X9, X9
+ PSHUFD $0x39, X10, X10
+
+ // Round 8 column step.
+ PSHUFD $0xc0, X0, X14
+ PSHUFD $0x0c, X1, X13
+ PBLENDW $0x0c, X13, X14
+ PSHUFD $0x01, X3, X13
+ PBLENDW $0x33, X13, X14
+ MOVOU permuted_blake_consts<>+448(SB), X15
+ PXOR X14, X15
+ PADDD X15, X7
+ PSHUFD $0x10, X0, X14
+ PSHUFD $0x43, X2, X13
+ PBLENDW $0xc3, X13, X14
+ PSHUFD $0x08, X3, X13
+ PBLENDW $0x0c, X13, X14
+ MOVOU permuted_blake_consts<>+464(SB), X15
+ PXOR X14, X15
+ PADDD X8, X7
+ PXOR X7, X10
+ PSHUFB X5, X10
+ PADDD X10, X9
+ PXOR X9, X8
+ MOVO X8, X13
+ PSRLL $0x0c, X13
+ PSLLL $0x14, X8
+ PXOR X13, X8
+ PADDD X15, X7
+ PADDD X8, X7
+ PXOR X7, X10
+ PSHUFB X4, X10
+ PADDD X10, X9
+ PXOR X9, X8
+ MOVO X8, X13
+ PSRLL $0x07, X13
+ PSLLL $0x19, X8
+ PXOR X13, X8
+
+ // Round 8 diagonal step part 1: diagonalize.
+ PSHUFD $0x39, X8, X8
+ PSHUFD $0x4e, X9, X9
+ PSHUFD $0x93, X10, X10
+
+ // Round 8 diagonal step part 2: column step.
+ PSHUFD $0x80, X0, X14
+ PSHUFD $0x01, X1, X13
+ PBLENDW $0x03, X13, X14
+ PSHUFD $0x00, X2, X13
+ PBLENDW $0x30, X13, X14
+ PSHUFD $0x0c, X3, X13
+ PBLENDW $0x0c, X13, X14
+ MOVOU permuted_blake_consts<>+480(SB), X15
+ PXOR X14, X15
+ PADDD X15, X7
+ PSHUFD $0x00, X0, X14
+ PSHUFD $0x20, X1, X13
+ PBLENDW $0x3c, X13, X14
+ PSHUFD $0x80, X2, X13
+ PBLENDW $0xc0, X13, X14
+ MOVOU permuted_blake_consts<>+496(SB), X15
+ PXOR X14, X15
+ PADDD X8, X7
+ PXOR X7, X10
+ PSHUFB X5, X10
+ PADDD X10, X9
+ PXOR X9, X8
+ MOVO X8, X13
+ PSRLL $0x0c, X13
+ PSLLL $0x14, X8
+ PXOR X13, X8
+ PADDD X15, X7
+ PADDD X8, X7
+ PXOR X7, X10
+ PSHUFB X4, X10
+ PADDD X10, X9
+ PXOR X9, X8
+ MOVO X8, X13
+ PSRLL $0x07, X13
+ PSLLL $0x19, X8
+ PXOR X13, X8
+
+ // Round 8 diagonal step part 3: undiagonalize.
+ PSHUFD $0x93, X8, X8
+ PSHUFD $0x4e, X9, X9
+ PSHUFD $0x39, X10, X10
+
+ // Round 9 column step.
+ PSHUFD $0x00, X0, X14
+ PSHUFD $0x02, X1, X13
+ PBLENDW $0x03, X13, X14
+ PSHUFD $0x30, X2, X13
+ PBLENDW $0x30, X13, X14
+ PSHUFD $0x08, X3, X13
+ PBLENDW $0x0c, X13, X14
+ MOVOU permuted_blake_consts<>+512(SB), X15
+ PXOR X14, X15
+ PADDD X15, X7
+ PSHUFD $0x30, X0, X14
+ PSHUFD $0x04, X2, X13
+ PBLENDW $0xcc, X13, X14
+ PSHUFD $0x03, X3, X13
+ PBLENDW $0x03, X13, X14
+ MOVOU permuted_blake_consts<>+528(SB), X15
+ PXOR X14, X15
+ PADDD X8, X7
+ PXOR X7, X10
+ PSHUFB X5, X10
+ PADDD X10, X9
+ PXOR X9, X8
+ MOVO X8, X13
+ PSRLL $0x0c, X13
+ PSLLL $0x14, X8
+ PXOR X13, X8
+ PADDD X15, X7
+ PADDD X8, X7
+ PXOR X7, X10
+ PSHUFB X4, X10
+ PADDD X10, X9
+ PXOR X9, X8
+ MOVO X8, X13
+ PSRLL $0x07, X13
+ PSLLL $0x19, X8
+ PXOR X13, X8
+
+ // Round 9 diagonal step part 1: diagonalize.
+ PSHUFD $0x39, X8, X8
+ PSHUFD $0x4e, X9, X9
+ PSHUFD $0x93, X10, X10
+
+ // Round 9 diagonal step part 2: column step.
+ PSHUFD $0x10, X0, X14
+ PSHUFD $0x80, X2, X13
+ PBLENDW $0xc0, X13, X14
+ PSHUFD $0x04, X3, X13
+ PBLENDW $0x0f, X13, X14
+ MOVOU permuted_blake_consts<>+544(SB), X15
+ PXOR X14, X15
+ PADDD X15, X7
+ PSHUFD $0x02, X0, X14
+ PSHUFD $0x4c, X1, X13
+ PBLENDW $0xfc, X13, X14
+ MOVOU permuted_blake_consts<>+560(SB), X15
+ PXOR X14, X15
+ PADDD X8, X7
+ PXOR X7, X10
+ PSHUFB X5, X10
+ PADDD X10, X9
+ PXOR X9, X8
+ MOVO X8, X13
+ PSRLL $0x0c, X13
+ PSLLL $0x14, X8
+ PXOR X13, X8
+ PADDD X15, X7
+ PADDD X8, X7
+ PXOR X7, X10
+ PSHUFB X4, X10
+ PADDD X10, X9
+ PXOR X9, X8
+ MOVO X8, X13
+ PSRLL $0x07, X13
+ PSLLL $0x19, X8
+ PXOR X13, X8
+
+ // Round 9 diagonal step part 3: undiagonalize.
+ PSHUFD $0x93, X8, X8
+ PSHUFD $0x4e, X9, X9
+ PSHUFD $0x39, X10, X10
+
+ // Round 10 column step.
+ PSHUFD $0x40, X0, X14
+ PSHUFD $0x30, X1, X13
+ PBLENDW $0x30, X13, X14
+ PSHUFD $0x02, X2, X13
+ PBLENDW $0x0f, X13, X14
+ MOVOU permuted_blake_consts<>+576(SB), X15
+ PXOR X14, X15
+ PADDD X15, X7
+ PSHUFD $0x02, X0, X14
+ PSHUFD $0x60, X1, X13
+ PBLENDW $0xfc, X13, X14
+ MOVOU permuted_blake_consts<>+592(SB), X15
+ PXOR X14, X15
+ PADDD X8, X7
+ PXOR X7, X10
+ PSHUFB X5, X10
+ PADDD X10, X9
+ PXOR X9, X8
+ MOVO X8, X13
+ PSRLL $0x0c, X13
+ PSLLL $0x14, X8
+ PXOR X13, X8
+ PADDD X15, X7
+ PADDD X8, X7
+ PXOR X7, X10
+ PSHUFB X4, X10
+ PADDD X10, X9
+ PXOR X9, X8
+ MOVO X8, X13
+ PSRLL $0x07, X13
+ PSLLL $0x19, X8
+ PXOR X13, X8
+
+ // Round 10 diagonal step part 1: diagonalize.
+ PSHUFD $0x39, X8, X8
+ PSHUFD $0x4e, X9, X9
+ PSHUFD $0x93, X10, X10
+
+ // Round 10 diagonal step part 2: column step.
+ PSHUFD $0x30, X0, X14
+ PSHUFD $0x04, X2, X13
+ PBLENDW $0x0c, X13, X14
+ PSHUFD $0x43, X3, X13
+ PBLENDW $0xc3, X13, X14
+ MOVOU permuted_blake_consts<>+608(SB), X15
+ PXOR X14, X15
+ PADDD X15, X7
+ PSHUFD $0x00, X0, X14
+ PSHUFD $0x03, X2, X13
+ PBLENDW $0x03, X13, X14
+ PSHUFD $0x08, X3, X13
+ PBLENDW $0x3c, X13, X14
+ MOVOU permuted_blake_consts<>+624(SB), X15
+ PXOR X14, X15
+ PADDD X8, X7
+ PXOR X7, X10
+ PSHUFB X5, X10
+ PADDD X10, X9
+ PXOR X9, X8
+ MOVO X8, X13
+ PSRLL $0x0c, X13
+ PSLLL $0x14, X8
+ PXOR X13, X8
+ PADDD X15, X7
+ PADDD X8, X7
+ PXOR X7, X10
+ PSHUFB X4, X10
+ PADDD X10, X9
+ PXOR X9, X8
+ MOVO X8, X13
+ PSRLL $0x07, X13
+ PSLLL $0x19, X8
+ PXOR X13, X8
+
+ // Round 10 diagonal step part 3: undiagonalize.
+ PSHUFD $0x93, X8, X8
+ PSHUFD $0x4e, X9, X9
+ PSHUFD $0x39, X10, X10
+
+ // Round 11 column step.
+ PSHUFD $0x08, X0, X14
+ PSHUFD $0x80, X1, X13
+ PBLENDW $0xf0, X13, X14
+ MOVOU permuted_blake_consts<>+0(SB), X15
+ PXOR X14, X15
+ PADDD X15, X7
+ PSHUFD $0x0d, X0, X14
+ PSHUFD $0xd0, X1, X13
+ PBLENDW $0xf0, X13, X14
+ MOVOU permuted_blake_consts<>+16(SB), X15
+ PXOR X14, X15
+ PADDD X8, X7
+ PXOR X7, X10
+ PSHUFB X5, X10
+ PADDD X10, X9
+ PXOR X9, X8
+ MOVO X8, X13
+ PSRLL $0x0c, X13
+ PSLLL $0x14, X8
+ PXOR X13, X8
+ PADDD X15, X7
+ PADDD X8, X7
+ PXOR X7, X10
+ PSHUFB X4, X10
+ PADDD X10, X9
+ PXOR X9, X8
+ MOVO X8, X13
+ PSRLL $0x07, X13
+ PSLLL $0x19, X8
+ PXOR X13, X8
+
+ // Round 11 diagonal step part 1: diagonalize.
+ PSHUFD $0x39, X8, X8
+ PSHUFD $0x4e, X9, X9
+ PSHUFD $0x93, X10, X10
+
+ // Round 11 diagonal step part 2: column step.
+ PSHUFD $0x08, X2, X14
+ PSHUFD $0x80, X3, X13
+ PBLENDW $0xf0, X13, X14
+ MOVOU permuted_blake_consts<>+32(SB), X15
+ PXOR X14, X15
+ PADDD X15, X7
+ PSHUFD $0x0d, X2, X14
+ PSHUFD $0xd0, X3, X13
+ PBLENDW $0xf0, X13, X14
+ MOVOU permuted_blake_consts<>+48(SB), X15
+ PXOR X14, X15
+ PADDD X8, X7
+ PXOR X7, X10
+ PSHUFB X5, X10
+ PADDD X10, X9
+ PXOR X9, X8
+ MOVO X8, X13
+ PSRLL $0x0c, X13
+ PSLLL $0x14, X8
+ PXOR X13, X8
+ PADDD X15, X7
+ PADDD X8, X7
+ PXOR X7, X10
+ PSHUFB X4, X10
+ PADDD X10, X9
+ PXOR X9, X8
+ MOVO X8, X13
+ PSRLL $0x07, X13
+ PSLLL $0x19, X8
+ PXOR X13, X8
+
+ // Round 11 diagonal step part 3: undiagonalize.
+ PSHUFD $0x93, X8, X8
+ PSHUFD $0x4e, X9, X9
+ PSHUFD $0x39, X10, X10
+
+ // Round 12 column step.
+ PSHUFD $0x00, X1, X14
+ PSHUFD $0x10, X2, X13
+ PBLENDW $0x30, X13, X14
+ PSHUFD $0x42, X3, X13
+ PBLENDW $0xc3, X13, X14
+ MOVOU permuted_blake_consts<>+64(SB), X15
+ PXOR X14, X15
+ PADDD X15, X7
+ PSHUFD $0x80, X1, X14
+ PSHUFD $0x02, X2, X13
+ PBLENDW $0x0f, X13, X14
+ PSHUFD $0x30, X3, X13
+ PBLENDW $0x30, X13, X14
+ MOVOU permuted_blake_consts<>+80(SB), X15
+ PXOR X14, X15
+ PADDD X8, X7
+ PXOR X7, X10
+ PSHUFB X5, X10
+ PADDD X10, X9
+ PXOR X9, X8
+ MOVO X8, X13
+ PSRLL $0x0c, X13
+ PSLLL $0x14, X8
+ PXOR X13, X8
+ PADDD X15, X7
+ PADDD X8, X7
+ PXOR X7, X10
+ PSHUFB X4, X10
+ PADDD X10, X9
+ PXOR X9, X8
+ MOVO X8, X13
+ PSRLL $0x07, X13
+ PSLLL $0x19, X8
+ PXOR X13, X8
+
+ // Round 12 diagonal step part 1: diagonalize.
+ PSHUFD $0x39, X8, X8
+ PSHUFD $0x4e, X9, X9
+ PSHUFD $0x93, X10, X10
+
+ // Round 12 diagonal step part 2: column step.
+ PSHUFD $0x01, X0, X14
+ PSHUFD $0x40, X1, X13
+ PBLENDW $0xc0, X13, X14
+ PSHUFD $0x30, X2, X13
+ PBLENDW $0x30, X13, X14
+ MOVOU permuted_blake_consts<>+96(SB), X15
+ PXOR X14, X15
+ PADDD X15, X7
+ PSHUFD $0xc8, X0, X14
+ PSHUFD $0x30, X1, X13
+ PBLENDW $0x30, X13, X14
+ PSHUFD $0x00, X3, X13
+ PBLENDW $0x03, X13, X14
+ MOVOU permuted_blake_consts<>+112(SB), X15
+ PXOR X14, X15
+ PADDD X8, X7
+ PXOR X7, X10
+ PSHUFB X5, X10
+ PADDD X10, X9
+ PXOR X9, X8
+ MOVO X8, X13
+ PSRLL $0x0c, X13
+ PSLLL $0x14, X8
+ PXOR X13, X8
+ PADDD X15, X7
+ PADDD X8, X7
+ PXOR X7, X10
+ PSHUFB X4, X10
+ PADDD X10, X9
+ PXOR X9, X8
+ MOVO X8, X13
+ PSRLL $0x07, X13
+ PSLLL $0x19, X8
+ PXOR X13, X8
+
+ // Round 12 diagonal step part 3: undiagonalize.
+ PSHUFD $0x93, X8, X8
+ PSHUFD $0x4e, X9, X9
+ PSHUFD $0x39, X10, X10
+
+ // Round 13 column step.
+ PSHUFD $0x10, X1, X14
+ PSHUFD $0x03, X2, X13
+ PBLENDW $0x03, X13, X14
+ PSHUFD $0xc0, X3, X13
+ PBLENDW $0xcc, X13, X14
+ MOVOU permuted_blake_consts<>+128(SB), X15
+ PXOR X14, X15
+ PADDD X15, X7
+ PSHUFD $0x20, X0, X14
+ PSHUFD $0x00, X2, X13
+ PBLENDW $0x03, X13, X14
+ PSHUFD $0x40, X3, X13
+ PBLENDW $0xc0, X13, X14
+ MOVOU permuted_blake_consts<>+144(SB), X15
+ PXOR X14, X15
+ PADDD X8, X7
+ PXOR X7, X10
+ PSHUFB X5, X10
+ PADDD X10, X9
+ PXOR X9, X8
+ MOVO X8, X13
+ PSRLL $0x0c, X13
+ PSLLL $0x14, X8
+ PXOR X13, X8
+ PADDD X15, X7
+ PADDD X8, X7
+ PXOR X7, X10
+ PSHUFB X4, X10
+ PADDD X10, X9
+ PXOR X9, X8
+ MOVO X8, X13
+ PSRLL $0x07, X13
+ PSLLL $0x19, X8
+ PXOR X13, X8
+
+ // Round 13 diagonal step part 1: diagonalize.
+ PSHUFD $0x39, X8, X8
+ PSHUFD $0x4e, X9, X9
+ PSHUFD $0x93, X10, X10
+
+ // Round 13 diagonal step part 2: column step.
+ PSHUFD $0x0c, X0, X14
+ PSHUFD $0x30, X1, X13
+ PBLENDW $0x30, X13, X14
+ PSHUFD $0x42, X2, X13
+ PBLENDW $0xc3, X13, X14
+ MOVOU permuted_blake_consts<>+160(SB), X15
+ PXOR X14, X15
+ PADDD X15, X7
+ PSHUFD $0x10, X0, X14
+ PSHUFD $0x08, X1, X13
+ PBLENDW $0xcc, X13, X14
+ PSHUFD $0x02, X3, X13
+ PBLENDW $0x03, X13, X14
+ MOVOU permuted_blake_consts<>+176(SB), X15
+ PXOR X14, X15
+ PADDD X8, X7
+ PXOR X7, X10
+ PSHUFB X5, X10
+ PADDD X10, X9
+ PXOR X9, X8
+ MOVO X8, X13
+ PSRLL $0x0c, X13
+ PSLLL $0x14, X8
+ PXOR X13, X8
+ PADDD X15, X7
+ PADDD X8, X7
+ PXOR X7, X10
+ PSHUFB X4, X10
+ PADDD X10, X9
+ PXOR X9, X8
+ MOVO X8, X13
+ PSRLL $0x07, X13
+ PSLLL $0x19, X8
+ PXOR X13, X8
+
+ // Round 13 diagonal step part 3: undiagonalize.
+ PSHUFD $0x93, X8, X8
+ PSHUFD $0x4e, X9, X9
+ PSHUFD $0x39, X10, X10
+
+ // Round 14 column step.
+ PSHUFD $0x0c, X0, X14
+ PSHUFD $0x03, X1, X13
+ PBLENDW $0x03, X13, X14
+ PSHUFD $0xc0, X2, X13
+ PBLENDW $0xc0, X13, X14
+ PSHUFD $0x10, X3, X13
+ PBLENDW $0x30, X13, X14
+ MOVOU permuted_blake_consts<>+192(SB), X15
+ PXOR X14, X15
+ PADDD X15, X7
+ PSHUFD $0x04, X0, X14
+ PSHUFD $0x01, X2, X13
+ PBLENDW $0x03, X13, X14
+ PSHUFD $0x80, X3, X13
+ PBLENDW $0xf0, X13, X14
+ MOVOU permuted_blake_consts<>+208(SB), X15
+ PXOR X14, X15
+ PADDD X8, X7
+ PXOR X7, X10
+ PSHUFB X5, X10
+ PADDD X10, X9
+ PXOR X9, X8
+ MOVO X8, X13
+ PSRLL $0x0c, X13
+ PSLLL $0x14, X8
+ PXOR X13, X8
+ PADDD X15, X7
+ PADDD X8, X7
+ PXOR X7, X10
+ PSHUFB X4, X10
+ PADDD X10, X9
+ PXOR X9, X8
+ MOVO X8, X13
+ PSRLL $0x07, X13
+ PSLLL $0x19, X8
+ PXOR X13, X8
+
+ // Round 14 diagonal step part 1: diagonalize.
+ PSHUFD $0x39, X8, X8
+ PSHUFD $0x4e, X9, X9
+ PSHUFD $0x93, X10, X10
+
+ // Round 14 diagonal step part 2: column step.
+ PSHUFD $0x02, X0, X14
+ PSHUFD $0x04, X1, X13
+ PBLENDW $0x3c, X13, X14
+ PSHUFD $0xc0, X3, X13
+ PBLENDW $0xc0, X13, X14
+ MOVOU permuted_blake_consts<>+224(SB), X15
+ PXOR X14, X15
+ PADDD X15, X7
+ PSHUFD $0x00, X0, X14
+ PSHUFD $0x02, X1, X13
+ PBLENDW $0x03, X13, X14
+ PSHUFD $0x08, X2, X13
+ PBLENDW $0xcc, X13, X14
+ MOVOU permuted_blake_consts<>+240(SB), X15
+ PXOR X14, X15
+ PADDD X8, X7
+ PXOR X7, X10
+ PSHUFB X5, X10
+ PADDD X10, X9
+ PXOR X9, X8
+ MOVO X8, X13
+ PSRLL $0x0c, X13
+ PSLLL $0x14, X8
+ PXOR X13, X8
+ PADDD X15, X7
+ PADDD X8, X7
+ PXOR X7, X10
+ PSHUFB X4, X10
+ PADDD X10, X9
+ PXOR X9, X8
+ MOVO X8, X13
+ PSRLL $0x07, X13
+ PSLLL $0x19, X8
+ PXOR X13, X8
+
+ // Round 14 diagonal step part 3: undiagonalize.
+ PSHUFD $0x93, X8, X8
+ PSHUFD $0x4e, X9, X9
+ PSHUFD $0x39, X10, X10
+
+ // Finally the chain value is defined as:
+ // h'0 = h0^s0^v0^v8
+ // h'1 = h1^s1^v1^v9
+ // h'2 = h2^s2^v2^va
+ // h'3 = h3^s3^v3^vb
+ // h'4 = h4^s0^v4^vc
+ // h'5 = h5^s1^v5^vd
+ // h'6 = h6^s2^v6^ve
+ // h'7 = h7^s3^v7^vf
+ PXOR X11, X7
+ PXOR X6, X7
+ PXOR X9, X7
+ PXOR X12, X8
+ PXOR X6, X8
+ PXOR X10, X8
+
+ // Either terminate the loop when there are no more full blocks
+ // to compress or move the message pointer to the next block of
+ // bytes to compress, increment the message bits counter
+ // accordingly, and loop back around to compress it.
+ DECQ BX
+ JZ done
+ LEAQ 64(DX), DX
+ ADDQ $0x00000200, CX
+ JMP compressLoop
+
+done:
+ // Output the resulting chain value.
+ MOVOU X7, (AX)
+ MOVOU X8, 16(AX)
+ RET
+
+// func blocksAVX(state *State, msg []byte, counter uint64)
+// Requires: AVX
+TEXT ·blocksAVX(SB), NOSPLIT, $0-40
+ MOVQ state+0(FP), AX
+ MOVQ counter+32(FP), CX
+ MOVQ msg_base+8(FP), DX
+ MOVQ msg_len+16(FP), BX
+
+ // Populate registers for fast right rotations.
+ VMOVDQU shuffle_rotr8_4x32<>+0(SB), X4
+ VMOVDQU shuffle_rotr16_4x32<>+0(SB), X5
+
+ // Convert message len to number of blocks for loop counter.
+ SHRQ $0x06, BX
+
+ // Initialize state matrix.
+ // row0 = |v0 v1 v2 v3| | h0 h1 h2 h3 |
+ // row1 = |v4 v5 v6 v7| | h4 h5 h6 h7 |
+ VMOVDQU 32(AX), X6
+ VMOVDQU (AX), X7
+ VMOVDQU 16(AX), X8
+
+compressLoop:
+ // row2 = |v8 v9 va vb| = |s0^c0 s1^c1 s2^c2 s3^c3|
+ // row3 = |vc vd ve vf| |t0^c4 t0^c5 t1^c6 t1^c7|
+ VMOVDQU first_8_blake_consts<>+0(SB), X9
+ VPXOR X6, X9, X9
+ VMOVQ CX, X10
+ VPSHUFD $0x50, X10, X10
+ VPXOR first_8_blake_consts<>+16(SB), X10, X10
+ VMOVDQA X7, X11
+ VMOVDQA X8, X12
+
+ // Convert message to big endian.
+ VMOVDQU shuffle_le_to_be_4x32<>+0(SB), X13
+ VMOVDQU (DX), X0
+ VPSHUFB X13, X0, X0
+ VMOVDQU 16(DX), X1
+ VPSHUFB X13, X1, X1
+ VMOVDQU 32(DX), X2
+ VPSHUFB X13, X2, X2
+ VMOVDQU 48(DX), X3
+ VPSHUFB X13, X3, X3
+
+ // Round 1 column step.
+ VPSHUFD $0x08, X0, X14
+ VPSHUFD $0x80, X1, X13
+ VPBLENDW $0xf0, X13, X14, X14
+ VMOVDQU permuted_blake_consts<>+0(SB), X15
+ VPXOR X14, X15, X15
+ VPADDD X15, X7, X7
+ VPSHUFD $0x0d, X0, X14
+ VPSHUFD $0xd0, X1, X13
+ VPBLENDW $0xf0, X13, X14, X14
+ VMOVDQU permuted_blake_consts<>+16(SB), X15
+ VPXOR X14, X15, X15
+ VPADDD X8, X7, X7
+ VPXOR X7, X10, X10
+ VPSHUFB X5, X10, X10
+ VPADDD X10, X9, X9
+ VPXOR X9, X8, X8
+ VPSRLD $0x0c, X8, X13
+ VPSLLD $0x14, X8, X8
+ VPXOR X13, X8, X8
+ VPADDD X15, X7, X7
+ VPADDD X8, X7, X7
+ VPXOR X7, X10, X10
+ VPSHUFB X4, X10, X10
+ VPADDD X10, X9, X9
+ VPXOR X9, X8, X8
+ VPSRLD $0x07, X8, X13
+ VPSLLD $0x19, X8, X8
+ VPXOR X13, X8, X8
+
+ // Round 1 diagonal step part 1: diagonalize.
+ VPSHUFD $0x39, X8, X8
+ VPSHUFD $0x4e, X9, X9
+ VPSHUFD $0x93, X10, X10
+
+ // Round 1 diagonal step part 2: column step.
+ VPSHUFD $0x08, X2, X14
+ VPSHUFD $0x80, X3, X13
+ VPBLENDW $0xf0, X13, X14, X14
+ VMOVDQU permuted_blake_consts<>+32(SB), X15
+ VPXOR X14, X15, X15
+ VPADDD X15, X7, X7
+ VPSHUFD $0x0d, X2, X14
+ VPSHUFD $0xd0, X3, X13
+ VPBLENDW $0xf0, X13, X14, X14
+ VMOVDQU permuted_blake_consts<>+48(SB), X15
+ VPXOR X14, X15, X15
+ VPADDD X8, X7, X7
+ VPXOR X7, X10, X10
+ VPSHUFB X5, X10, X10
+ VPADDD X10, X9, X9
+ VPXOR X9, X8, X8
+ VPSRLD $0x0c, X8, X13
+ VPSLLD $0x14, X8, X8
+ VPXOR X13, X8, X8
+ VPADDD X15, X7, X7
+ VPADDD X8, X7, X7
+ VPXOR X7, X10, X10
+ VPSHUFB X4, X10, X10
+ VPADDD X10, X9, X9
+ VPXOR X9, X8, X8
+ VPSRLD $0x07, X8, X13
+ VPSLLD $0x19, X8, X8
+ VPXOR X13, X8, X8
+
+ // Round 1 diagonal step part 3: undiagonalize.
+ VPSHUFD $0x93, X8, X8
+ VPSHUFD $0x4e, X9, X9
+ VPSHUFD $0x39, X10, X10
+
+ // Round 2 column step.
+ VPSHUFD $0x00, X1, X14
+ VPSHUFD $0x10, X2, X13
+ VPBLENDW $0x30, X13, X14, X14
+ VPSHUFD $0x42, X3, X13
+ VPBLENDW $0xc3, X13, X14, X14
+ VMOVDQU permuted_blake_consts<>+64(SB), X15
+ VPXOR X14, X15, X15
+ VPADDD X15, X7, X7
+ VPSHUFD $0x80, X1, X14
+ VPSHUFD $0x02, X2, X13
+ VPBLENDW $0x0f, X13, X14, X14
+ VPSHUFD $0x30, X3, X13
+ VPBLENDW $0x30, X13, X14, X14
+ VMOVDQU permuted_blake_consts<>+80(SB), X15
+ VPXOR X14, X15, X15
+ VPADDD X8, X7, X7
+ VPXOR X7, X10, X10
+ VPSHUFB X5, X10, X10
+ VPADDD X10, X9, X9
+ VPXOR X9, X8, X8
+ VPSRLD $0x0c, X8, X13
+ VPSLLD $0x14, X8, X8
+ VPXOR X13, X8, X8
+ VPADDD X15, X7, X7
+ VPADDD X8, X7, X7
+ VPXOR X7, X10, X10
+ VPSHUFB X4, X10, X10
+ VPADDD X10, X9, X9
+ VPXOR X9, X8, X8
+ VPSRLD $0x07, X8, X13
+ VPSLLD $0x19, X8, X8
+ VPXOR X13, X8, X8
+
+ // Round 2 diagonal step part 1: diagonalize.
+ VPSHUFD $0x39, X8, X8
+ VPSHUFD $0x4e, X9, X9
+ VPSHUFD $0x93, X10, X10
+
+ // Round 2 diagonal step part 2: column step.
+ VPSHUFD $0x01, X0, X14
+ VPSHUFD $0x40, X1, X13
+ VPBLENDW $0xc0, X13, X14, X14
+ VPSHUFD $0x30, X2, X13
+ VPBLENDW $0x30, X13, X14, X14
+ VMOVDQU permuted_blake_consts<>+96(SB), X15
+ VPXOR X14, X15, X15
+ VPADDD X15, X7, X7
+ VPSHUFD $0xc8, X0, X14
+ VPSHUFD $0x30, X1, X13
+ VPBLENDW $0x30, X13, X14, X14
+ VPSHUFD $0x00, X3, X13
+ VPBLENDW $0x03, X13, X14, X14
+ VMOVDQU permuted_blake_consts<>+112(SB), X15
+ VPXOR X14, X15, X15
+ VPADDD X8, X7, X7
+ VPXOR X7, X10, X10
+ VPSHUFB X5, X10, X10
+ VPADDD X10, X9, X9
+ VPXOR X9, X8, X8
+ VPSRLD $0x0c, X8, X13
+ VPSLLD $0x14, X8, X8
+ VPXOR X13, X8, X8
+ VPADDD X15, X7, X7
+ VPADDD X8, X7, X7
+ VPXOR X7, X10, X10
+ VPSHUFB X4, X10, X10
+ VPADDD X10, X9, X9
+ VPXOR X9, X8, X8
+ VPSRLD $0x07, X8, X13
+ VPSLLD $0x19, X8, X8
+ VPXOR X13, X8, X8
+
+ // Round 2 diagonal step part 3: undiagonalize.
+ VPSHUFD $0x93, X8, X8
+ VPSHUFD $0x4e, X9, X9
+ VPSHUFD $0x39, X10, X10
+
+ // Round 3 column step.
+ VPSHUFD $0x10, X1, X14
+ VPSHUFD $0x03, X2, X13
+ VPBLENDW $0x03, X13, X14, X14
+ VPSHUFD $0xc0, X3, X13
+ VPBLENDW $0xcc, X13, X14, X14
+ VMOVDQU permuted_blake_consts<>+128(SB), X15
+ VPXOR X14, X15, X15
+ VPADDD X15, X7, X7
+ VPSHUFD $0x20, X0, X14
+ VPSHUFD $0x00, X2, X13
+ VPBLENDW $0x03, X13, X14, X14
+ VPSHUFD $0x40, X3, X13
+ VPBLENDW $0xc0, X13, X14, X14
+ VMOVDQU permuted_blake_consts<>+144(SB), X15
+ VPXOR X14, X15, X15
+ VPADDD X8, X7, X7
+ VPXOR X7, X10, X10
+ VPSHUFB X5, X10, X10
+ VPADDD X10, X9, X9
+ VPXOR X9, X8, X8
+ VPSRLD $0x0c, X8, X13
+ VPSLLD $0x14, X8, X8
+ VPXOR X13, X8, X8
+ VPADDD X15, X7, X7
+ VPADDD X8, X7, X7
+ VPXOR X7, X10, X10
+ VPSHUFB X4, X10, X10
+ VPADDD X10, X9, X9
+ VPXOR X9, X8, X8
+ VPSRLD $0x07, X8, X13
+ VPSLLD $0x19, X8, X8
+ VPXOR X13, X8, X8
+
+ // Round 3 diagonal step part 1: diagonalize.
+ VPSHUFD $0x39, X8, X8
+ VPSHUFD $0x4e, X9, X9
+ VPSHUFD $0x93, X10, X10
+
+ // Round 3 diagonal step part 2: column step.
+ VPSHUFD $0x0c, X0, X14
+ VPSHUFD $0x30, X1, X13
+ VPBLENDW $0x30, X13, X14, X14
+ VPSHUFD $0x42, X2, X13
+ VPBLENDW $0xc3, X13, X14, X14
+ VMOVDQU permuted_blake_consts<>+160(SB), X15
+ VPXOR X14, X15, X15
+ VPADDD X15, X7, X7
+ VPSHUFD $0x10, X0, X14
+ VPSHUFD $0x08, X1, X13
+ VPBLENDW $0xcc, X13, X14, X14
+ VPSHUFD $0x02, X3, X13
+ VPBLENDW $0x03, X13, X14, X14
+ VMOVDQU permuted_blake_consts<>+176(SB), X15
+ VPXOR X14, X15, X15
+ VPADDD X8, X7, X7
+ VPXOR X7, X10, X10
+ VPSHUFB X5, X10, X10
+ VPADDD X10, X9, X9
+ VPXOR X9, X8, X8
+ VPSRLD $0x0c, X8, X13
+ VPSLLD $0x14, X8, X8
+ VPXOR X13, X8, X8
+ VPADDD X15, X7, X7
+ VPADDD X8, X7, X7
+ VPXOR X7, X10, X10
+ VPSHUFB X4, X10, X10
+ VPADDD X10, X9, X9
+ VPXOR X9, X8, X8
+ VPSRLD $0x07, X8, X13
+ VPSLLD $0x19, X8, X8
+ VPXOR X13, X8, X8
+
+ // Round 3 diagonal step part 3: undiagonalize.
+ VPSHUFD $0x93, X8, X8
+ VPSHUFD $0x4e, X9, X9
+ VPSHUFD $0x39, X10, X10
+
+ // Round 4 column step.
+ VPSHUFD $0x0c, X0, X14
+ VPSHUFD $0x03, X1, X13
+ VPBLENDW $0x03, X13, X14, X14
+ VPSHUFD $0xc0, X2, X13
+ VPBLENDW $0xc0, X13, X14, X14
+ VPSHUFD $0x10, X3, X13
+ VPBLENDW $0x30, X13, X14, X14
+ VMOVDQU permuted_blake_consts<>+192(SB), X15
+ VPXOR X14, X15, X15
+ VPADDD X15, X7, X7
+ VPSHUFD $0x04, X0, X14
+ VPSHUFD $0x01, X2, X13
+ VPBLENDW $0x03, X13, X14, X14
+ VPSHUFD $0x80, X3, X13
+ VPBLENDW $0xf0, X13, X14, X14
+ VMOVDQU permuted_blake_consts<>+208(SB), X15
+ VPXOR X14, X15, X15
+ VPADDD X8, X7, X7
+ VPXOR X7, X10, X10
+ VPSHUFB X5, X10, X10
+ VPADDD X10, X9, X9
+ VPXOR X9, X8, X8
+ VPSRLD $0x0c, X8, X13
+ VPSLLD $0x14, X8, X8
+ VPXOR X13, X8, X8
+ VPADDD X15, X7, X7
+ VPADDD X8, X7, X7
+ VPXOR X7, X10, X10
+ VPSHUFB X4, X10, X10
+ VPADDD X10, X9, X9
+ VPXOR X9, X8, X8
+ VPSRLD $0x07, X8, X13
+ VPSLLD $0x19, X8, X8
+ VPXOR X13, X8, X8
+
+ // Round 4 diagonal step part 1: diagonalize.
+ VPSHUFD $0x39, X8, X8
+ VPSHUFD $0x4e, X9, X9
+ VPSHUFD $0x93, X10, X10
+
+ // Round 4 diagonal step part 2: column step.
+ VPSHUFD $0x02, X0, X14
+ VPSHUFD $0x04, X1, X13
+ VPBLENDW $0x3c, X13, X14, X14
+ VPSHUFD $0xc0, X3, X13
+ VPBLENDW $0xc0, X13, X14, X14
+ VMOVDQU permuted_blake_consts<>+224(SB), X15
+ VPXOR X14, X15, X15
+ VPADDD X15, X7, X7
+ VPSHUFD $0x00, X0, X14
+ VPSHUFD $0x02, X1, X13
+ VPBLENDW $0x03, X13, X14, X14
+ VPSHUFD $0x08, X2, X13
+ VPBLENDW $0xcc, X13, X14, X14
+ VMOVDQU permuted_blake_consts<>+240(SB), X15
+ VPXOR X14, X15, X15
+ VPADDD X8, X7, X7
+ VPXOR X7, X10, X10
+ VPSHUFB X5, X10, X10
+ VPADDD X10, X9, X9
+ VPXOR X9, X8, X8
+ VPSRLD $0x0c, X8, X13
+ VPSLLD $0x14, X8, X8
+ VPXOR X13, X8, X8
+ VPADDD X15, X7, X7
+ VPADDD X8, X7, X7
+ VPXOR X7, X10, X10
+ VPSHUFB X4, X10, X10
+ VPADDD X10, X9, X9
+ VPXOR X9, X8, X8
+ VPSRLD $0x07, X8, X13
+ VPSLLD $0x19, X8, X8
+ VPXOR X13, X8, X8
+
+ // Round 4 diagonal step part 3: undiagonalize.
+ VPSHUFD $0x93, X8, X8
+ VPSHUFD $0x4e, X9, X9
+ VPSHUFD $0x39, X10, X10
+
+ // Round 5 column step.
+ VPSHUFD $0x20, X0, X14
+ VPSHUFD $0x04, X1, X13
+ VPBLENDW $0x0c, X13, X14, X14
+ VPSHUFD $0x81, X2, X13
+ VPBLENDW $0xc3, X13, X14, X14
+ VMOVDQU permuted_blake_consts<>+256(SB), X15
+ VPXOR X14, X15, X15
+ VPADDD X15, X7, X7
+ VPSHUFD $0x00, X0, X14
+ VPSHUFD $0x0c, X1, X13
+ VPBLENDW $0x3c, X13, X14, X14
+ VPSHUFD $0xc0, X3, X13
+ VPBLENDW $0xc0, X13, X14, X14
+ VMOVDQU permuted_blake_consts<>+272(SB), X15
+ VPXOR X14, X15, X15
+ VPADDD X8, X7, X7
+ VPXOR X7, X10, X10
+ VPSHUFB X5, X10, X10
+ VPADDD X10, X9, X9
+ VPXOR X9, X8, X8
+ VPSRLD $0x0c, X8, X13
+ VPSLLD $0x14, X8, X8
+ VPXOR X13, X8, X8
+ VPADDD X15, X7, X7
+ VPADDD X8, X7, X7
+ VPXOR X7, X10, X10
+ VPSHUFB X4, X10, X10
+ VPADDD X10, X9, X9
+ VPXOR X9, X8, X8
+ VPSRLD $0x07, X8, X13
+ VPSLLD $0x19, X8, X8
+ VPXOR X13, X8, X8
+
+ // Round 5 diagonal step part 1: diagonalize.
+ VPSHUFD $0x39, X8, X8
+ VPSHUFD $0x4e, X9, X9
+ VPSHUFD $0x93, X10, X10
+
+ // Round 5 diagonal step part 2: column step.
+ VPSHUFD $0xc0, X0, X14
+ VPSHUFD $0x20, X1, X13
+ VPBLENDW $0x30, X13, X14, X14
+ VPSHUFD $0x0c, X2, X13
+ VPBLENDW $0x0c, X13, X14, X14
+ VPSHUFD $0x02, X3, X13
+ VPBLENDW $0x03, X13, X14, X14
+ VMOVDQU permuted_blake_consts<>+288(SB), X15
+ VPXOR X14, X15, X15
+ VPADDD X15, X7, X7
+ VPSHUFD $0x01, X0, X14
+ VPSHUFD $0x00, X2, X13
+ VPBLENDW $0x30, X13, X14, X14
+ VPSHUFD $0x40, X3, X13
+ VPBLENDW $0xcc, X13, X14, X14
+ VMOVDQU permuted_blake_consts<>+304(SB), X15
+ VPXOR X14, X15, X15
+ VPADDD X8, X7, X7
+ VPXOR X7, X10, X10
+ VPSHUFB X5, X10, X10
+ VPADDD X10, X9, X9
+ VPXOR X9, X8, X8
+ VPSRLD $0x0c, X8, X13
+ VPSLLD $0x14, X8, X8
+ VPXOR X13, X8, X8
+ VPADDD X15, X7, X7
+ VPADDD X8, X7, X7
+ VPXOR X7, X10, X10
+ VPSHUFB X4, X10, X10
+ VPADDD X10, X9, X9
+ VPXOR X9, X8, X8
+ VPSRLD $0x07, X8, X13
+ VPSLLD $0x19, X8, X8
+ VPXOR X13, X8, X8
+
+ // Round 5 diagonal step part 3: undiagonalize.
+ VPSHUFD $0x93, X8, X8
+ VPSHUFD $0x4e, X9, X9
+ VPSHUFD $0x39, X10, X10
+
+ // Round 6 column step.
+ VPSHUFD $0x02, X0, X14
+ VPSHUFD $0x08, X1, X13
+ VPBLENDW $0x0c, X13, X14, X14
+ VPSHUFD $0x00, X2, X13
+ VPBLENDW $0xc0, X13, X14, X14
+ VMOVDQU permuted_blake_consts<>+320(SB), X15
+ VPXOR X14, X15, X15
+ VPADDD X15, X7, X7
+ VPSHUFD $0xc0, X0, X14
+ VPSHUFD $0x38, X2, X13
+ VPBLENDW $0x3c, X13, X14, X14
+ VPSHUFD $0x00, X3, X13
+ VPBLENDW $0x03, X13, X14, X14
+ VMOVDQU permuted_blake_consts<>+336(SB), X15
+ VPXOR X14, X15, X15
+ VPADDD X8, X7, X7
+ VPXOR X7, X10, X10
+ VPSHUFB X5, X10, X10
+ VPADDD X10, X9, X9
+ VPXOR X9, X8, X8
+ VPSRLD $0x0c, X8, X13
+ VPSLLD $0x14, X8, X8
+ VPXOR X13, X8, X8
+ VPADDD X15, X7, X7
+ VPADDD X8, X7, X7
+ VPXOR X7, X10, X10
+ VPSHUFB X4, X10, X10
+ VPADDD X10, X9, X9
+ VPXOR X9, X8, X8
+ VPSRLD $0x07, X8, X13
+ VPSLLD $0x19, X8, X8
+ VPXOR X13, X8, X8
+
+ // Round 6 diagonal step part 1: diagonalize.
+ VPSHUFD $0x39, X8, X8
+ VPSHUFD $0x4e, X9, X9
+ VPSHUFD $0x93, X10, X10
+
+ // Round 6 diagonal step part 2: column step.
+ VPSHUFD $0x40, X0, X14
+ VPSHUFD $0x0c, X1, X13
+ VPBLENDW $0x0f, X13, X14, X14
+ VPSHUFD $0x30, X3, X13
+ VPBLENDW $0x30, X13, X14, X14
+ VMOVDQU permuted_blake_consts<>+352(SB), X15
+ VPXOR X14, X15, X15
+ VPADDD X15, X7, X7
+ VPSHUFD $0x04, X1, X14
+ VPSHUFD $0x40, X2, X13
+ VPBLENDW $0xc0, X13, X14, X14
+ VPSHUFD $0x21, X3, X13
+ VPBLENDW $0x33, X13, X14, X14
+ VMOVDQU permuted_blake_consts<>+368(SB), X15
+ VPXOR X14, X15, X15
+ VPADDD X8, X7, X7
+ VPXOR X7, X10, X10
+ VPSHUFB X5, X10, X10
+ VPADDD X10, X9, X9
+ VPXOR X9, X8, X8
+ VPSRLD $0x0c, X8, X13
+ VPSLLD $0x14, X8, X8
+ VPXOR X13, X8, X8
+ VPADDD X15, X7, X7
+ VPADDD X8, X7, X7
+ VPXOR X7, X10, X10
+ VPSHUFB X4, X10, X10
+ VPADDD X10, X9, X9
+ VPXOR X9, X8, X8
+ VPSRLD $0x07, X8, X13
+ VPSLLD $0x19, X8, X8
+ VPXOR X13, X8, X8
+
+ // Round 6 diagonal step part 3: undiagonalize.
+ VPSHUFD $0x93, X8, X8
+ VPSHUFD $0x4e, X9, X9
+ VPSHUFD $0x39, X10, X10
+
+ // Round 7 column step.
+ VPSHUFD $0x04, X0, X14
+ VPSHUFD $0x00, X1, X13
+ VPBLENDW $0xc0, X13, X14, X14
+ VPSHUFD $0x20, X3, X13
+ VPBLENDW $0x33, X13, X14, X14
+ VMOVDQU permuted_blake_consts<>+384(SB), X15
+ VPXOR X14, X15, X15
+ VPADDD X15, X7, X7
+ VPSHUFD $0x01, X1, X14
+ VPSHUFD $0x80, X2, X13
+ VPBLENDW $0xc0, X13, X14, X14
+ VPSHUFD $0x1c, X3, X13
+ VPBLENDW $0x3c, X13, X14, X14
+ VMOVDQU permuted_blake_consts<>+400(SB), X15
+ VPXOR X14, X15, X15
+ VPADDD X8, X7, X7
+ VPXOR X7, X10, X10
+ VPSHUFB X5, X10, X10
+ VPADDD X10, X9, X9
+ VPXOR X9, X8, X8
+ VPSRLD $0x0c, X8, X13
+ VPSLLD $0x14, X8, X8
+ VPXOR X13, X8, X8
+ VPADDD X15, X7, X7
+ VPADDD X8, X7, X7
+ VPXOR X7, X10, X10
+ VPSHUFB X4, X10, X10
+ VPADDD X10, X9, X9
+ VPXOR X9, X8, X8
+ VPSRLD $0x07, X8, X13
+ VPSLLD $0x19, X8, X8
+ VPXOR X13, X8, X8
+
+ // Round 7 diagonal step part 1: diagonalize.
+ VPSHUFD $0x39, X8, X8
+ VPSHUFD $0x4e, X9, X9
+ VPSHUFD $0x93, X10, X10
+
+ // Round 7 diagonal step part 2: column step.
+ VPSHUFD $0x00, X0, X14
+ VPSHUFD $0x08, X1, X13
+ VPBLENDW $0x0c, X13, X14, X14
+ VPSHUFD $0x10, X2, X13
+ VPBLENDW $0xf0, X13, X14, X14
+ VMOVDQU permuted_blake_consts<>+416(SB), X15
+ VPXOR X14, X15, X15
+ VPADDD X15, X7, X7
+ VPSHUFD $0x2c, X0, X14
+ VPSHUFD $0x03, X1, X13
+ VPBLENDW $0x03, X13, X14, X14
+ VPSHUFD $0xc0, X2, X13
+ VPBLENDW $0xc0, X13, X14, X14
+ VMOVDQU permuted_blake_consts<>+432(SB), X15
+ VPXOR X14, X15, X15
+ VPADDD X8, X7, X7
+ VPXOR X7, X10, X10
+ VPSHUFB X5, X10, X10
+ VPADDD X10, X9, X9
+ VPXOR X9, X8, X8
+ VPSRLD $0x0c, X8, X13
+ VPSLLD $0x14, X8, X8
+ VPXOR X13, X8, X8
+ VPADDD X15, X7, X7
+ VPADDD X8, X7, X7
+ VPXOR X7, X10, X10
+ VPSHUFB X4, X10, X10
+ VPADDD X10, X9, X9
+ VPXOR X9, X8, X8
+ VPSRLD $0x07, X8, X13
+ VPSLLD $0x19, X8, X8
+ VPXOR X13, X8, X8
+
+ // Round 7 diagonal step part 3: undiagonalize.
+ VPSHUFD $0x93, X8, X8
+ VPSHUFD $0x4e, X9, X9
+ VPSHUFD $0x39, X10, X10
+
+ // Round 8 column step.
+ VPSHUFD $0xc0, X0, X14
+ VPSHUFD $0x0c, X1, X13
+ VPBLENDW $0x0c, X13, X14, X14
+ VPSHUFD $0x01, X3, X13
+ VPBLENDW $0x33, X13, X14, X14
+ VMOVDQU permuted_blake_consts<>+448(SB), X15
+ VPXOR X14, X15, X15
+ VPADDD X15, X7, X7
+ VPSHUFD $0x10, X0, X14
+ VPSHUFD $0x43, X2, X13
+ VPBLENDW $0xc3, X13, X14, X14
+ VPSHUFD $0x08, X3, X13
+ VPBLENDW $0x0c, X13, X14, X14
+ VMOVDQU permuted_blake_consts<>+464(SB), X15
+ VPXOR X14, X15, X15
+ VPADDD X8, X7, X7
+ VPXOR X7, X10, X10
+ VPSHUFB X5, X10, X10
+ VPADDD X10, X9, X9
+ VPXOR X9, X8, X8
+ VPSRLD $0x0c, X8, X13
+ VPSLLD $0x14, X8, X8
+ VPXOR X13, X8, X8
+ VPADDD X15, X7, X7
+ VPADDD X8, X7, X7
+ VPXOR X7, X10, X10
+ VPSHUFB X4, X10, X10
+ VPADDD X10, X9, X9
+ VPXOR X9, X8, X8
+ VPSRLD $0x07, X8, X13
+ VPSLLD $0x19, X8, X8
+ VPXOR X13, X8, X8
+
+ // Round 8 diagonal step part 1: diagonalize.
+ VPSHUFD $0x39, X8, X8
+ VPSHUFD $0x4e, X9, X9
+ VPSHUFD $0x93, X10, X10
+
+ // Round 8 diagonal step part 2: column step.
+ VPSHUFD $0x80, X0, X14
+ VPSHUFD $0x01, X1, X13
+ VPBLENDW $0x03, X13, X14, X14
+ VPSHUFD $0x00, X2, X13
+ VPBLENDW $0x30, X13, X14, X14
+ VPSHUFD $0x0c, X3, X13
+ VPBLENDW $0x0c, X13, X14, X14
+ VMOVDQU permuted_blake_consts<>+480(SB), X15
+ VPXOR X14, X15, X15
+ VPADDD X15, X7, X7
+ VPSHUFD $0x00, X0, X14
+ VPSHUFD $0x20, X1, X13
+ VPBLENDW $0x3c, X13, X14, X14
+ VPSHUFD $0x80, X2, X13
+ VPBLENDW $0xc0, X13, X14, X14
+ VMOVDQU permuted_blake_consts<>+496(SB), X15
+ VPXOR X14, X15, X15
+ VPADDD X8, X7, X7
+ VPXOR X7, X10, X10
+ VPSHUFB X5, X10, X10
+ VPADDD X10, X9, X9
+ VPXOR X9, X8, X8
+ VPSRLD $0x0c, X8, X13
+ VPSLLD $0x14, X8, X8
+ VPXOR X13, X8, X8
+ VPADDD X15, X7, X7
+ VPADDD X8, X7, X7
+ VPXOR X7, X10, X10
+ VPSHUFB X4, X10, X10
+ VPADDD X10, X9, X9
+ VPXOR X9, X8, X8
+ VPSRLD $0x07, X8, X13
+ VPSLLD $0x19, X8, X8
+ VPXOR X13, X8, X8
+
+ // Round 8 diagonal step part 3: undiagonalize.
+ VPSHUFD $0x93, X8, X8
+ VPSHUFD $0x4e, X9, X9
+ VPSHUFD $0x39, X10, X10
+
+ // Round 9 column step.
+ VPSHUFD $0x00, X0, X14
+ VPSHUFD $0x02, X1, X13
+ VPBLENDW $0x03, X13, X14, X14
+ VPSHUFD $0x30, X2, X13
+ VPBLENDW $0x30, X13, X14, X14
+ VPSHUFD $0x08, X3, X13
+ VPBLENDW $0x0c, X13, X14, X14
+ VMOVDQU permuted_blake_consts<>+512(SB), X15
+ VPXOR X14, X15, X15
+ VPADDD X15, X7, X7
+ VPSHUFD $0x30, X0, X14
+ VPSHUFD $0x04, X2, X13
+ VPBLENDW $0xcc, X13, X14, X14
+ VPSHUFD $0x03, X3, X13
+ VPBLENDW $0x03, X13, X14, X14
+ VMOVDQU permuted_blake_consts<>+528(SB), X15
+ VPXOR X14, X15, X15
+ VPADDD X8, X7, X7
+ VPXOR X7, X10, X10
+ VPSHUFB X5, X10, X10
+ VPADDD X10, X9, X9
+ VPXOR X9, X8, X8
+ VPSRLD $0x0c, X8, X13
+ VPSLLD $0x14, X8, X8
+ VPXOR X13, X8, X8
+ VPADDD X15, X7, X7
+ VPADDD X8, X7, X7
+ VPXOR X7, X10, X10
+ VPSHUFB X4, X10, X10
+ VPADDD X10, X9, X9
+ VPXOR X9, X8, X8
+ VPSRLD $0x07, X8, X13
+ VPSLLD $0x19, X8, X8
+ VPXOR X13, X8, X8
+
+ // Round 9 diagonal step part 1: diagonalize.
+ VPSHUFD $0x39, X8, X8
+ VPSHUFD $0x4e, X9, X9
+ VPSHUFD $0x93, X10, X10
+
+ // Round 9 diagonal step part 2: column step.
+ VPSHUFD $0x10, X0, X14
+ VPSHUFD $0x80, X2, X13
+ VPBLENDW $0xc0, X13, X14, X14
+ VPSHUFD $0x04, X3, X13
+ VPBLENDW $0x0f, X13, X14, X14
+ VMOVDQU permuted_blake_consts<>+544(SB), X15
+ VPXOR X14, X15, X15
+ VPADDD X15, X7, X7
+ VPSHUFD $0x02, X0, X14
+ VPSHUFD $0x4c, X1, X13
+ VPBLENDW $0xfc, X13, X14, X14
+ VMOVDQU permuted_blake_consts<>+560(SB), X15
+ VPXOR X14, X15, X15
+ VPADDD X8, X7, X7
+ VPXOR X7, X10, X10
+ VPSHUFB X5, X10, X10
+ VPADDD X10, X9, X9
+ VPXOR X9, X8, X8
+ VPSRLD $0x0c, X8, X13
+ VPSLLD $0x14, X8, X8
+ VPXOR X13, X8, X8
+ VPADDD X15, X7, X7
+ VPADDD X8, X7, X7
+ VPXOR X7, X10, X10
+ VPSHUFB X4, X10, X10
+ VPADDD X10, X9, X9
+ VPXOR X9, X8, X8
+ VPSRLD $0x07, X8, X13
+ VPSLLD $0x19, X8, X8
+ VPXOR X13, X8, X8
+
+ // Round 9 diagonal step part 3: undiagonalize.
+ VPSHUFD $0x93, X8, X8
+ VPSHUFD $0x4e, X9, X9
+ VPSHUFD $0x39, X10, X10
+
+ // Round 10 column step.
+ VPSHUFD $0x40, X0, X14
+ VPSHUFD $0x30, X1, X13
+ VPBLENDW $0x30, X13, X14, X14
+ VPSHUFD $0x02, X2, X13
+ VPBLENDW $0x0f, X13, X14, X14
+ VMOVDQU permuted_blake_consts<>+576(SB), X15
+ VPXOR X14, X15, X15
+ VPADDD X15, X7, X7
+ VPSHUFD $0x02, X0, X14
+ VPSHUFD $0x60, X1, X13
+ VPBLENDW $0xfc, X13, X14, X14
+ VMOVDQU permuted_blake_consts<>+592(SB), X15
+ VPXOR X14, X15, X15
+ VPADDD X8, X7, X7
+ VPXOR X7, X10, X10
+ VPSHUFB X5, X10, X10
+ VPADDD X10, X9, X9
+ VPXOR X9, X8, X8
+ VPSRLD $0x0c, X8, X13
+ VPSLLD $0x14, X8, X8
+ VPXOR X13, X8, X8
+ VPADDD X15, X7, X7
+ VPADDD X8, X7, X7
+ VPXOR X7, X10, X10
+ VPSHUFB X4, X10, X10
+ VPADDD X10, X9, X9
+ VPXOR X9, X8, X8
+ VPSRLD $0x07, X8, X13
+ VPSLLD $0x19, X8, X8
+ VPXOR X13, X8, X8
+
+ // Round 10 diagonal step part 1: diagonalize.
+ VPSHUFD $0x39, X8, X8
+ VPSHUFD $0x4e, X9, X9
+ VPSHUFD $0x93, X10, X10
+
+ // Round 10 diagonal step part 2: column step.
+ VPSHUFD $0x30, X0, X14
+ VPSHUFD $0x04, X2, X13
+ VPBLENDW $0x0c, X13, X14, X14
+ VPSHUFD $0x43, X3, X13
+ VPBLENDW $0xc3, X13, X14, X14
+ VMOVDQU permuted_blake_consts<>+608(SB), X15
+ VPXOR X14, X15, X15
+ VPADDD X15, X7, X7
+ VPSHUFD $0x00, X0, X14
+ VPSHUFD $0x03, X2, X13
+ VPBLENDW $0x03, X13, X14, X14
+ VPSHUFD $0x08, X3, X13
+ VPBLENDW $0x3c, X13, X14, X14
+ VMOVDQU permuted_blake_consts<>+624(SB), X15
+ VPXOR X14, X15, X15
+ VPADDD X8, X7, X7
+ VPXOR X7, X10, X10
+ VPSHUFB X5, X10, X10
+ VPADDD X10, X9, X9
+ VPXOR X9, X8, X8
+ VPSRLD $0x0c, X8, X13
+ VPSLLD $0x14, X8, X8
+ VPXOR X13, X8, X8
+ VPADDD X15, X7, X7
+ VPADDD X8, X7, X7
+ VPXOR X7, X10, X10
+ VPSHUFB X4, X10, X10
+ VPADDD X10, X9, X9
+ VPXOR X9, X8, X8
+ VPSRLD $0x07, X8, X13
+ VPSLLD $0x19, X8, X8
+ VPXOR X13, X8, X8
+
+ // Round 10 diagonal step part 3: undiagonalize.
+ VPSHUFD $0x93, X8, X8
+ VPSHUFD $0x4e, X9, X9
+ VPSHUFD $0x39, X10, X10
+
+ // Round 11 column step.
+ VPSHUFD $0x08, X0, X14
+ VPSHUFD $0x80, X1, X13
+ VPBLENDW $0xf0, X13, X14, X14
+ VMOVDQU permuted_blake_consts<>+0(SB), X15
+ VPXOR X14, X15, X15
+ VPADDD X15, X7, X7
+ VPSHUFD $0x0d, X0, X14
+ VPSHUFD $0xd0, X1, X13
+ VPBLENDW $0xf0, X13, X14, X14
+ VMOVDQU permuted_blake_consts<>+16(SB), X15
+ VPXOR X14, X15, X15
+ VPADDD X8, X7, X7
+ VPXOR X7, X10, X10
+ VPSHUFB X5, X10, X10
+ VPADDD X10, X9, X9
+ VPXOR X9, X8, X8
+ VPSRLD $0x0c, X8, X13
+ VPSLLD $0x14, X8, X8
+ VPXOR X13, X8, X8
+ VPADDD X15, X7, X7
+ VPADDD X8, X7, X7
+ VPXOR X7, X10, X10
+ VPSHUFB X4, X10, X10
+ VPADDD X10, X9, X9
+ VPXOR X9, X8, X8
+ VPSRLD $0x07, X8, X13
+ VPSLLD $0x19, X8, X8
+ VPXOR X13, X8, X8
+
+ // Round 11 diagonal step part 1: diagonalize.
+ VPSHUFD $0x39, X8, X8
+ VPSHUFD $0x4e, X9, X9
+ VPSHUFD $0x93, X10, X10
+
+ // Round 11 diagonal step part 2: column step.
+ VPSHUFD $0x08, X2, X14
+ VPSHUFD $0x80, X3, X13
+ VPBLENDW $0xf0, X13, X14, X14
+ VMOVDQU permuted_blake_consts<>+32(SB), X15
+ VPXOR X14, X15, X15
+ VPADDD X15, X7, X7
+ VPSHUFD $0x0d, X2, X14
+ VPSHUFD $0xd0, X3, X13
+ VPBLENDW $0xf0, X13, X14, X14
+ VMOVDQU permuted_blake_consts<>+48(SB), X15
+ VPXOR X14, X15, X15
+ VPADDD X8, X7, X7
+ VPXOR X7, X10, X10
+ VPSHUFB X5, X10, X10
+ VPADDD X10, X9, X9
+ VPXOR X9, X8, X8
+ VPSRLD $0x0c, X8, X13
+ VPSLLD $0x14, X8, X8
+ VPXOR X13, X8, X8
+ VPADDD X15, X7, X7
+ VPADDD X8, X7, X7
+ VPXOR X7, X10, X10
+ VPSHUFB X4, X10, X10
+ VPADDD X10, X9, X9
+ VPXOR X9, X8, X8
+ VPSRLD $0x07, X8, X13
+ VPSLLD $0x19, X8, X8
+ VPXOR X13, X8, X8
+
+ // Round 11 diagonal step part 3: undiagonalize.
+ VPSHUFD $0x93, X8, X8
+ VPSHUFD $0x4e, X9, X9
+ VPSHUFD $0x39, X10, X10
+
+ // Round 12 column step.
+ VPSHUFD $0x00, X1, X14
+ VPSHUFD $0x10, X2, X13
+ VPBLENDW $0x30, X13, X14, X14
+ VPSHUFD $0x42, X3, X13
+ VPBLENDW $0xc3, X13, X14, X14
+ VMOVDQU permuted_blake_consts<>+64(SB), X15
+ VPXOR X14, X15, X15
+ VPADDD X15, X7, X7
+ VPSHUFD $0x80, X1, X14
+ VPSHUFD $0x02, X2, X13
+ VPBLENDW $0x0f, X13, X14, X14
+ VPSHUFD $0x30, X3, X13
+ VPBLENDW $0x30, X13, X14, X14
+ VMOVDQU permuted_blake_consts<>+80(SB), X15
+ VPXOR X14, X15, X15
+ VPADDD X8, X7, X7
+ VPXOR X7, X10, X10
+ VPSHUFB X5, X10, X10
+ VPADDD X10, X9, X9
+ VPXOR X9, X8, X8
+ VPSRLD $0x0c, X8, X13
+ VPSLLD $0x14, X8, X8
+ VPXOR X13, X8, X8
+ VPADDD X15, X7, X7
+ VPADDD X8, X7, X7
+ VPXOR X7, X10, X10
+ VPSHUFB X4, X10, X10
+ VPADDD X10, X9, X9
+ VPXOR X9, X8, X8
+ VPSRLD $0x07, X8, X13
+ VPSLLD $0x19, X8, X8
+ VPXOR X13, X8, X8
+
+ // Round 12 diagonal step part 1: diagonalize.
+ VPSHUFD $0x39, X8, X8
+ VPSHUFD $0x4e, X9, X9
+ VPSHUFD $0x93, X10, X10
+
+ // Round 12 diagonal step part 2: column step.
+ VPSHUFD $0x01, X0, X14
+ VPSHUFD $0x40, X1, X13
+ VPBLENDW $0xc0, X13, X14, X14
+ VPSHUFD $0x30, X2, X13
+ VPBLENDW $0x30, X13, X14, X14
+ VMOVDQU permuted_blake_consts<>+96(SB), X15
+ VPXOR X14, X15, X15
+ VPADDD X15, X7, X7
+ VPSHUFD $0xc8, X0, X14
+ VPSHUFD $0x30, X1, X13
+ VPBLENDW $0x30, X13, X14, X14
+ VPSHUFD $0x00, X3, X13
+ VPBLENDW $0x03, X13, X14, X14
+ VMOVDQU permuted_blake_consts<>+112(SB), X15
+ VPXOR X14, X15, X15
+ VPADDD X8, X7, X7
+ VPXOR X7, X10, X10
+ VPSHUFB X5, X10, X10
+ VPADDD X10, X9, X9
+ VPXOR X9, X8, X8
+ VPSRLD $0x0c, X8, X13
+ VPSLLD $0x14, X8, X8
+ VPXOR X13, X8, X8
+ VPADDD X15, X7, X7
+ VPADDD X8, X7, X7
+ VPXOR X7, X10, X10
+ VPSHUFB X4, X10, X10
+ VPADDD X10, X9, X9
+ VPXOR X9, X8, X8
+ VPSRLD $0x07, X8, X13
+ VPSLLD $0x19, X8, X8
+ VPXOR X13, X8, X8
+
+ // Round 12 diagonal step part 3: undiagonalize.
+ VPSHUFD $0x93, X8, X8
+ VPSHUFD $0x4e, X9, X9
+ VPSHUFD $0x39, X10, X10
+
+ // Round 13 column step.
+ VPSHUFD $0x10, X1, X14
+ VPSHUFD $0x03, X2, X13
+ VPBLENDW $0x03, X13, X14, X14
+ VPSHUFD $0xc0, X3, X13
+ VPBLENDW $0xcc, X13, X14, X14
+ VMOVDQU permuted_blake_consts<>+128(SB), X15
+ VPXOR X14, X15, X15
+ VPADDD X15, X7, X7
+ VPSHUFD $0x20, X0, X14
+ VPSHUFD $0x00, X2, X13
+ VPBLENDW $0x03, X13, X14, X14
+ VPSHUFD $0x40, X3, X13
+ VPBLENDW $0xc0, X13, X14, X14
+ VMOVDQU permuted_blake_consts<>+144(SB), X15
+ VPXOR X14, X15, X15
+ VPADDD X8, X7, X7
+ VPXOR X7, X10, X10
+ VPSHUFB X5, X10, X10
+ VPADDD X10, X9, X9
+ VPXOR X9, X8, X8
+ VPSRLD $0x0c, X8, X13
+ VPSLLD $0x14, X8, X8
+ VPXOR X13, X8, X8
+ VPADDD X15, X7, X7
+ VPADDD X8, X7, X7
+ VPXOR X7, X10, X10
+ VPSHUFB X4, X10, X10
+ VPADDD X10, X9, X9
+ VPXOR X9, X8, X8
+ VPSRLD $0x07, X8, X13
+ VPSLLD $0x19, X8, X8
+ VPXOR X13, X8, X8
+
+ // Round 13 diagonal step part 1: diagonalize.
+ VPSHUFD $0x39, X8, X8
+ VPSHUFD $0x4e, X9, X9
+ VPSHUFD $0x93, X10, X10
+
+ // Round 13 diagonal step part 2: column step.
+ VPSHUFD $0x0c, X0, X14
+ VPSHUFD $0x30, X1, X13
+ VPBLENDW $0x30, X13, X14, X14
+ VPSHUFD $0x42, X2, X13
+ VPBLENDW $0xc3, X13, X14, X14
+ VMOVDQU permuted_blake_consts<>+160(SB), X15
+ VPXOR X14, X15, X15
+ VPADDD X15, X7, X7
+ VPSHUFD $0x10, X0, X14
+ VPSHUFD $0x08, X1, X13
+ VPBLENDW $0xcc, X13, X14, X14
+ VPSHUFD $0x02, X3, X13
+ VPBLENDW $0x03, X13, X14, X14
+ VMOVDQU permuted_blake_consts<>+176(SB), X15
+ VPXOR X14, X15, X15
+ VPADDD X8, X7, X7
+ VPXOR X7, X10, X10
+ VPSHUFB X5, X10, X10
+ VPADDD X10, X9, X9
+ VPXOR X9, X8, X8
+ VPSRLD $0x0c, X8, X13
+ VPSLLD $0x14, X8, X8
+ VPXOR X13, X8, X8
+ VPADDD X15, X7, X7
+ VPADDD X8, X7, X7
+ VPXOR X7, X10, X10
+ VPSHUFB X4, X10, X10
+ VPADDD X10, X9, X9
+ VPXOR X9, X8, X8
+ VPSRLD $0x07, X8, X13
+ VPSLLD $0x19, X8, X8
+ VPXOR X13, X8, X8
+
+ // Round 13 diagonal step part 3: undiagonalize.
+ VPSHUFD $0x93, X8, X8
+ VPSHUFD $0x4e, X9, X9
+ VPSHUFD $0x39, X10, X10
+
+ // Round 14 column step.
+ VPSHUFD $0x0c, X0, X14
+ VPSHUFD $0x03, X1, X13
+ VPBLENDW $0x03, X13, X14, X14
+ VPSHUFD $0xc0, X2, X13
+ VPBLENDW $0xc0, X13, X14, X14
+ VPSHUFD $0x10, X3, X13
+ VPBLENDW $0x30, X13, X14, X14
+ VMOVDQU permuted_blake_consts<>+192(SB), X15
+ VPXOR X14, X15, X15
+ VPADDD X15, X7, X7
+ VPSHUFD $0x04, X0, X14
+ VPSHUFD $0x01, X2, X13
+ VPBLENDW $0x03, X13, X14, X14
+ VPSHUFD $0x80, X3, X13
+ VPBLENDW $0xf0, X13, X14, X14
+ VMOVDQU permuted_blake_consts<>+208(SB), X15
+ VPXOR X14, X15, X15
+ VPADDD X8, X7, X7
+ VPXOR X7, X10, X10
+ VPSHUFB X5, X10, X10
+ VPADDD X10, X9, X9
+ VPXOR X9, X8, X8
+ VPSRLD $0x0c, X8, X13
+ VPSLLD $0x14, X8, X8
+ VPXOR X13, X8, X8
+ VPADDD X15, X7, X7
+ VPADDD X8, X7, X7
+ VPXOR X7, X10, X10
+ VPSHUFB X4, X10, X10
+ VPADDD X10, X9, X9
+ VPXOR X9, X8, X8
+ VPSRLD $0x07, X8, X13
+ VPSLLD $0x19, X8, X8
+ VPXOR X13, X8, X8
+
+ // Round 14 diagonal step part 1: diagonalize.
+ VPSHUFD $0x39, X8, X8
+ VPSHUFD $0x4e, X9, X9
+ VPSHUFD $0x93, X10, X10
+
+ // Round 14 diagonal step part 2: column step.
+ VPSHUFD $0x02, X0, X14
+ VPSHUFD $0x04, X1, X13
+ VPBLENDW $0x3c, X13, X14, X14
+ VPSHUFD $0xc0, X3, X13
+ VPBLENDW $0xc0, X13, X14, X14
+ VMOVDQU permuted_blake_consts<>+224(SB), X15
+ VPXOR X14, X15, X15
+ VPADDD X15, X7, X7
+ VPSHUFD $0x00, X0, X14
+ VPSHUFD $0x02, X1, X13
+ VPBLENDW $0x03, X13, X14, X14
+ VPSHUFD $0x08, X2, X13
+ VPBLENDW $0xcc, X13, X14, X14
+ VMOVDQU permuted_blake_consts<>+240(SB), X15
+ VPXOR X14, X15, X15
+ VPADDD X8, X7, X7
+ VPXOR X7, X10, X10
+ VPSHUFB X5, X10, X10
+ VPADDD X10, X9, X9
+ VPXOR X9, X8, X8
+ VPSRLD $0x0c, X8, X13
+ VPSLLD $0x14, X8, X8
+ VPXOR X13, X8, X8
+ VPADDD X15, X7, X7
+ VPADDD X8, X7, X7
+ VPXOR X7, X10, X10
+ VPSHUFB X4, X10, X10
+ VPADDD X10, X9, X9
+ VPXOR X9, X8, X8
+ VPSRLD $0x07, X8, X13
+ VPSLLD $0x19, X8, X8
+ VPXOR X13, X8, X8
+
+ // Round 14 diagonal step part 3: undiagonalize.
+ VPSHUFD $0x93, X8, X8
+ VPSHUFD $0x4e, X9, X9
+ VPSHUFD $0x39, X10, X10
+
+ // Finally the chain value is defined as:
+ // h'0 = h0^s0^v0^v8
+ // h'1 = h1^s1^v1^v9
+ // h'2 = h2^s2^v2^va
+ // h'3 = h3^s3^v3^vb
+ // h'4 = h4^s0^v4^vc
+ // h'5 = h5^s1^v5^vd
+ // h'6 = h6^s2^v6^ve
+ // h'7 = h7^s3^v7^vf
+ VPXOR X11, X7, X7
+ VPXOR X6, X7, X7
+ VPXOR X9, X7, X7
+ VPXOR X12, X8, X8
+ VPXOR X6, X8, X8
+ VPXOR X10, X8, X8
+
+ // Either terminate the loop when there are no more full blocks
+ // to compress or move the message pointer to the next block of
+ // bytes to compress, increment the message bits counter
+ // accordingly, and loop back around to compress it.
+ DECQ BX
+ JZ done
+ LEAQ 64(DX), DX
+ ADDQ $0x00000200, CX
+ JMP compressLoop
+
+done:
+ // Output the resulting chain value.
+ VMOVDQU X7, (AX)
+ VMOVDQU X8, 16(AX)
+ RET
diff --git a/vendor/github.com/decred/dcrd/crypto/blake256/internal/compress/blocks_generic.go b/vendor/github.com/decred/dcrd/crypto/blake256/internal/compress/blocks_generic.go
new file mode 100644
index 0000000..65bc306
--- /dev/null
+++ b/vendor/github.com/decred/dcrd/crypto/blake256/internal/compress/blocks_generic.go
@@ -0,0 +1,312 @@
+// Copyright (c) 2024 The Decred developers
+// Use of this source code is governed by an ISC
+// license that can be found in the LICENSE file.
+//
+// Main Go code originally written and optimized by Dave Collins May 2020.
+// Additional cleanup and comments added July 2024.
+
+package compress
+
+import (
+ "math/bits"
+)
+
+const (
+ // blockSize is the block size of the hash algorithm in bytes.
+ blockSize = 64
+
+ // blockSizeLog2 is the base-2 log of the block size. It is used to
+ // efficiently perform integer division by the block size.
+ blockSizeLog2 = 6
+)
+
+// State houses the current chain value and salt used during block compression.
+// It is housed in a separate struct in order to reduce the number of parameters
+// to help prevent register spillage on platforms with a limited number of
+// registers for better performance.
+type State struct {
+ CV [8]uint32 // the current chain value
+ S [4]uint32 // salt (zero by default)
+}
+
+// g is the quarter round function that each round applies to the 4x4 internal
+// state in the compression function.
+func g(a, b, c, d, mx, my, cx, cy uint32) (uint32, uint32, uint32, uint32) {
+ a += b + (mx ^ cx)
+ d = bits.RotateLeft32(d^a, -16)
+ c += d
+ b = bits.RotateLeft32(b^c, -12)
+ a += b + (my ^ cy)
+ d = bits.RotateLeft32(d^a, -8)
+ c += d
+ b = bits.RotateLeft32(b^c, -7)
+ return a, b, c, d
+}
+
+// blocksGeneric performs BLAKE-224 and BLAKE-256 block compression using pure
+// Go. It will compress as many full blocks as are available in the provided
+// message.
+//
+// The parameters are:
+//
+// state: the block compression state with the chain value and salt
+// msg: the padded message to compress (must be at least 64 bytes)
+// counter: the total number of message bits hashed so far
+//
+// It will panic if the provided message block does not have at least 64 bytes.
+//
+// The chain value in the provided state is updated in place.
+func blocksGeneric(state *State, msg []byte, counter uint64) {
+ // The compression func initializes the 16-word state matrix as follows:
+ //
+ // h0..h7 is the input chaining value.
+ //
+ // s0..s3 is the salt.
+ //
+ // c0..c7 are the first 8 words of the BLAKE constants defined by the
+ // specification (the first digits of π).
+ //
+ // t0 and t1 are the lower and higher order words of the 64-bit counter.
+ //
+ // |v0 v1 v2 v3| | h0 h1 h2 h3 |
+ // |v4 v5 v6 v7| | h4 h5 h6 h7 |
+ // |v8 v9 va vb| = |s0^c0 s1^c1 s2^c2 s3^c3|
+ // |vc vd ve vf| |t0^c4 t0^c5 t1^c6 t1^c7|
+ //
+ // Each round consists of 8 applications of the G function as follows:
+ // G0(v0,v4,v8,vc) G1(v1,v5,v9,vd) G2(v2,v6,va,ve) G3(v3,v7,vb,vf)
+ // G4(v0,v5,va,vf) G5(v1,v6,vb,vc) G6(v2,v7,v8,vd) G7(v3,v4,v9,ve)
+ //
+ // In other words, the G function is applied to each column of the 4x4 state
+ // and then to each of the diagonals.
+ //
+ // In addition, at each round, the message words are permuted according to
+ // the following schedule where each round is mod 10. In other words round
+ // 11 uses the same permutation as round 1, round 12 the same as round 2,
+ // etc:
+ //
+ // round 1: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
+ // round 2: 14 10 4 8 9 15 13 6 1 12 0 2 11 7 5 3
+ // round 3: 11 8 12 0 5 2 15 13 10 14 3 6 7 1 9 4
+ // round 4: 7 9 3 1 13 12 11 14 2 6 5 10 4 0 15 8
+ // round 5: 9 0 5 7 2 4 10 15 14 1 11 12 6 8 3 13
+ // round 6: 2 12 6 10 0 11 8 3 4 13 7 5 15 14 1 9
+ // round 7: 12 5 1 15 14 13 4 10 0 7 6 3 9 2 8 11
+ // round 8: 13 11 7 14 12 1 3 9 5 0 15 4 8 6 2 10
+ // round 9: 6 15 14 9 11 3 0 8 12 2 13 7 1 4 10 5
+ // round 10: 10 2 8 4 7 6 1 5 15 11 9 14 3 12 13 0
+
+ const (
+ c0, c1, c2, c3 = 0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344
+ c4, c5, c6, c7 = 0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89
+ c8, c9, ca, cb = 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c
+ cc, cd, ce, cf = 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917
+ )
+
+ // Ideally these hints wouldn't be necessary, but they do make quite a big
+ // difference in avoiding a bunch of additional bounds checks as determined
+ // by both reviewing the resulting compiled asm as well as benchmarks.
+ h := &state.CV
+ s := &state.S
+ _ = h[7] // Bounds check hint to compiler.
+ _ = s[3] // Bounds check hint to compiler.
+ for numBlocks := len(msg) >> blockSizeLog2; numBlocks > 0; numBlocks-- {
+ _ = msg[63] // Bounds check hint to compiler.
+
+ // Convert the provided message of at least 64 bytes to an array of 16
+ // 32-bit unsigned big-endian words.
+ //
+ // Note that this conversion is intentionally not in a separate function
+ // because the Go compiler unfortunately sees a function that does this
+ // as too complex to inline.
+ //
+ // It also avoids using binary.BigEndian.Uint32 for these even though it
+ // is more readable for increased performance in the critical path.
+ //
+ // Finally, this is optimized to favor arm since there currently is only
+ // a pure Go implementation for that arch while amd64 will be using the
+ // vector accelerated versions in practice. It's only slightly slower
+ // on amd64 versus various rearrangements that favor it instead.
+ m0 := uint32(msg[3]) | uint32(msg[2])<<8 | uint32(msg[1])<<16 | uint32(msg[0])<<24
+ m1 := uint32(msg[7]) | uint32(msg[6])<<8 | uint32(msg[5])<<16 | uint32(msg[4])<<24
+ m2 := uint32(msg[11]) | uint32(msg[10])<<8 | uint32(msg[9])<<16 | uint32(msg[8])<<24
+ m3 := uint32(msg[15]) | uint32(msg[14])<<8 | uint32(msg[13])<<16 | uint32(msg[12])<<24
+ m4 := uint32(msg[19]) | uint32(msg[18])<<8 | uint32(msg[17])<<16 | uint32(msg[16])<<24
+ m5 := uint32(msg[23]) | uint32(msg[22])<<8 | uint32(msg[21])<<16 | uint32(msg[20])<<24
+ m6 := uint32(msg[27]) | uint32(msg[26])<<8 | uint32(msg[25])<<16 | uint32(msg[24])<<24
+ m7 := uint32(msg[31]) | uint32(msg[30])<<8 | uint32(msg[29])<<16 | uint32(msg[28])<<24
+ m8 := uint32(msg[35]) | uint32(msg[34])<<8 | uint32(msg[33])<<16 | uint32(msg[32])<<24
+ m9 := uint32(msg[39]) | uint32(msg[38])<<8 | uint32(msg[37])<<16 | uint32(msg[36])<<24
+ m10 := uint32(msg[43]) | uint32(msg[42])<<8 | uint32(msg[41])<<16 | uint32(msg[40])<<24
+ m11 := uint32(msg[47]) | uint32(msg[46])<<8 | uint32(msg[45])<<16 | uint32(msg[44])<<24
+ m12 := uint32(msg[51]) | uint32(msg[50])<<8 | uint32(msg[49])<<16 | uint32(msg[48])<<24
+ m13 := uint32(msg[55]) | uint32(msg[54])<<8 | uint32(msg[53])<<16 | uint32(msg[52])<<24
+ m14 := uint32(msg[59]) | uint32(msg[58])<<8 | uint32(msg[57])<<16 | uint32(msg[56])<<24
+ m15 := uint32(msg[63]) | uint32(msg[62])<<8 | uint32(msg[61])<<16 | uint32(msg[60])<<24
+
+ // Round 1 plus state matrix initialization.
+ t0, t1 := uint32(counter), uint32(counter>>32)
+ v0, v4, v8, vc := g(h[0], h[4], s[0]^c0, t0^c4, m0, m1, c1, c0)
+ v1, v5, v9, vd := g(h[1], h[5], s[1]^c1, t0^c5, m2, m3, c3, c2)
+ v2, v6, va, ve := g(h[2], h[6], s[2]^c2, t1^c6, m4, m5, c5, c4)
+ v3, v7, vb, vf := g(h[3], h[7], s[3]^c3, t1^c7, m6, m7, c7, c6)
+ v0, v5, va, vf = g(v0, v5, va, vf, m8, m9, c9, c8)
+ v1, v6, vb, vc = g(v1, v6, vb, vc, m10, m11, cb, ca)
+ v2, v7, v8, vd = g(v2, v7, v8, vd, m12, m13, cd, cc)
+ v3, v4, v9, ve = g(v3, v4, v9, ve, m14, m15, cf, ce)
+
+ // Round 2 with message word and constants permutation.
+ v0, v4, v8, vc = g(v0, v4, v8, vc, m14, m10, ca, ce)
+ v1, v5, v9, vd = g(v1, v5, v9, vd, m4, m8, c8, c4)
+ v2, v6, va, ve = g(v2, v6, va, ve, m9, m15, cf, c9)
+ v3, v7, vb, vf = g(v3, v7, vb, vf, m13, m6, c6, cd)
+ v0, v5, va, vf = g(v0, v5, va, vf, m1, m12, cc, c1)
+ v1, v6, vb, vc = g(v1, v6, vb, vc, m0, m2, c2, c0)
+ v2, v7, v8, vd = g(v2, v7, v8, vd, m11, m7, c7, cb)
+ v3, v4, v9, ve = g(v3, v4, v9, ve, m5, m3, c3, c5)
+
+ // Round 3 with message word and constants permutation.
+ v0, v4, v8, vc = g(v0, v4, v8, vc, m11, m8, c8, cb)
+ v1, v5, v9, vd = g(v1, v5, v9, vd, m12, m0, c0, cc)
+ v2, v6, va, ve = g(v2, v6, va, ve, m5, m2, c2, c5)
+ v3, v7, vb, vf = g(v3, v7, vb, vf, m15, m13, cd, cf)
+ v0, v5, va, vf = g(v0, v5, va, vf, m10, m14, ce, ca)
+ v1, v6, vb, vc = g(v1, v6, vb, vc, m3, m6, c6, c3)
+ v2, v7, v8, vd = g(v2, v7, v8, vd, m7, m1, c1, c7)
+ v3, v4, v9, ve = g(v3, v4, v9, ve, m9, m4, c4, c9)
+
+ // Round 4 with message word and constants permutation.
+ v0, v4, v8, vc = g(v0, v4, v8, vc, m7, m9, c9, c7)
+ v1, v5, v9, vd = g(v1, v5, v9, vd, m3, m1, c1, c3)
+ v2, v6, va, ve = g(v2, v6, va, ve, m13, m12, cc, cd)
+ v3, v7, vb, vf = g(v3, v7, vb, vf, m11, m14, ce, cb)
+ v0, v5, va, vf = g(v0, v5, va, vf, m2, m6, c6, c2)
+ v1, v6, vb, vc = g(v1, v6, vb, vc, m5, m10, ca, c5)
+ v2, v7, v8, vd = g(v2, v7, v8, vd, m4, m0, c0, c4)
+ v3, v4, v9, ve = g(v3, v4, v9, ve, m15, m8, c8, cf)
+
+ // Round 5 with message word and constants permutation.
+ v0, v4, v8, vc = g(v0, v4, v8, vc, m9, m0, c0, c9)
+ v1, v5, v9, vd = g(v1, v5, v9, vd, m5, m7, c7, c5)
+ v2, v6, va, ve = g(v2, v6, va, ve, m2, m4, c4, c2)
+ v3, v7, vb, vf = g(v3, v7, vb, vf, m10, m15, cf, ca)
+ v0, v5, va, vf = g(v0, v5, va, vf, m14, m1, c1, ce)
+ v1, v6, vb, vc = g(v1, v6, vb, vc, m11, m12, cc, cb)
+ v2, v7, v8, vd = g(v2, v7, v8, vd, m6, m8, c8, c6)
+ v3, v4, v9, ve = g(v3, v4, v9, ve, m3, m13, cd, c3)
+
+ // Round 6 with message word and constants permutation.
+ v0, v4, v8, vc = g(v0, v4, v8, vc, m2, m12, cc, c2)
+ v1, v5, v9, vd = g(v1, v5, v9, vd, m6, m10, ca, c6)
+ v2, v6, va, ve = g(v2, v6, va, ve, m0, m11, cb, c0)
+ v3, v7, vb, vf = g(v3, v7, vb, vf, m8, m3, c3, c8)
+ v0, v5, va, vf = g(v0, v5, va, vf, m4, m13, cd, c4)
+ v1, v6, vb, vc = g(v1, v6, vb, vc, m7, m5, c5, c7)
+ v2, v7, v8, vd = g(v2, v7, v8, vd, m15, m14, ce, cf)
+ v3, v4, v9, ve = g(v3, v4, v9, ve, m1, m9, c9, c1)
+
+ // Round 7 with message word and constants permutation.
+ v0, v4, v8, vc = g(v0, v4, v8, vc, m12, m5, c5, cc)
+ v1, v5, v9, vd = g(v1, v5, v9, vd, m1, m15, cf, c1)
+ v2, v6, va, ve = g(v2, v6, va, ve, m14, m13, cd, ce)
+ v3, v7, vb, vf = g(v3, v7, vb, vf, m4, m10, ca, c4)
+ v0, v5, va, vf = g(v0, v5, va, vf, m0, m7, c7, c0)
+ v1, v6, vb, vc = g(v1, v6, vb, vc, m6, m3, c3, c6)
+ v2, v7, v8, vd = g(v2, v7, v8, vd, m9, m2, c2, c9)
+ v3, v4, v9, ve = g(v3, v4, v9, ve, m8, m11, cb, c8)
+
+ // Round 8 with message word and constants permutation.
+ v0, v4, v8, vc = g(v0, v4, v8, vc, m13, m11, cb, cd)
+ v1, v5, v9, vd = g(v1, v5, v9, vd, m7, m14, ce, c7)
+ v2, v6, va, ve = g(v2, v6, va, ve, m12, m1, c1, cc)
+ v3, v7, vb, vf = g(v3, v7, vb, vf, m3, m9, c9, c3)
+ v0, v5, va, vf = g(v0, v5, va, vf, m5, m0, c0, c5)
+ v1, v6, vb, vc = g(v1, v6, vb, vc, m15, m4, c4, cf)
+ v2, v7, v8, vd = g(v2, v7, v8, vd, m8, m6, c6, c8)
+ v3, v4, v9, ve = g(v3, v4, v9, ve, m2, m10, ca, c2)
+
+ // Round 9 with message word and constants permutation.
+ v0, v4, v8, vc = g(v0, v4, v8, vc, m6, m15, cf, c6)
+ v1, v5, v9, vd = g(v1, v5, v9, vd, m14, m9, c9, ce)
+ v2, v6, va, ve = g(v2, v6, va, ve, m11, m3, c3, cb)
+ v3, v7, vb, vf = g(v3, v7, vb, vf, m0, m8, c8, c0)
+ v0, v5, va, vf = g(v0, v5, va, vf, m12, m2, c2, cc)
+ v1, v6, vb, vc = g(v1, v6, vb, vc, m13, m7, c7, cd)
+ v2, v7, v8, vd = g(v2, v7, v8, vd, m1, m4, c4, c1)
+ v3, v4, v9, ve = g(v3, v4, v9, ve, m10, m5, c5, ca)
+
+ // Round 10 with message word and constants permutation.
+ v0, v4, v8, vc = g(v0, v4, v8, vc, m10, m2, c2, ca)
+ v1, v5, v9, vd = g(v1, v5, v9, vd, m8, m4, c4, c8)
+ v2, v6, va, ve = g(v2, v6, va, ve, m7, m6, c6, c7)
+ v3, v7, vb, vf = g(v3, v7, vb, vf, m1, m5, c5, c1)
+ v0, v5, va, vf = g(v0, v5, va, vf, m15, m11, cb, cf)
+ v1, v6, vb, vc = g(v1, v6, vb, vc, m9, m14, ce, c9)
+ v2, v7, v8, vd = g(v2, v7, v8, vd, m3, m12, cc, c3)
+ v3, v4, v9, ve = g(v3, v4, v9, ve, m13, m0, c0, cd)
+
+ // Round 11 with message word and constants permutation.
+ v0, v4, v8, vc = g(v0, v4, v8, vc, m0, m1, c1, c0)
+ v1, v5, v9, vd = g(v1, v5, v9, vd, m2, m3, c3, c2)
+ v2, v6, va, ve = g(v2, v6, va, ve, m4, m5, c5, c4)
+ v3, v7, vb, vf = g(v3, v7, vb, vf, m6, m7, c7, c6)
+ v0, v5, va, vf = g(v0, v5, va, vf, m8, m9, c9, c8)
+ v1, v6, vb, vc = g(v1, v6, vb, vc, m10, m11, cb, ca)
+ v2, v7, v8, vd = g(v2, v7, v8, vd, m12, m13, cd, cc)
+ v3, v4, v9, ve = g(v3, v4, v9, ve, m14, m15, cf, ce)
+
+ // Round 12 with message word and constants permutation.
+ v0, v4, v8, vc = g(v0, v4, v8, vc, m14, m10, ca, ce)
+ v1, v5, v9, vd = g(v1, v5, v9, vd, m4, m8, c8, c4)
+ v2, v6, va, ve = g(v2, v6, va, ve, m9, m15, cf, c9)
+ v3, v7, vb, vf = g(v3, v7, vb, vf, m13, m6, c6, cd)
+ v0, v5, va, vf = g(v0, v5, va, vf, m1, m12, cc, c1)
+ v1, v6, vb, vc = g(v1, v6, vb, vc, m0, m2, c2, c0)
+ v2, v7, v8, vd = g(v2, v7, v8, vd, m11, m7, c7, cb)
+ v3, v4, v9, ve = g(v3, v4, v9, ve, m5, m3, c3, c5)
+
+ // Round 13 with message word and constants permutation.
+ v0, v4, v8, vc = g(v0, v4, v8, vc, m11, m8, c8, cb)
+ v1, v5, v9, vd = g(v1, v5, v9, vd, m12, m0, c0, cc)
+ v2, v6, va, ve = g(v2, v6, va, ve, m5, m2, c2, c5)
+ v3, v7, vb, vf = g(v3, v7, vb, vf, m15, m13, cd, cf)
+ v0, v5, va, vf = g(v0, v5, va, vf, m10, m14, ce, ca)
+ v1, v6, vb, vc = g(v1, v6, vb, vc, m3, m6, c6, c3)
+ v2, v7, v8, vd = g(v2, v7, v8, vd, m7, m1, c1, c7)
+ v3, v4, v9, ve = g(v3, v4, v9, ve, m9, m4, c4, c9)
+
+ // Round 14 with message word and constants permutation.
+ v0, v4, v8, vc = g(v0, v4, v8, vc, m7, m9, c9, c7)
+ v1, v5, v9, vd = g(v1, v5, v9, vd, m3, m1, c1, c3)
+ v2, v6, va, ve = g(v2, v6, va, ve, m13, m12, cc, cd)
+ v3, v7, vb, vf = g(v3, v7, vb, vf, m11, m14, ce, cb)
+ v0, v5, va, vf = g(v0, v5, va, vf, m2, m6, c6, c2)
+ v1, v6, vb, vc = g(v1, v6, vb, vc, m5, m10, ca, c5)
+ v2, v7, v8, vd = g(v2, v7, v8, vd, m4, m0, c0, c4)
+ v3, v4, v9, ve = g(v3, v4, v9, ve, m15, m8, c8, cf)
+
+ // Finally the output is defined as:
+ //
+ // h'0 = h0^s0^v0^v8
+ // h'1 = h1^s1^v1^v9
+ // h'2 = h2^s2^v2^va
+ // h'3 = h3^s3^v3^vb
+ // h'4 = h4^s0^v4^vc
+ // h'5 = h5^s1^v5^vd
+ // h'6 = h6^s2^v6^ve
+ // h'7 = h7^s3^v7^vf
+ h[0] ^= s[0] ^ v0 ^ v8
+ h[1] ^= s[1] ^ v1 ^ v9
+ h[2] ^= s[2] ^ v2 ^ va
+ h[3] ^= s[3] ^ v3 ^ vb
+ h[4] ^= s[0] ^ v4 ^ vc
+ h[5] ^= s[1] ^ v5 ^ vd
+ h[6] ^= s[2] ^ v6 ^ ve
+ h[7] ^= s[3] ^ v7 ^ vf
+
+ // Move to the next message and increase the message bits counter
+ // accordingly.
+ msg = msg[blockSize:]
+ counter += blockSize << 3
+ }
+}
diff --git a/vendor/github.com/decred/dcrd/crypto/blake256/internal/compress/blocks_noasm.go b/vendor/github.com/decred/dcrd/crypto/blake256/internal/compress/blocks_noasm.go
new file mode 100644
index 0000000..7c6fabc
--- /dev/null
+++ b/vendor/github.com/decred/dcrd/crypto/blake256/internal/compress/blocks_noasm.go
@@ -0,0 +1,25 @@
+// Copyright (c) 2024 The Decred developers
+// Use of this source code is governed by an ISC
+// license that can be found in the LICENSE file.
+//
+// Automatic selection originally written by Dave Collins July 2024.
+
+//go:build !amd64 || purego
+
+package compress
+
+// Blocks performs BLAKE-224 and BLAKE-256 block compression using pure Go. It
+// will compress as many full blocks as are available in the provided message.
+//
+// The parameters are:
+//
+// state: the block compression state with the chain value and salt
+// msg: the padded message to compress (must be at least 64 bytes)
+// counter: the total number of message bits hashed so far
+//
+// It will panic if the provided message block does not have at least 64 bytes.
+//
+// The chain value in the passed state is updated in place.
+func Blocks(state *State, msg []byte, counter uint64) {
+ blocksGeneric(state, msg, counter)
+}
diff --git a/vendor/github.com/decred/dcrd/crypto/blake256/internal/compress/blocksisa_amd64.go b/vendor/github.com/decred/dcrd/crypto/blake256/internal/compress/blocksisa_amd64.go
new file mode 100644
index 0000000..4083ece
--- /dev/null
+++ b/vendor/github.com/decred/dcrd/crypto/blake256/internal/compress/blocksisa_amd64.go
@@ -0,0 +1,35 @@
+// Copyright (c) 2024 The Decred developers
+// Use of this source code is governed by an ISC
+// license that can be found in the LICENSE file.
+//
+// Automatic selection originally written by Dave Collins July 2024.
+
+//go:build !purego
+
+package compress
+
+// Blocks performs BLAKE-224 and BLAKE-256 block compression using processor
+// specific vector extensions when available. It will compress as many full
+// blocks as are available in the provided message.
+//
+// The parameters are:
+//
+// state: the block compression state with the chain value and salt
+// msg: the padded message to compress (must be at least 64 bytes)
+// counter: the total number of message bits hashed so far
+//
+// It will panic if the provided message block does not have at least 64 bytes.
+//
+// The chain value in the passed state is updated in place.
+func Blocks(state *State, msg []byte, counter uint64) {
+ switch {
+ case hasAVX:
+ blocksAVX(state, msg, counter)
+ case hasSSE41:
+ blocksSSE41(state, msg, counter)
+ case hasSSE2:
+ blocksSSE2(state, msg, counter)
+ default:
+ blocksGeneric(state, msg, counter)
+ }
+}
diff --git a/vendor/github.com/decred/dcrd/crypto/blake256/internal/compress/cpu_amd64.go b/vendor/github.com/decred/dcrd/crypto/blake256/internal/compress/cpu_amd64.go
new file mode 100644
index 0000000..46b66f3
--- /dev/null
+++ b/vendor/github.com/decred/dcrd/crypto/blake256/internal/compress/cpu_amd64.go
@@ -0,0 +1,182 @@
+// Copyright (c) 2024 The Decred developers
+// Use of this source code is governed by an ISC
+// license that can be found in the LICENSE file.
+//
+// Feature detection originally written by Dave Collins Feb 2019. Additional
+// cleanup and comments added Jul 2024.
+
+//go:build !purego
+
+package compress
+
+import (
+ "os"
+)
+
+var (
+ // features houses the result of querying the CPU and OS for supported
+ // features.
+ features = querySupportedFeatures()
+
+ hasSSE2 = features.SSE2 && os.Getenv("BLAKE256_DISABLE_SSE2") != "1"
+ hasSSE41 = features.SSE41 && os.Getenv("BLAKE256_DISABLE_SSE41") != "1"
+ hasAVX = features.AVX && os.Getenv("BLAKE256_DISABLE_AVX") != "1"
+)
+
+// supportsCPUID returns true when the CPU supports the CPUID opcode.
+//
+//go:noescape
+func supportsCPUID() bool
+
+// cpuid provides access to the CPUID opcode.
+//
+//go:noescape
+func cpuid(eaxIn, ecxIn uint32) (eax, ebx, ecx, edx uint32)
+
+// xgetbv provides access to the XGETBV opcode to read the contents of the
+// extended control register with ECX = 0x00.
+//
+//go:noescape
+func xgetbv() (eax uint32)
+
+// isBitSet returns whether or not the provided bit is set in the given test
+// value.
+func isBitSet(testVal uint32, bit uint8) bool {
+ return testVal>>bit&1 == 1
+}
+
+// supportedFeatures houses flags that specify whether or not various features
+// are supported by the CPU.
+type supportedFeatures struct {
+ SSE2 bool
+ SSE41 bool
+ AVX bool
+ AVX2 bool
+}
+
+// querySupportedFeatures returns the result of querying the CPU and OS to
+// determine supported features.
+func querySupportedFeatures() supportedFeatures {
+ // Per CPUID—CPU Identification in Chapter 3 of the Intel 64 and IA-32
+ // Architectures Software Developer's Manual, Volume 2A:
+ //
+ // "The ID flag (bit 21) in the EFLAGS register indicates support for the
+ // CPUID instruction. If a software procedure can set and clear this flag,
+ // the processor executing the procedure supports the CPUID instruction.
+ // This instruction operates the same in non-64-bit modes and 64-bit mode.
+ //
+ // CPUID returns processor identification and feature information in the
+ // EAX, EBX, ECX, and EDX registers. The output is dependent on the
+ // contents of the EAX register upon execution (in some cases, ECX as
+ // well)."
+ //
+ // The inputs and outputs for determining various levels of SIMD support
+ // that are likely relevant to BLAKE are:
+ //
+ // Initial EAX Value | Output
+ // ------------------|------------------------------------------------
+ // 0x00 | EAX = Maximum Input Value for Basic CPUID Info.
+ // -------------------------------------------------------------------
+ // 0x01 | ECX = Feature Information
+ // | Bit 0 = Streaming SIMD Extensions 3 (SSE3)
+ // | Bit 9 = Supplemental SSE3 (SSSE3)
+ // | Bit 19 = Streaming SIMD Extensions 4.1 (SSE4.1)
+ // | Bit 20 = Streaming SIMD Extensions 4.2 (SSE4.2)
+ // | Bit 27 = OS sets to enable XSAVE features (OSXSAVE)
+ // | Bit 28 = Advanced Vector Extensions (AVX)
+ // | EDX = Feature Information
+ // | Bit 25 = Streaming SIMD Extensions (SSE)
+ // | Bit 26 = Streaming SIMD Extensions 2 (SSE2)
+ // -------------------------------------------------------------------
+ // 0x07 | EBX = Feature Information
+ // | Bit 5 = Advanced Vector Extensions 2 (AVX2)
+ // | Bit 16 = AVX-512 Foundation (AVX512F)
+ // | Bit 17 = AVX-512 Double and Quadword (AVX512DQ)
+ // | Bit 30 = AVX-512 Byte and Word (AVX512BW)
+ // | Bit 31 = AVX-512 Vector Length Extensions (AVX512VL)
+ //
+ // Note that all SSE and AVX variants also require operating system support
+ // in order to properly save the additional state when doing context
+ // switches. Starting with AVX, this is signaled by the OS by setting bits
+ // in the extended control register which itself requires CPU support as
+ // specified by the OSXSAVE bit in the table above.
+ //
+ // Per Chapter 13 of the Intel 64 and IA-32 Architectures Software
+ // Developer’s Manual, Volume 1, the XGETBV opcode is used to obtain the
+ // aforementioned extended control register (XCR). Per the "XSAVE-SUPPORTED
+ // FEATURES AND STATE-COMPONENT BITMAPS" section, the relevant bits for
+ // AVX/AVX-512 support are:
+ //
+ // XCR | Output
+ // -----|------------------------------------------------
+ // 0x00 | EAX
+ // | Bit 1 = SSE state (XMM registers)
+ // | Bit 2 = AVX state (YMM registers)
+ // | Bits 5-7 = AVX-512 state components
+ // | Bit 5 = Opmask state (K0-K7 registers)
+ // | Bit 6 = ZMM high 256 state (upper 256 bits of ZMM0-ZMM15 registers)
+ // | Bit 7 = High 16 ZMM state (ZMM16-ZMM31 registers)
+ const (
+ eaxInputQueryMax = 0x00
+ eaxInputQueryFeatureInfo = 0x01
+ eaxInputQueryExtFeatFlags = 0x07
+
+ ecx1OutputOSXSAVEBit = 27
+ edx1OutputSSE2Bit = 26
+ ecx1OutputSSE41Bit = 19
+ ecx1OutputAVXBit = 28
+ ebx7OutputAVX2Bit = 5
+
+ xgbvEaxOutputSSEStateBit = 1
+ xgbvEaxOutputAVXStateBit = 2
+ )
+
+ // Nothing to do if the CPU somehow does not support CPUID. Go probably
+ // won't even run on such a CPU, but as the Intel manual states, it is
+ // technically required to check if CPUID is supported before querying it
+ // and it's best to be safe.
+ var features supportedFeatures
+ if !supportsCPUID() {
+ return features
+ }
+
+ // Perform initial query to determine the max CPUID input value since the
+ // remaining checks are only valid if the CPU at least supports querying
+ // them to begin with.
+ maxEAXInput, _, _, _ := cpuid(eaxInputQueryMax, 0)
+ if maxEAXInput < eaxInputQueryFeatureInfo {
+ return features
+ }
+
+ // Query basic feature info to determine if the CPU supports SSE2/SSE4.1.
+ //
+ // Note that SSE2 is always active on amd64, so checking for it could
+ // probably technically be skipped, but it doesn't really cost anything
+ // extra to check for it and checking is more correct.
+ _, _, ecx, edx := cpuid(eaxInputQueryFeatureInfo, 0)
+ features.SSE2 = isBitSet(edx, edx1OutputSSE2Bit)
+ features.SSE41 = isBitSet(ecx, ecx1OutputSSE41Bit)
+ hasOSXSAVE := isBitSet(ecx, ecx1OutputOSXSAVEBit)
+
+ // Query basic feature info to determine AVX support as well as if the OS
+ // supports AVX/AVX2. See the description above for details.
+ var osSupportsAVX bool
+ if hasOSXSAVE {
+ eax := xgetbv()
+ osSupportsSSE := isBitSet(eax, xgbvEaxOutputSSEStateBit)
+ osSupportsAVX = osSupportsSSE && isBitSet(eax, xgbvEaxOutputAVXStateBit)
+ }
+ features.AVX = isBitSet(ecx, ecx1OutputAVXBit) && osSupportsAVX
+
+ // Querying the supported feature info for AVX2 is only valid if the CPU at
+ // least supports querying it to begin with.
+ if maxEAXInput < eaxInputQueryExtFeatFlags {
+ return features
+ }
+
+ // Query extended feature info to determine AVX2 support.
+ _, ebx, _, _ := cpuid(eaxInputQueryExtFeatFlags, 0)
+ features.AVX2 = isBitSet(ebx, ebx7OutputAVX2Bit) && osSupportsAVX
+
+ return features
+}
diff --git a/vendor/github.com/decred/dcrd/crypto/blake256/internal/compress/cpu_amd64.s b/vendor/github.com/decred/dcrd/crypto/blake256/internal/compress/cpu_amd64.s
new file mode 100644
index 0000000..48c22bd
--- /dev/null
+++ b/vendor/github.com/decred/dcrd/crypto/blake256/internal/compress/cpu_amd64.s
@@ -0,0 +1,62 @@
+// Copyright (c) 2024 The Decred developers
+// Use of this source code is governed by an ISC
+// license that can be found in the LICENSE file.
+//
+// Feature detection originally written by Dave Collins Feb 2019.
+
+//go:build !purego
+
+#include "textflag.h"
+
+// func supportsCPUID() bool
+TEXT ·supportsCPUID(SB), $8-4
+ // Per the Intel 64 and IA-32 Architectures Software Developer's Manual,
+ // CPUID is supported if bit 21 of the EFLAGS register can be modified.
+ //
+ // To that end, this works as follows:
+ //
+ // 1. Get the current value of EFLAGS by pushing it and popping it into AX.
+ // 2. Make a copy into BX for later comparison.
+ // 3. Toggle bit 21 (the EFLAGS ID bit) of AX.
+ // 4. Put the modified value back into EFLAGS by pushing it and popping it
+ // into EFLAGS. The CPU will either update bit 21 of the EFLAGS with the
+ // modified value when it supports CPUID or leave it unmodified when it
+ // does not.
+ // 5. Get the potentially modified value of EFLAGS by pushing it and popping
+ // it into AX.
+ // 6. Compare the original and potentially modified value (aka AX vs BX)
+ // 7. CPUID is supported when they do not match since bit 21 was able to be
+ // modified.
+ PUSHFQ
+ POPQ AX
+ MOVQ AX, BX
+ XORQ $0x200000, AX
+ PUSHQ AX
+ POPFQ
+ PUSHFQ
+ POPQ AX
+ CMPQ AX, BX
+ JE nocpuid
+ MOVB $1, ret+0(FP)
+ RET
+nocpuid:
+ MOVB $0, ret+0(FP)
+ RET
+
+// func cpuid(eaxIn, ecxIn uint32) (eax, ebx, ecx, edx uint32)
+TEXT ·cpuid(SB), NOSPLIT, $0-24
+ MOVL eaxIn+0(FP), AX
+ MOVL ecxIn+4(FP), CX
+ CPUID
+ MOVL AX, eax+8(FP)
+ MOVL BX, ebx+12(FP)
+ MOVL CX, ecx+16(FP)
+ MOVL DX, edx+20(FP)
+ RET
+
+// func xgetbv() (eax uint32)
+TEXT ·xgetbv(SB), NOSPLIT, $0-4
+ MOVL $0, CX
+ XGETBV
+ MOVL AX, eax+0(FP)
+ RET
diff --git a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/LICENSE b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/LICENSE
new file mode 100644
index 0000000..fdf6d88
--- /dev/null
+++ b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/LICENSE
@@ -0,0 +1,17 @@
+ISC License
+
+Copyright (c) 2013-2017 The btcsuite developers
+Copyright (c) 2015-2024 The Decred developers
+Copyright (c) 2017 The Lightning Network Developers
+
+Permission to use, copy, modify, and distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
diff --git a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/README.md b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/README.md
new file mode 100644
index 0000000..b84bcdb
--- /dev/null
+++ b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/README.md
@@ -0,0 +1,72 @@
+secp256k1
+=========
+
+[![Build Status](https://github.com/decred/dcrd/workflows/Build%20and%20Test/badge.svg)](https://github.com/decred/dcrd/actions)
+[![ISC License](https://img.shields.io/badge/license-ISC-blue.svg)](http://copyfree.org)
+[![Doc](https://img.shields.io/badge/doc-reference-blue.svg)](https://pkg.go.dev/github.com/decred/dcrd/dcrec/secp256k1/v4)
+
+Package secp256k1 implements optimized secp256k1 elliptic curve operations.
+
+This package provides an optimized pure Go implementation of elliptic curve
+cryptography operations over the secp256k1 curve as well as data structures and
+functions for working with public and private secp256k1 keys. See
+https://www.secg.org/sec2-v2.pdf for details on the standard.
+
+In addition, sub packages are provided to produce, verify, parse, and serialize
+ECDSA signatures and EC-Schnorr-DCRv0 (a custom Schnorr-based signature scheme
+specific to Decred) signatures. See the README.md files in the relevant sub
+packages for more details about those aspects.
+
+An overview of the features provided by this package are as follows:
+
+- Private key generation, serialization, and parsing
+- Public key generation, serialization and parsing per ANSI X9.62-1998
+ - Parses uncompressed, compressed, and hybrid public keys
+ - Serializes uncompressed and compressed public keys
+- Specialized types for performing optimized and constant time field operations
+ - `FieldVal` type for working modulo the secp256k1 field prime
+ - `ModNScalar` type for working modulo the secp256k1 group order
+- Elliptic curve operations in Jacobian projective coordinates
+ - Point addition
+ - Point doubling
+ - Scalar multiplication with an arbitrary point
+ - Scalar multiplication with the base point (group generator)
+- Point decompression from a given x coordinate
+- Nonce generation via RFC6979 with support for extra data and version
+ information that can be used to prevent nonce reuse between signing algorithms
+
+It also provides an implementation of the Go standard library `crypto/elliptic`
+`Curve` interface via the `S256` function so that it may be used with other
+packages in the standard library such as `crypto/tls`, `crypto/x509`, and
+`crypto/ecdsa`. However, in the case of ECDSA, it is highly recommended to use
+the `ecdsa` sub package of this package instead since it is optimized
+specifically for secp256k1 and is significantly faster as a result.
+
+Although this package was primarily written for dcrd, it has intentionally been
+designed so it can be used as a standalone package for any projects needing to
+use optimized secp256k1 elliptic curve cryptography.
+
+Finally, a comprehensive suite of tests is provided to provide a high level of
+quality assurance.
+
+## secp256k1 use in Decred
+
+At the time of this writing, the primary public key cryptography in widespread
+use on the Decred network used to secure coins is based on elliptic curves
+defined by the secp256k1 domain parameters.
+
+## Installation and Updating
+
+This package is part of the `github.com/decred/dcrd/dcrec/secp256k1/v4` module.
+Use the standard go tooling for working with modules to incorporate it.
+
+## Examples
+
+* [Encryption](https://pkg.go.dev/github.com/decred/dcrd/dcrec/secp256k1/v4#example-package-EncryptDecryptMessage)
+ Demonstrates encrypting and decrypting a message using a shared key derived
+ through ECDHE.
+
+## License
+
+Package secp256k1 is licensed under the [copyfree](http://copyfree.org) ISC
+License.
diff --git a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/compressedbytepoints.go b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/compressedbytepoints.go
new file mode 100644
index 0000000..bb0b41f
--- /dev/null
+++ b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/compressedbytepoints.go
@@ -0,0 +1,18 @@
+// Copyright (c) 2015 The btcsuite developers
+// Copyright (c) 2015-2022 The Decred developers
+// Use of this source code is governed by an ISC
+// license that can be found in the LICENSE file.
+
+package secp256k1
+
+// Auto-generated file (see genprecomps.go)
+// DO NOT EDIT
+
+var compressedBytePoints = "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"
+
+// Set accessor to a real function.
+func init() {
+ compressedBytePointsFn = func() string {
+ return compressedBytePoints
+ }
+}
diff --git a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/curve.go b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/curve.go
new file mode 100644
index 0000000..4100500
--- /dev/null
+++ b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/curve.go
@@ -0,0 +1,1291 @@
+// Copyright (c) 2015-2024 The Decred developers
+// Copyright 2013-2014 The btcsuite developers
+// Use of this source code is governed by an ISC
+// license that can be found in the LICENSE file.
+
+package secp256k1
+
+import (
+ "encoding/hex"
+ "math/bits"
+)
+
+// References:
+// [SECG]: Recommended Elliptic Curve Domain Parameters
+// https://www.secg.org/sec2-v2.pdf
+//
+// [GECC]: Guide to Elliptic Curve Cryptography (Hankerson, Menezes, Vanstone)
+//
+// [BRID]: On Binary Representations of Integers with Digits -1, 0, 1
+// (Prodinger, Helmut)
+//
+// [STWS]: Secure-TWS: Authenticating Node to Multi-user Communication in
+// Shared Sensor Networks (Oliveira, Leonardo B. et al)
+
+// All group operations are performed using Jacobian coordinates. For a given
+// (x, y) position on the curve, the Jacobian coordinates are (x1, y1, z1)
+// where x = x1/z1^2 and y = y1/z1^3.
+
+// hexToFieldVal converts the passed hex string into a FieldVal and will panic
+// if there is an error. This is only provided for the hard-coded constants so
+// errors in the source code can be detected. It will only (and must only) be
+// called with hard-coded values.
+func hexToFieldVal(s string) *FieldVal {
+ b, err := hex.DecodeString(s)
+ if err != nil {
+ panic("invalid hex in source file: " + s)
+ }
+ var f FieldVal
+ if overflow := f.SetByteSlice(b); overflow {
+ panic("hex in source file overflows mod P: " + s)
+ }
+ return &f
+}
+
+// hexToModNScalar converts the passed hex string into a ModNScalar and will
+// panic if there is an error. This is only provided for the hard-coded
+// constants so errors in the source code can be detected. It will only (and
+// must only) be called with hard-coded values.
+func hexToModNScalar(s string) *ModNScalar {
+ var isNegative bool
+ if len(s) > 0 && s[0] == '-' {
+ isNegative = true
+ s = s[1:]
+ }
+ if len(s)%2 != 0 {
+ s = "0" + s
+ }
+ b, err := hex.DecodeString(s)
+ if err != nil {
+ panic("invalid hex in source file: " + s)
+ }
+ var scalar ModNScalar
+ if overflow := scalar.SetByteSlice(b); overflow {
+ panic("hex in source file overflows mod N scalar: " + s)
+ }
+ if isNegative {
+ scalar.Negate()
+ }
+ return &scalar
+}
+
+var (
+ // The following constants are used to accelerate scalar point
+ // multiplication through the use of the endomorphism:
+ //
+ // φ(Q) ⟼ λ*Q = (β*Q.x mod p, Q.y)
+ //
+ // See the code in the deriveEndomorphismParams function in genprecomps.go
+ // for details on their derivation.
+ //
+ // Additionally, see the scalar multiplication function in this file for
+ // details on how they are used.
+ endoNegLambda = hexToModNScalar("-5363ad4cc05c30e0a5261c028812645a122e22ea20816678df02967c1b23bd72")
+ endoBeta = hexToFieldVal("7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee")
+ endoNegB1 = hexToModNScalar("e4437ed6010e88286f547fa90abfe4c3")
+ endoNegB2 = hexToModNScalar("-3086d221a7d46bcde86c90e49284eb15")
+ endoZ1 = hexToModNScalar("3086d221a7d46bcde86c90e49284eb153daa8a1471e8ca7f")
+ endoZ2 = hexToModNScalar("e4437ed6010e88286f547fa90abfe4c4221208ac9df506c6")
+
+ // Alternatively, the following parameters are valid as well, however,
+ // benchmarks show them to be about 2% slower in practice.
+ // endoNegLambda = hexToModNScalar("-ac9c52b33fa3cf1f5ad9e3fd77ed9ba4a880b9fc8ec739c2e0cfc810b51283ce")
+ // endoBeta = hexToFieldVal("851695d49a83f8ef919bb86153cbcb16630fb68aed0a766a3ec693d68e6afa40")
+ // endoNegB1 = hexToModNScalar("3086d221a7d46bcde86c90e49284eb15")
+ // endoNegB2 = hexToModNScalar("-114ca50f7a8e2f3f657c1108d9d44cfd8")
+ // endoZ1 = hexToModNScalar("114ca50f7a8e2f3f657c1108d9d44cfd95fbc92c10fddd145")
+ // endoZ2 = hexToModNScalar("3086d221a7d46bcde86c90e49284eb153daa8a1471e8ca7f")
+)
+
+// JacobianPoint is an element of the group formed by the secp256k1 curve in
+// Jacobian projective coordinates and thus represents a point on the curve.
+type JacobianPoint struct {
+ // The X coordinate in Jacobian projective coordinates. The affine point is
+ // X/z^2.
+ X FieldVal
+
+ // The Y coordinate in Jacobian projective coordinates. The affine point is
+ // Y/z^3.
+ Y FieldVal
+
+ // The Z coordinate in Jacobian projective coordinates.
+ Z FieldVal
+}
+
+// MakeJacobianPoint returns a Jacobian point with the provided X, Y, and Z
+// coordinates.
+func MakeJacobianPoint(x, y, z *FieldVal) JacobianPoint {
+ var p JacobianPoint
+ p.X.Set(x)
+ p.Y.Set(y)
+ p.Z.Set(z)
+ return p
+}
+
+// Set sets the Jacobian point to the provided point.
+func (p *JacobianPoint) Set(other *JacobianPoint) {
+ p.X.Set(&other.X)
+ p.Y.Set(&other.Y)
+ p.Z.Set(&other.Z)
+}
+
+// ToAffine reduces the Z value of the existing point to 1 effectively
+// making it an affine coordinate in constant time. The point will be
+// normalized.
+func (p *JacobianPoint) ToAffine() {
+ // Inversions are expensive and both point addition and point doubling
+ // are faster when working with points that have a z value of one. So,
+ // if the point needs to be converted to affine, go ahead and normalize
+ // the point itself at the same time as the calculation is the same.
+ var zInv, tempZ FieldVal
+ zInv.Set(&p.Z).Inverse() // zInv = Z^-1
+ tempZ.SquareVal(&zInv) // tempZ = Z^-2
+ p.X.Mul(&tempZ) // X = X/Z^2 (mag: 1)
+ p.Y.Mul(tempZ.Mul(&zInv)) // Y = Y/Z^3 (mag: 1)
+ p.Z.SetInt(1) // Z = 1 (mag: 1)
+
+ // Normalize the x and y values.
+ p.X.Normalize()
+ p.Y.Normalize()
+}
+
+// addZ1AndZ2EqualsOne adds two Jacobian points that are already known to have
+// z values of 1 and stores the result in the provided result param. That is to
+// say result = p1 + p2. It performs faster addition than the generic add
+// routine since less arithmetic is needed due to the ability to avoid the z
+// value multiplications.
+//
+// NOTE: The points must be normalized for this function to return the correct
+// result. The resulting point will be normalized.
+func addZ1AndZ2EqualsOne(p1, p2, result *JacobianPoint) {
+ // To compute the point addition efficiently, this implementation splits
+ // the equation into intermediate elements which are used to minimize
+ // the number of field multiplications using the method shown at:
+ // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-mmadd-2007-bl
+ //
+ // In particular it performs the calculations using the following:
+ // H = X2-X1, HH = H^2, I = 4*HH, J = H*I, r = 2*(Y2-Y1), V = X1*I
+ // X3 = r^2-J-2*V, Y3 = r*(V-X3)-2*Y1*J, Z3 = 2*H
+ //
+ // This results in a cost of 4 field multiplications, 2 field squarings,
+ // 6 field additions, and 5 integer multiplications.
+ x1, y1 := &p1.X, &p1.Y
+ x2, y2 := &p2.X, &p2.Y
+ x3, y3, z3 := &result.X, &result.Y, &result.Z
+
+ // When the x coordinates are the same for two points on the curve, the
+ // y coordinates either must be the same, in which case it is point
+ // doubling, or they are opposite and the result is the point at
+ // infinity per the group law for elliptic curve cryptography.
+ if x1.Equals(x2) {
+ if y1.Equals(y2) {
+ // Since x1 == x2 and y1 == y2, point doubling must be
+ // done, otherwise the addition would end up dividing
+ // by zero.
+ DoubleNonConst(p1, result)
+ return
+ }
+
+ // Since x1 == x2 and y1 == -y2, the sum is the point at
+ // infinity per the group law.
+ x3.SetInt(0)
+ y3.SetInt(0)
+ z3.SetInt(0)
+ return
+ }
+
+ // Calculate X3, Y3, and Z3 according to the intermediate elements
+ // breakdown above.
+ var h, i, j, r, v FieldVal
+ var negJ, neg2V, negX3 FieldVal
+ h.Set(x1).Negate(1).Add(x2) // H = X2-X1 (mag: 3)
+ i.SquareVal(&h).MulInt(4) // I = 4*H^2 (mag: 4)
+ j.Mul2(&h, &i) // J = H*I (mag: 1)
+ r.Set(y1).Negate(1).Add(y2).MulInt(2) // r = 2*(Y2-Y1) (mag: 6)
+ v.Mul2(x1, &i) // V = X1*I (mag: 1)
+ negJ.Set(&j).Negate(1) // negJ = -J (mag: 2)
+ neg2V.Set(&v).MulInt(2).Negate(2) // neg2V = -(2*V) (mag: 3)
+ x3.Set(&r).Square().Add(&negJ).Add(&neg2V) // X3 = r^2-J-2*V (mag: 6)
+ negX3.Set(x3).Negate(6) // negX3 = -X3 (mag: 7)
+ j.Mul(y1).MulInt(2).Negate(2) // J = -(2*Y1*J) (mag: 3)
+ y3.Set(&v).Add(&negX3).Mul(&r).Add(&j) // Y3 = r*(V-X3)-2*Y1*J (mag: 4)
+ z3.Set(&h).MulInt(2) // Z3 = 2*H (mag: 6)
+
+ // Normalize the resulting field values as needed.
+ x3.Normalize()
+ y3.Normalize()
+ z3.Normalize()
+}
+
+// addZ1EqualsZ2 adds two Jacobian points that are already known to have the
+// same z value and stores the result in the provided result param. That is to
+// say result = p1 + p2. It performs faster addition than the generic add
+// routine since less arithmetic is needed due to the known equivalence.
+//
+// NOTE: The points must be normalized for this function to return the correct
+// result. The resulting point will be normalized.
+func addZ1EqualsZ2(p1, p2, result *JacobianPoint) {
+ // To compute the point addition efficiently, this implementation splits
+ // the equation into intermediate elements which are used to minimize
+ // the number of field multiplications using a slightly modified version
+ // of the method shown at:
+ // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-zadd-2007-m
+ //
+ // In particular it performs the calculations using the following:
+ // A = X2-X1, B = A^2, C=Y2-Y1, D = C^2, E = X1*B, F = X2*B
+ // X3 = D-E-F, Y3 = C*(E-X3)-Y1*(F-E), Z3 = Z1*A
+ //
+ // This results in a cost of 5 field multiplications, 2 field squarings,
+ // 9 field additions, and 0 integer multiplications.
+ x1, y1, z1 := &p1.X, &p1.Y, &p1.Z
+ x2, y2 := &p2.X, &p2.Y
+ x3, y3, z3 := &result.X, &result.Y, &result.Z
+
+ // When the x coordinates are the same for two points on the curve, the
+ // y coordinates either must be the same, in which case it is point
+ // doubling, or they are opposite and the result is the point at
+ // infinity per the group law for elliptic curve cryptography.
+ if x1.Equals(x2) {
+ if y1.Equals(y2) {
+ // Since x1 == x2 and y1 == y2, point doubling must be
+ // done, otherwise the addition would end up dividing
+ // by zero.
+ DoubleNonConst(p1, result)
+ return
+ }
+
+ // Since x1 == x2 and y1 == -y2, the sum is the point at
+ // infinity per the group law.
+ x3.SetInt(0)
+ y3.SetInt(0)
+ z3.SetInt(0)
+ return
+ }
+
+ // Calculate X3, Y3, and Z3 according to the intermediate elements
+ // breakdown above.
+ var a, b, c, d, e, f FieldVal
+ var negX1, negY1, negE, negX3 FieldVal
+ negX1.Set(x1).Negate(1) // negX1 = -X1 (mag: 2)
+ negY1.Set(y1).Negate(1) // negY1 = -Y1 (mag: 2)
+ a.Set(&negX1).Add(x2) // A = X2-X1 (mag: 3)
+ b.SquareVal(&a) // B = A^2 (mag: 1)
+ c.Set(&negY1).Add(y2) // C = Y2-Y1 (mag: 3)
+ d.SquareVal(&c) // D = C^2 (mag: 1)
+ e.Mul2(x1, &b) // E = X1*B (mag: 1)
+ negE.Set(&e).Negate(1) // negE = -E (mag: 2)
+ f.Mul2(x2, &b) // F = X2*B (mag: 1)
+ x3.Add2(&e, &f).Negate(2).Add(&d) // X3 = D-E-F (mag: 4)
+ negX3.Set(x3).Negate(4) // negX3 = -X3 (mag: 5)
+ y3.Set(y1).Mul(f.Add(&negE)).Negate(1) // Y3 = -(Y1*(F-E)) (mag: 2)
+ y3.Add(e.Add(&negX3).Mul(&c)) // Y3 = C*(E-X3)+Y3 (mag: 3)
+ z3.Mul2(z1, &a) // Z3 = Z1*A (mag: 1)
+
+ // Normalize the resulting field values as needed.
+ x3.Normalize()
+ y3.Normalize()
+ z3.Normalize()
+}
+
+// addZ2EqualsOne adds two Jacobian points when the second point is already
+// known to have a z value of 1 (and the z value for the first point is not 1)
+// and stores the result in the provided result param. That is to say result =
+// p1 + p2. It performs faster addition than the generic add routine since
+// less arithmetic is needed due to the ability to avoid multiplications by the
+// second point's z value.
+//
+// NOTE: The points must be normalized for this function to return the correct
+// result. The resulting point will be normalized.
+func addZ2EqualsOne(p1, p2, result *JacobianPoint) {
+ // To compute the point addition efficiently, this implementation splits
+ // the equation into intermediate elements which are used to minimize
+ // the number of field multiplications using the method shown at:
+ // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-madd-2007-bl
+ //
+ // In particular it performs the calculations using the following:
+ // Z1Z1 = Z1^2, U2 = X2*Z1Z1, S2 = Y2*Z1*Z1Z1, H = U2-X1, HH = H^2,
+ // I = 4*HH, J = H*I, r = 2*(S2-Y1), V = X1*I
+ // X3 = r^2-J-2*V, Y3 = r*(V-X3)-2*Y1*J, Z3 = (Z1+H)^2-Z1Z1-HH
+ //
+ // This results in a cost of 7 field multiplications, 4 field squarings,
+ // 9 field additions, and 4 integer multiplications.
+ x1, y1, z1 := &p1.X, &p1.Y, &p1.Z
+ x2, y2 := &p2.X, &p2.Y
+ x3, y3, z3 := &result.X, &result.Y, &result.Z
+
+ // When the x coordinates are the same for two points on the curve, the
+ // y coordinates either must be the same, in which case it is point
+ // doubling, or they are opposite and the result is the point at
+ // infinity per the group law for elliptic curve cryptography. Since
+ // any number of Jacobian coordinates can represent the same affine
+ // point, the x and y values need to be converted to like terms. Due to
+ // the assumption made for this function that the second point has a z
+ // value of 1 (z2=1), the first point is already "converted".
+ var z1z1, u2, s2 FieldVal
+ z1z1.SquareVal(z1) // Z1Z1 = Z1^2 (mag: 1)
+ u2.Set(x2).Mul(&z1z1).Normalize() // U2 = X2*Z1Z1 (mag: 1)
+ s2.Set(y2).Mul(&z1z1).Mul(z1).Normalize() // S2 = Y2*Z1*Z1Z1 (mag: 1)
+ if x1.Equals(&u2) {
+ if y1.Equals(&s2) {
+ // Since x1 == x2 and y1 == y2, point doubling must be
+ // done, otherwise the addition would end up dividing
+ // by zero.
+ DoubleNonConst(p1, result)
+ return
+ }
+
+ // Since x1 == x2 and y1 == -y2, the sum is the point at
+ // infinity per the group law.
+ x3.SetInt(0)
+ y3.SetInt(0)
+ z3.SetInt(0)
+ return
+ }
+
+ // Calculate X3, Y3, and Z3 according to the intermediate elements
+ // breakdown above.
+ var h, hh, i, j, r, rr, v FieldVal
+ var negX1, negY1, negX3 FieldVal
+ negX1.Set(x1).Negate(1) // negX1 = -X1 (mag: 2)
+ h.Add2(&u2, &negX1) // H = U2-X1 (mag: 3)
+ hh.SquareVal(&h) // HH = H^2 (mag: 1)
+ i.Set(&hh).MulInt(4) // I = 4 * HH (mag: 4)
+ j.Mul2(&h, &i) // J = H*I (mag: 1)
+ negY1.Set(y1).Negate(1) // negY1 = -Y1 (mag: 2)
+ r.Set(&s2).Add(&negY1).MulInt(2) // r = 2*(S2-Y1) (mag: 6)
+ rr.SquareVal(&r) // rr = r^2 (mag: 1)
+ v.Mul2(x1, &i) // V = X1*I (mag: 1)
+ x3.Set(&v).MulInt(2).Add(&j).Negate(3) // X3 = -(J+2*V) (mag: 4)
+ x3.Add(&rr) // X3 = r^2+X3 (mag: 5)
+ negX3.Set(x3).Negate(5) // negX3 = -X3 (mag: 6)
+ y3.Set(y1).Mul(&j).MulInt(2).Negate(2) // Y3 = -(2*Y1*J) (mag: 3)
+ y3.Add(v.Add(&negX3).Mul(&r)) // Y3 = r*(V-X3)+Y3 (mag: 4)
+ z3.Add2(z1, &h).Square() // Z3 = (Z1+H)^2 (mag: 1)
+ z3.Add(z1z1.Add(&hh).Negate(2)) // Z3 = Z3-(Z1Z1+HH) (mag: 4)
+
+ // Normalize the resulting field values as needed.
+ x3.Normalize()
+ y3.Normalize()
+ z3.Normalize()
+}
+
+// addGeneric adds two Jacobian points without any assumptions about the z
+// values of the two points and stores the result in the provided result param.
+// That is to say result = p1 + p2. It is the slowest of the add routines due
+// to requiring the most arithmetic.
+//
+// NOTE: The points must be normalized for this function to return the correct
+// result. The resulting point will be normalized.
+func addGeneric(p1, p2, result *JacobianPoint) {
+ // To compute the point addition efficiently, this implementation splits
+ // the equation into intermediate elements which are used to minimize
+ // the number of field multiplications using the method shown at:
+ // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-add-2007-bl
+ //
+ // In particular it performs the calculations using the following:
+ // Z1Z1 = Z1^2, Z2Z2 = Z2^2, U1 = X1*Z2Z2, U2 = X2*Z1Z1, S1 = Y1*Z2*Z2Z2
+ // S2 = Y2*Z1*Z1Z1, H = U2-U1, I = (2*H)^2, J = H*I, r = 2*(S2-S1)
+ // V = U1*I
+ // X3 = r^2-J-2*V, Y3 = r*(V-X3)-2*S1*J, Z3 = ((Z1+Z2)^2-Z1Z1-Z2Z2)*H
+ //
+ // This results in a cost of 11 field multiplications, 5 field squarings,
+ // 9 field additions, and 4 integer multiplications.
+ x1, y1, z1 := &p1.X, &p1.Y, &p1.Z
+ x2, y2, z2 := &p2.X, &p2.Y, &p2.Z
+ x3, y3, z3 := &result.X, &result.Y, &result.Z
+
+ // When the x coordinates are the same for two points on the curve, the
+ // y coordinates either must be the same, in which case it is point
+ // doubling, or they are opposite and the result is the point at
+ // infinity. Since any number of Jacobian coordinates can represent the
+ // same affine point, the x and y values need to be converted to like
+ // terms.
+ var z1z1, z2z2, u1, u2, s1, s2 FieldVal
+ z1z1.SquareVal(z1) // Z1Z1 = Z1^2 (mag: 1)
+ z2z2.SquareVal(z2) // Z2Z2 = Z2^2 (mag: 1)
+ u1.Set(x1).Mul(&z2z2).Normalize() // U1 = X1*Z2Z2 (mag: 1)
+ u2.Set(x2).Mul(&z1z1).Normalize() // U2 = X2*Z1Z1 (mag: 1)
+ s1.Set(y1).Mul(&z2z2).Mul(z2).Normalize() // S1 = Y1*Z2*Z2Z2 (mag: 1)
+ s2.Set(y2).Mul(&z1z1).Mul(z1).Normalize() // S2 = Y2*Z1*Z1Z1 (mag: 1)
+ if u1.Equals(&u2) {
+ if s1.Equals(&s2) {
+ // Since x1 == x2 and y1 == y2, point doubling must be
+ // done, otherwise the addition would end up dividing
+ // by zero.
+ DoubleNonConst(p1, result)
+ return
+ }
+
+ // Since x1 == x2 and y1 == -y2, the sum is the point at
+ // infinity per the group law.
+ x3.SetInt(0)
+ y3.SetInt(0)
+ z3.SetInt(0)
+ return
+ }
+
+ // Calculate X3, Y3, and Z3 according to the intermediate elements
+ // breakdown above.
+ var h, i, j, r, rr, v FieldVal
+ var negU1, negS1, negX3 FieldVal
+ negU1.Set(&u1).Negate(1) // negU1 = -U1 (mag: 2)
+ h.Add2(&u2, &negU1) // H = U2-U1 (mag: 3)
+ i.Set(&h).MulInt(2).Square() // I = (2*H)^2 (mag: 1)
+ j.Mul2(&h, &i) // J = H*I (mag: 1)
+ negS1.Set(&s1).Negate(1) // negS1 = -S1 (mag: 2)
+ r.Set(&s2).Add(&negS1).MulInt(2) // r = 2*(S2-S1) (mag: 6)
+ rr.SquareVal(&r) // rr = r^2 (mag: 1)
+ v.Mul2(&u1, &i) // V = U1*I (mag: 1)
+ x3.Set(&v).MulInt(2).Add(&j).Negate(3) // X3 = -(J+2*V) (mag: 4)
+ x3.Add(&rr) // X3 = r^2+X3 (mag: 5)
+ negX3.Set(x3).Negate(5) // negX3 = -X3 (mag: 6)
+ y3.Mul2(&s1, &j).MulInt(2).Negate(2) // Y3 = -(2*S1*J) (mag: 3)
+ y3.Add(v.Add(&negX3).Mul(&r)) // Y3 = r*(V-X3)+Y3 (mag: 4)
+ z3.Add2(z1, z2).Square() // Z3 = (Z1+Z2)^2 (mag: 1)
+ z3.Add(z1z1.Add(&z2z2).Negate(2)) // Z3 = Z3-(Z1Z1+Z2Z2) (mag: 4)
+ z3.Mul(&h) // Z3 = Z3*H (mag: 1)
+
+ // Normalize the resulting field values as needed.
+ x3.Normalize()
+ y3.Normalize()
+ z3.Normalize()
+}
+
+// AddNonConst adds the passed Jacobian points together and stores the result in
+// the provided result param in *non-constant* time.
+//
+// NOTE: The points must be normalized for this function to return the correct
+// result. The resulting point will be normalized.
+func AddNonConst(p1, p2, result *JacobianPoint) {
+ // The point at infinity is the identity according to the group law for
+ // elliptic curve cryptography. Thus, ∞ + P = P and P + ∞ = P.
+ if (p1.X.IsZero() && p1.Y.IsZero()) || p1.Z.IsZero() {
+ result.Set(p2)
+ return
+ }
+ if (p2.X.IsZero() && p2.Y.IsZero()) || p2.Z.IsZero() {
+ result.Set(p1)
+ return
+ }
+
+ // Faster point addition can be achieved when certain assumptions are
+ // met. For example, when both points have the same z value, arithmetic
+ // on the z values can be avoided. This section thus checks for these
+ // conditions and calls an appropriate add function which is accelerated
+ // by using those assumptions.
+ isZ1One := p1.Z.IsOne()
+ isZ2One := p2.Z.IsOne()
+ switch {
+ case isZ1One && isZ2One:
+ addZ1AndZ2EqualsOne(p1, p2, result)
+ return
+ case p1.Z.Equals(&p2.Z):
+ addZ1EqualsZ2(p1, p2, result)
+ return
+ case isZ2One:
+ addZ2EqualsOne(p1, p2, result)
+ return
+ }
+
+ // None of the above assumptions are true, so fall back to generic
+ // point addition.
+ addGeneric(p1, p2, result)
+}
+
+// doubleZ1EqualsOne performs point doubling on the passed Jacobian point when
+// the point is already known to have a z value of 1 and stores the result in
+// the provided result param. That is to say result = 2*p. It performs faster
+// point doubling than the generic routine since less arithmetic is needed due
+// to the ability to avoid multiplication by the z value.
+//
+// NOTE: The resulting point will be normalized.
+func doubleZ1EqualsOne(p, result *JacobianPoint) {
+ // This function uses the assumptions that z1 is 1, thus the point
+ // doubling formulas reduce to:
+ //
+ // X3 = (3*X1^2)^2 - 8*X1*Y1^2
+ // Y3 = (3*X1^2)*(4*X1*Y1^2 - X3) - 8*Y1^4
+ // Z3 = 2*Y1
+ //
+ // To compute the above efficiently, this implementation splits the
+ // equation into intermediate elements which are used to minimize the
+ // number of field multiplications in favor of field squarings which
+ // are roughly 35% faster than field multiplications with the current
+ // implementation at the time this was written.
+ //
+ // This uses a slightly modified version of the method shown at:
+ // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-mdbl-2007-bl
+ //
+ // In particular it performs the calculations using the following:
+ // A = X1^2, B = Y1^2, C = B^2, D = 2*((X1+B)^2-A-C)
+ // E = 3*A, F = E^2, X3 = F-2*D, Y3 = E*(D-X3)-8*C
+ // Z3 = 2*Y1
+ //
+ // This results in a cost of 1 field multiplication, 5 field squarings,
+ // 6 field additions, and 5 integer multiplications.
+ x1, y1 := &p.X, &p.Y
+ x3, y3, z3 := &result.X, &result.Y, &result.Z
+ var a, b, c, d, e, f FieldVal
+ z3.Set(y1).MulInt(2) // Z3 = 2*Y1 (mag: 2)
+ a.SquareVal(x1) // A = X1^2 (mag: 1)
+ b.SquareVal(y1) // B = Y1^2 (mag: 1)
+ c.SquareVal(&b) // C = B^2 (mag: 1)
+ b.Add(x1).Square() // B = (X1+B)^2 (mag: 1)
+ d.Set(&a).Add(&c).Negate(2) // D = -(A+C) (mag: 3)
+ d.Add(&b).MulInt(2) // D = 2*(B+D)(mag: 8)
+ e.Set(&a).MulInt(3) // E = 3*A (mag: 3)
+ f.SquareVal(&e) // F = E^2 (mag: 1)
+ x3.Set(&d).MulInt(2).Negate(16) // X3 = -(2*D) (mag: 17)
+ x3.Add(&f) // X3 = F+X3 (mag: 18)
+ f.Set(x3).Negate(18).Add(&d).Normalize() // F = D-X3 (mag: 1)
+ y3.Set(&c).MulInt(8).Negate(8) // Y3 = -(8*C) (mag: 9)
+ y3.Add(f.Mul(&e)) // Y3 = E*F+Y3 (mag: 10)
+
+ // Normalize the resulting field values as needed.
+ x3.Normalize()
+ y3.Normalize()
+ z3.Normalize()
+}
+
+// doubleGeneric performs point doubling on the passed Jacobian point without
+// any assumptions about the z value and stores the result in the provided
+// result param. That is to say result = 2*p. It is the slowest of the point
+// doubling routines due to requiring the most arithmetic.
+//
+// NOTE: The resulting point will be normalized.
+func doubleGeneric(p, result *JacobianPoint) {
+ // Point doubling formula for Jacobian coordinates for the secp256k1
+ // curve:
+ //
+ // X3 = (3*X1^2)^2 - 8*X1*Y1^2
+ // Y3 = (3*X1^2)*(4*X1*Y1^2 - X3) - 8*Y1^4
+ // Z3 = 2*Y1*Z1
+ //
+ // To compute the above efficiently, this implementation splits the
+ // equation into intermediate elements which are used to minimize the
+ // number of field multiplications in favor of field squarings which
+ // are roughly 35% faster than field multiplications with the current
+ // implementation at the time this was written.
+ //
+ // This uses a slightly modified version of the method shown at:
+ // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-dbl-2009-l
+ //
+ // In particular it performs the calculations using the following:
+ // A = X1^2, B = Y1^2, C = B^2, D = 2*((X1+B)^2-A-C)
+ // E = 3*A, F = E^2, X3 = F-2*D, Y3 = E*(D-X3)-8*C
+ // Z3 = 2*Y1*Z1
+ //
+ // This results in a cost of 1 field multiplication, 5 field squarings,
+ // 6 field additions, and 5 integer multiplications.
+ x1, y1, z1 := &p.X, &p.Y, &p.Z
+ x3, y3, z3 := &result.X, &result.Y, &result.Z
+ var a, b, c, d, e, f FieldVal
+ z3.Mul2(y1, z1).MulInt(2) // Z3 = 2*Y1*Z1 (mag: 2)
+ a.SquareVal(x1) // A = X1^2 (mag: 1)
+ b.SquareVal(y1) // B = Y1^2 (mag: 1)
+ c.SquareVal(&b) // C = B^2 (mag: 1)
+ b.Add(x1).Square() // B = (X1+B)^2 (mag: 1)
+ d.Set(&a).Add(&c).Negate(2) // D = -(A+C) (mag: 3)
+ d.Add(&b).MulInt(2) // D = 2*(B+D)(mag: 8)
+ e.Set(&a).MulInt(3) // E = 3*A (mag: 3)
+ f.SquareVal(&e) // F = E^2 (mag: 1)
+ x3.Set(&d).MulInt(2).Negate(16) // X3 = -(2*D) (mag: 17)
+ x3.Add(&f) // X3 = F+X3 (mag: 18)
+ f.Set(x3).Negate(18).Add(&d).Normalize() // F = D-X3 (mag: 1)
+ y3.Set(&c).MulInt(8).Negate(8) // Y3 = -(8*C) (mag: 9)
+ y3.Add(f.Mul(&e)) // Y3 = E*F+Y3 (mag: 10)
+
+ // Normalize the resulting field values as needed.
+ x3.Normalize()
+ y3.Normalize()
+ z3.Normalize()
+}
+
+// DoubleNonConst doubles the passed Jacobian point and stores the result in the
+// provided result parameter in *non-constant* time.
+//
+// NOTE: The point must be normalized for this function to return the correct
+// result. The resulting point will be normalized.
+func DoubleNonConst(p, result *JacobianPoint) {
+ // Doubling the point at infinity is still infinity.
+ if p.Y.IsZero() || p.Z.IsZero() {
+ result.X.SetInt(0)
+ result.Y.SetInt(0)
+ result.Z.SetInt(0)
+ return
+ }
+
+ // Slightly faster point doubling can be achieved when the z value is 1
+ // by avoiding the multiplication on the z value. This section calls
+ // a point doubling function which is accelerated by using that
+ // assumption when possible.
+ if p.Z.IsOne() {
+ doubleZ1EqualsOne(p, result)
+ return
+ }
+
+ // Fall back to generic point doubling which works with arbitrary z
+ // values.
+ doubleGeneric(p, result)
+}
+
+// mulAdd64 multiplies the two passed base 2^64 digits together, adds the given
+// value to the result, and returns the 128-bit result via a (hi, lo) tuple
+// where the upper half of the bits are returned in hi and the lower half in lo.
+func mulAdd64(digit1, digit2, m uint64) (hi, lo uint64) {
+ // Note the carry on the final add is safe to discard because the maximum
+ // possible value is:
+ // (2^64 - 1)(2^64 - 1) + (2^64 - 1) = 2^128 - 2^64
+ // and:
+ // 2^128 - 2^64 < 2^128.
+ var c uint64
+ hi, lo = bits.Mul64(digit1, digit2)
+ lo, c = bits.Add64(lo, m, 0)
+ hi, _ = bits.Add64(hi, 0, c)
+ return hi, lo
+}
+
+// mulAdd64Carry multiplies the two passed base 2^64 digits together, adds both
+// the given value and carry to the result, and returns the 128-bit result via a
+// (hi, lo) tuple where the upper half of the bits are returned in hi and the
+// lower half in lo.
+func mulAdd64Carry(digit1, digit2, m, c uint64) (hi, lo uint64) {
+ // Note the carry on the high order add is safe to discard because the
+ // maximum possible value is:
+ // (2^64 - 1)(2^64 - 1) + 2*(2^64 - 1) = 2^128 - 1
+ // and:
+ // 2^128 - 1 < 2^128.
+ var c2 uint64
+ hi, lo = mulAdd64(digit1, digit2, m)
+ lo, c2 = bits.Add64(lo, c, 0)
+ hi, _ = bits.Add64(hi, 0, c2)
+ return hi, lo
+}
+
+// mul512Rsh320Round computes the full 512-bit product of the two given scalars,
+// right shifts the result by 320 bits, rounds to the nearest integer, and
+// returns the result in constant time.
+//
+// Note that despite the inputs and output being mod n scalars, the 512-bit
+// product is NOT reduced mod N prior to the right shift. This is intentional
+// because it is used for replacing division with multiplication and thus the
+// intermediate results must be done via a field extension to a larger field.
+func mul512Rsh320Round(n1, n2 *ModNScalar) ModNScalar {
+ // Convert n1 and n2 to base 2^64 digits.
+ n1Digit0 := uint64(n1.n[0]) | uint64(n1.n[1])<<32
+ n1Digit1 := uint64(n1.n[2]) | uint64(n1.n[3])<<32
+ n1Digit2 := uint64(n1.n[4]) | uint64(n1.n[5])<<32
+ n1Digit3 := uint64(n1.n[6]) | uint64(n1.n[7])<<32
+ n2Digit0 := uint64(n2.n[0]) | uint64(n2.n[1])<<32
+ n2Digit1 := uint64(n2.n[2]) | uint64(n2.n[3])<<32
+ n2Digit2 := uint64(n2.n[4]) | uint64(n2.n[5])<<32
+ n2Digit3 := uint64(n2.n[6]) | uint64(n2.n[7])<<32
+
+ // Compute the full 512-bit product n1*n2.
+ var r0, r1, r2, r3, r4, r5, r6, r7, c uint64
+
+ // Terms resulting from the product of the first digit of the second number
+ // by all digits of the first number.
+ //
+ // Note that r0 is ignored because it is not needed to compute the higher
+ // terms and it is shifted out below anyway.
+ c, _ = bits.Mul64(n2Digit0, n1Digit0)
+ c, r1 = mulAdd64(n2Digit0, n1Digit1, c)
+ c, r2 = mulAdd64(n2Digit0, n1Digit2, c)
+ r4, r3 = mulAdd64(n2Digit0, n1Digit3, c)
+
+ // Terms resulting from the product of the second digit of the second number
+ // by all digits of the first number.
+ //
+ // Note that r1 is ignored because it is no longer needed to compute the
+ // higher terms and it is shifted out below anyway.
+ c, _ = mulAdd64(n2Digit1, n1Digit0, r1)
+ c, r2 = mulAdd64Carry(n2Digit1, n1Digit1, r2, c)
+ c, r3 = mulAdd64Carry(n2Digit1, n1Digit2, r3, c)
+ r5, r4 = mulAdd64Carry(n2Digit1, n1Digit3, r4, c)
+
+ // Terms resulting from the product of the third digit of the second number
+ // by all digits of the first number.
+ //
+ // Note that r2 is ignored because it is no longer needed to compute the
+ // higher terms and it is shifted out below anyway.
+ c, _ = mulAdd64(n2Digit2, n1Digit0, r2)
+ c, r3 = mulAdd64Carry(n2Digit2, n1Digit1, r3, c)
+ c, r4 = mulAdd64Carry(n2Digit2, n1Digit2, r4, c)
+ r6, r5 = mulAdd64Carry(n2Digit2, n1Digit3, r5, c)
+
+ // Terms resulting from the product of the fourth digit of the second number
+ // by all digits of the first number.
+ //
+ // Note that r3 is ignored because it is no longer needed to compute the
+ // higher terms and it is shifted out below anyway.
+ c, _ = mulAdd64(n2Digit3, n1Digit0, r3)
+ c, r4 = mulAdd64Carry(n2Digit3, n1Digit1, r4, c)
+ c, r5 = mulAdd64Carry(n2Digit3, n1Digit2, r5, c)
+ r7, r6 = mulAdd64Carry(n2Digit3, n1Digit3, r6, c)
+
+ // At this point the upper 256 bits of the full 512-bit product n1*n2 are in
+ // r4..r7 (recall the low order results were discarded as noted above).
+ //
+ // Right shift the result 320 bits. Note that the MSB of r4 determines
+ // whether or not to round because it is the final bit that is shifted out.
+ //
+ // Also, notice that r3..r7 would also ordinarily be set to 0 as well for
+ // the full shift, but that is skipped since they are no longer used as
+ // their values are known to be zero.
+ roundBit := r4 >> 63
+ r2, r1, r0 = r7, r6, r5
+
+ // Conditionally add 1 depending on the round bit in constant time.
+ r0, c = bits.Add64(r0, roundBit, 0)
+ r1, c = bits.Add64(r1, 0, c)
+ r2, r3 = bits.Add64(r2, 0, c)
+
+ // Finally, convert the result to a mod n scalar.
+ //
+ // No modular reduction is needed because the result is guaranteed to be
+ // less than the group order given the group order is > 2^255 and the
+ // maximum possible value of the result is 2^192.
+ var result ModNScalar
+ result.n[0] = uint32(r0)
+ result.n[1] = uint32(r0 >> 32)
+ result.n[2] = uint32(r1)
+ result.n[3] = uint32(r1 >> 32)
+ result.n[4] = uint32(r2)
+ result.n[5] = uint32(r2 >> 32)
+ result.n[6] = uint32(r3)
+ result.n[7] = uint32(r3 >> 32)
+ return result
+}
+
+// splitK returns two scalars (k1 and k2) that are a balanced length-two
+// representation of the provided scalar such that k ≡ k1 + k2*λ (mod N), where
+// N is the secp256k1 group order.
+func splitK(k *ModNScalar) (ModNScalar, ModNScalar) {
+ // The ultimate goal is to decompose k into two scalars that are around
+ // half the bit length of k such that the following equation is satisfied:
+ //
+ // k1 + k2*λ ≡ k (mod n)
+ //
+ // The strategy used here is based on algorithm 3.74 from [GECC] with a few
+ // modifications to make use of the more efficient mod n scalar type, avoid
+ // some costly long divisions, and minimize the number of calculations.
+ //
+ // Start by defining a function that takes a vector v = ∈ ℤ⨯ℤ:
+ //
+ // f(v) = a + bλ (mod n)
+ //
+ // Then, find two vectors, v1 = , and v2 = in ℤ⨯ℤ such that:
+ // 1) v1 and v2 are linearly independent
+ // 2) f(v1) = f(v2) = 0
+ // 3) v1 and v2 have small Euclidean norm
+ //
+ // The vectors that satisfy these properties are found via the Euclidean
+ // algorithm and are precomputed since both n and λ are fixed values for the
+ // secp256k1 curve. See genprecomps.go for derivation details.
+ //
+ // Next, consider k as a vector in ℚ⨯ℚ and by linear algebra write:
+ //
+ // = g1*v1 + g2*v2, where g1, g2 ∈ ℚ
+ //
+ // Note that, per above, the components of vector v1 are a1 and b1 while the
+ // components of vector v2 are a2 and b2. Given the vectors v1 and v2 were
+ // generated such that a1*b2 - a2*b1 = n, solving the equation for g1 and g2
+ // yields:
+ //
+ // g1 = b2*k / n
+ // g2 = -b1*k / n
+ //
+ // Observe:
+ // = g1*v1 + g2*v2
+ // = (b2*k/n)* + (-b1*k/n)* | substitute
+ // = + <-a2*b1*k/n, -b2*b1*k/n> | scalar mul
+ // = | vector add
+ // = <[a1*b2*k - a2*b1*k]/n, 0> | simplify
+ // = | factor out k
+ // = | substitute
+ // = | simplify
+ //
+ // Now, consider an integer-valued vector v:
+ //
+ // v = c1*v1 + c2*v2, where c1, c2 ∈ ℤ (mod n)
+ //
+ // Since vectors v1 and v2 are linearly independent and were generated such
+ // that f(v1) = f(v2) = 0, all possible scalars c1 and c2 also produce a
+ // vector v such that f(v) = 0.
+ //
+ // In other words, c1 and c2 can be any integers and the resulting
+ // decomposition will still satisfy the required equation. However, since
+ // the goal is to produce a balanced decomposition that provides a
+ // performance advantage by minimizing max(k1, k2), c1 and c2 need to be
+ // integers close to g1 and g2, respectively, so the resulting vector v is
+ // an integer-valued vector that is close to .
+ //
+ // Finally, consider the vector u:
+ //
+ // u = - v
+ //
+ // It follows that f(u) = k and thus the two components of vector u satisfy
+ // the required equation:
+ //
+ // k1 + k2*λ ≡ k (mod n)
+ //
+ // Choosing c1 and c2:
+ // -------------------
+ //
+ // As mentioned above, c1 and c2 need to be integers close to g1 and g2,
+ // respectively. The algorithm in [GECC] chooses the following values:
+ //
+ // c1 = round(g1) = round(b2*k / n)
+ // c2 = round(g2) = round(-b1*k / n)
+ //
+ // However, as section 3.4.2 of [STWS] notes, the aforementioned approach
+ // requires costly long divisions that can be avoided by precomputing
+ // rounded estimates as follows:
+ //
+ // t = bitlen(n) + 1
+ // z1 = round(2^t * b2 / n)
+ // z2 = round(2^t * -b1 / n)
+ //
+ // Then, use those precomputed estimates to perform a multiplication by k
+ // along with a floored division by 2^t, which is a simple right shift by t:
+ //
+ // c1 = floor(k * z1 / 2^t) = (k * z1) >> t
+ // c2 = floor(k * z2 / 2^t) = (k * z2) >> t
+ //
+ // Finally, round up if last bit discarded in the right shift by t is set by
+ // adding 1.
+ //
+ // As a further optimization, rather than setting t = bitlen(n) + 1 = 257 as
+ // stated by [STWS], this implementation uses a higher precision estimate of
+ // t = bitlen(n) + 64 = 320 because it allows simplification of the shifts
+ // in the internal calculations that are done via uint64s and also allows
+ // the use of floor in the precomputations.
+ //
+ // Thus, the calculations this implementation uses are:
+ //
+ // z1 = floor(b2<<320 / n) | precomputed
+ // z2 = floor((-b1)<<320) / n) | precomputed
+ // c1 = ((k * z1) >> 320) + (((k * z1) >> 319) & 1)
+ // c2 = ((k * z2) >> 320) + (((k * z2) >> 319) & 1)
+ //
+ // Putting it all together:
+ // ------------------------
+ //
+ // Calculate the following vectors using the values discussed above:
+ //
+ // v = c1*v1 + c2*v2
+ // u = - v
+ //
+ // The two components of the resulting vector v are:
+ // va = c1*a1 + c2*a2
+ // vb = c1*b1 + c2*b2
+ //
+ // Thus, the two components of the resulting vector u are:
+ // k1 = k - va
+ // k2 = 0 - vb = -vb
+ //
+ // As some final optimizations:
+ //
+ // 1) Note that k1 + k2*λ ≡ k (mod n) means that k1 ≡ k - k2*λ (mod n).
+ // Therefore, the computation of va can be avoided to save two
+ // field multiplications and a field addition.
+ //
+ // 2) Since k1 = k - k2*λ = k + k2*(-λ), an additional field negation is
+ // saved by storing and using the negative version of λ.
+ //
+ // 3) Since k2 = -vb = -(c1*b1 + c2*b2) = c1*(-b1) + c2*(-b2), one more
+ // field negation is saved by storing and using the negative versions of
+ // b1 and b2.
+ //
+ // k2 = c1*(-b1) + c2*(-b2)
+ // k1 = k + k2*(-λ)
+ var k1, k2 ModNScalar
+ c1 := mul512Rsh320Round(k, endoZ1)
+ c2 := mul512Rsh320Round(k, endoZ2)
+ k2.Add2(c1.Mul(endoNegB1), c2.Mul(endoNegB2))
+ k1.Mul2(&k2, endoNegLambda).Add(k)
+ return k1, k2
+}
+
+// nafScalar represents a positive integer up to a maximum value of 2^256 - 1
+// encoded in non-adjacent form.
+//
+// NAF is a signed-digit representation where each digit can be +1, 0, or -1.
+//
+// In order to efficiently encode that information, this type uses two arrays, a
+// "positive" array where set bits represent the +1 signed digits and a
+// "negative" array where set bits represent the -1 signed digits. 0 is
+// represented by neither array having a bit set in that position.
+//
+// The Pos and Neg methods return the aforementioned positive and negative
+// arrays, respectively.
+type nafScalar struct {
+ // pos houses the positive portion of the representation. An additional
+ // byte is required for the positive portion because the NAF encoding can be
+ // up to 1 bit longer than the normal binary encoding of the value.
+ //
+ // neg houses the negative portion of the representation. Even though the
+ // additional byte is not required for the negative portion, since it can
+ // never exceed the length of the normal binary encoding of the value,
+ // keeping the same length for positive and negative portions simplifies
+ // working with the representation and allows extra conditional branches to
+ // be avoided.
+ //
+ // start and end specify the starting and ending index to use within the pos
+ // and neg arrays, respectively. This allows fixed size arrays to be used
+ // versus needing to dynamically allocate space on the heap.
+ //
+ // NOTE: The fields are defined in the order that they are to minimize the
+ // padding on 32-bit and 64-bit platforms.
+ pos [33]byte
+ start, end uint8
+ neg [33]byte
+}
+
+// Pos returns the bytes of the encoded value with bits set in the positions
+// that represent a signed digit of +1.
+func (s *nafScalar) Pos() []byte {
+ return s.pos[s.start:s.end]
+}
+
+// Neg returns the bytes of the encoded value with bits set in the positions
+// that represent a signed digit of -1.
+func (s *nafScalar) Neg() []byte {
+ return s.neg[s.start:s.end]
+}
+
+// naf takes a positive integer up to a maximum value of 2^256 - 1 and returns
+// its non-adjacent form (NAF), which is a unique signed-digit representation
+// such that no two consecutive digits are nonzero. See the documentation for
+// the returned type for details on how the representation is encoded
+// efficiently and how to interpret it
+//
+// NAF is useful in that it has the fewest nonzero digits of any signed digit
+// representation, only 1/3rd of its digits are nonzero on average, and at least
+// half of the digits will be 0.
+//
+// The aforementioned properties are particularly beneficial for optimizing
+// elliptic curve point multiplication because they effectively minimize the
+// number of required point additions in exchange for needing to perform a mix
+// of fewer point additions and subtractions and possibly one additional point
+// doubling. This is an excellent tradeoff because subtraction of points has
+// the same computational complexity as addition of points and point doubling is
+// faster than both.
+func naf(k []byte) nafScalar {
+ // Strip leading zero bytes.
+ for len(k) > 0 && k[0] == 0x00 {
+ k = k[1:]
+ }
+
+ // The non-adjacent form (NAF) of a positive integer k is an expression
+ // k = ∑_(i=0, l-1) k_i * 2^i where k_i ∈ {0,±1}, k_(l-1) != 0, and no two
+ // consecutive digits k_i are nonzero.
+ //
+ // The traditional method of computing the NAF of a positive integer is
+ // given by algorithm 3.30 in [GECC]. It consists of repeatedly dividing k
+ // by 2 and choosing the remainder so that the quotient (k−r)/2 is even
+ // which ensures the next NAF digit is 0. This requires log_2(k) steps.
+ //
+ // However, in [BRID], Prodinger notes that a closed form expression for the
+ // NAF representation is the bitwise difference 3k/2 - k/2. This is more
+ // efficient as it can be computed in O(1) versus the O(log(n)) of the
+ // traditional approach.
+ //
+ // The following code makes use of that formula to compute the NAF more
+ // efficiently.
+ //
+ // To understand the logic here, observe that the only way the NAF has a
+ // nonzero digit at a given bit is when either 3k/2 or k/2 has a bit set in
+ // that position, but not both. In other words, the result of a bitwise
+ // xor. This can be seen simply by considering that when the bits are the
+ // same, the subtraction is either 0-0 or 1-1, both of which are 0.
+ //
+ // Further, observe that the "+1" digits in the result are contributed by
+ // 3k/2 while the "-1" digits are from k/2. So, they can be determined by
+ // taking the bitwise and of each respective value with the result of the
+ // xor which identifies which bits are nonzero.
+ //
+ // Using that information, this loops backwards from the least significant
+ // byte to the most significant byte while performing the aforementioned
+ // calculations by propagating the potential carry and high order bit from
+ // the next word during the right shift.
+ kLen := len(k)
+ var result nafScalar
+ var carry uint8
+ for byteNum := kLen - 1; byteNum >= 0; byteNum-- {
+ // Calculate k/2. Notice the carry from the previous word is added and
+ // the low order bit from the next word is shifted in accordingly.
+ kc := uint16(k[byteNum]) + uint16(carry)
+ var nextWord uint8
+ if byteNum > 0 {
+ nextWord = k[byteNum-1]
+ }
+ halfK := kc>>1 | uint16(nextWord<<7)
+
+ // Calculate 3k/2 and determine the non-zero digits in the result.
+ threeHalfK := kc + halfK
+ nonZeroResultDigits := threeHalfK ^ halfK
+
+ // Determine the signed digits {0, ±1}.
+ result.pos[byteNum+1] = uint8(threeHalfK & nonZeroResultDigits)
+ result.neg[byteNum+1] = uint8(halfK & nonZeroResultDigits)
+
+ // Propagate the potential carry from the 3k/2 calculation.
+ carry = uint8(threeHalfK >> 8)
+ }
+ result.pos[0] = carry
+
+ // Set the starting and ending positions within the fixed size arrays to
+ // identify the bytes that are actually used. This is important since the
+ // encoding is big endian and thus trailing zero bytes changes its value.
+ result.start = 1 - carry
+ result.end = uint8(kLen + 1)
+ return result
+}
+
+// ScalarMultNonConst multiplies k*P where k is a scalar modulo the curve order
+// and P is a point in Jacobian projective coordinates and stores the result in
+// the provided Jacobian point.
+//
+// NOTE: The point must be normalized for this function to return the correct
+// result. The resulting point will be normalized.
+func ScalarMultNonConst(k *ModNScalar, point, result *JacobianPoint) {
+ // -------------------------------------------------------------------------
+ // This makes use of the following efficiently-computable endomorphism to
+ // accelerate the computation:
+ //
+ // φ(P) ⟼ λ*P = (β*P.x mod p, P.y)
+ //
+ // In other words, there is a special scalar λ that every point on the
+ // elliptic curve can be multiplied by that will result in the same point as
+ // performing a single field multiplication of the point's X coordinate by
+ // the special value β.
+ //
+ // This is useful because scalar point multiplication is significantly more
+ // expensive than a single field multiplication given the former involves a
+ // series of point doublings and additions which themselves consist of a
+ // combination of several field multiplications, squarings, and additions.
+ //
+ // So, the idea behind making use of the endomorphism is thus to decompose
+ // the scalar into two scalars that are each about half the bit length of
+ // the original scalar such that:
+ //
+ // k ≡ k1 + k2*λ (mod n)
+ //
+ // This in turn allows the scalar point multiplication to be performed as a
+ // sum of two smaller half-length multiplications as follows:
+ //
+ // k*P = (k1 + k2*λ)*P
+ // = k1*P + k2*λ*P
+ // = k1*P + k2*φ(P)
+ //
+ // Thus, a speedup is achieved so long as it's faster to decompose the
+ // scalar, compute φ(P), and perform a simultaneous multiply of the
+ // half-length point multiplications than it is to compute a full width
+ // point multiplication.
+ //
+ // In practice, benchmarks show the current implementation provides a
+ // speedup of around 30-35% versus not using the endomorphism.
+ //
+ // See section 3.5 in [GECC] for a more rigorous treatment.
+ // -------------------------------------------------------------------------
+
+ // Per above, the main equation here to remember is:
+ // k*P = k1*P + k2*φ(P)
+ //
+ // p1 below is P in the equation while p2 is φ(P) in the equation.
+ //
+ // NOTE: φ(x,y) = (β*x,y). The Jacobian z coordinates are the same, so this
+ // math goes through.
+ //
+ // Also, calculate -p1 and -p2 for use in the NAF optimization.
+ p1, p1Neg := new(JacobianPoint), new(JacobianPoint)
+ p1.Set(point)
+ p1Neg.Set(p1)
+ p1Neg.Y.Negate(1).Normalize()
+ p2, p2Neg := new(JacobianPoint), new(JacobianPoint)
+ p2.Set(p1)
+ p2.X.Mul(endoBeta).Normalize()
+ p2Neg.Set(p2)
+ p2Neg.Y.Negate(1).Normalize()
+
+ // Decompose k into k1 and k2 such that k = k1 + k2*λ (mod n) where k1 and
+ // k2 are around half the bit length of k in order to halve the number of EC
+ // operations.
+ //
+ // Notice that this also flips the sign of the scalars and points as needed
+ // to minimize the bit lengths of the scalars k1 and k2.
+ //
+ // This is done because the scalars are operating modulo the group order
+ // which means that when they would otherwise be a small negative magnitude
+ // they will instead be a large positive magnitude. Since the goal is for
+ // the scalars to have a small magnitude to achieve a performance boost, use
+ // their negation when they are greater than the half order of the group and
+ // flip the positive and negative values of the corresponding point that
+ // will be multiplied by to compensate.
+ //
+ // In other words, transform the calc when k1 is over the half order to:
+ // k1*P = -k1*-P
+ //
+ // Similarly, transform the calc when k2 is over the half order to:
+ // k2*φ(P) = -k2*-φ(P)
+ k1, k2 := splitK(k)
+ if k1.IsOverHalfOrder() {
+ k1.Negate()
+ p1, p1Neg = p1Neg, p1
+ }
+ if k2.IsOverHalfOrder() {
+ k2.Negate()
+ p2, p2Neg = p2Neg, p2
+ }
+
+ // Convert k1 and k2 into their NAF representations since NAF has a lot more
+ // zeros overall on average which minimizes the number of required point
+ // additions in exchange for a mix of fewer point additions and subtractions
+ // at the cost of one additional point doubling.
+ //
+ // This is an excellent tradeoff because subtraction of points has the same
+ // computational complexity as addition of points and point doubling is
+ // faster than both.
+ //
+ // Concretely, on average, 1/2 of all bits will be non-zero with the normal
+ // binary representation whereas only 1/3rd of the bits will be non-zero
+ // with NAF.
+ //
+ // The Pos version of the bytes contain the +1s and the Neg versions contain
+ // the -1s.
+ k1Bytes, k2Bytes := k1.Bytes(), k2.Bytes()
+ k1NAF, k2NAF := naf(k1Bytes[:]), naf(k2Bytes[:])
+ k1PosNAF, k1NegNAF := k1NAF.Pos(), k1NAF.Neg()
+ k2PosNAF, k2NegNAF := k2NAF.Pos(), k2NAF.Neg()
+ k1Len, k2Len := len(k1PosNAF), len(k2PosNAF)
+
+ // Add left-to-right using the NAF optimization. See algorithm 3.77 from
+ // [GECC].
+ //
+ // Point Q = ∞ (point at infinity).
+ var q JacobianPoint
+ m := k1Len
+ if m < k2Len {
+ m = k2Len
+ }
+ for i := 0; i < m; i++ {
+ // Since k1 and k2 are potentially different lengths and the calculation
+ // is being done left to right, pad the front of the shorter one with
+ // 0s.
+ var k1BytePos, k1ByteNeg, k2BytePos, k2ByteNeg byte
+ if i >= m-k1Len {
+ k1BytePos, k1ByteNeg = k1PosNAF[i-(m-k1Len)], k1NegNAF[i-(m-k1Len)]
+ }
+ if i >= m-k2Len {
+ k2BytePos, k2ByteNeg = k2PosNAF[i-(m-k2Len)], k2NegNAF[i-(m-k2Len)]
+ }
+
+ for mask := uint8(1 << 7); mask > 0; mask >>= 1 {
+ // Q = 2 * Q
+ DoubleNonConst(&q, &q)
+
+ // Add or subtract the first point based on the signed digit of the
+ // NAF representation of k1 at this bit position.
+ //
+ // +1: Q = Q + p1
+ // -1: Q = Q - p1
+ // 0: Q = Q (no change)
+ if k1BytePos&mask == mask {
+ AddNonConst(&q, p1, &q)
+ } else if k1ByteNeg&mask == mask {
+ AddNonConst(&q, p1Neg, &q)
+ }
+
+ // Add or subtract the second point based on the signed digit of the
+ // NAF representation of k2 at this bit position.
+ //
+ // +1: Q = Q + p2
+ // -1: Q = Q - p2
+ // 0: Q = Q (no change)
+ if k2BytePos&mask == mask {
+ AddNonConst(&q, p2, &q)
+ } else if k2ByteNeg&mask == mask {
+ AddNonConst(&q, p2Neg, &q)
+ }
+ }
+ }
+
+ result.Set(&q)
+}
+
+// ScalarBaseMultNonConst multiplies k*G where k is a scalar modulo the curve
+// order and G is the base point of the group and stores the result in the
+// provided Jacobian point.
+//
+// NOTE: The resulting point will be normalized.
+func ScalarBaseMultNonConst(k *ModNScalar, result *JacobianPoint) {
+ scalarBaseMultNonConst(k, result)
+}
+
+// jacobianG is the secp256k1 base point converted to Jacobian coordinates and
+// is defined here to avoid repeatedly converting it.
+var jacobianG = func() JacobianPoint {
+ var G JacobianPoint
+ bigAffineToJacobian(curveParams.Gx, curveParams.Gy, &G)
+ return G
+}()
+
+// scalarBaseMultNonConstSlow computes k*G through ScalarMultNonConst.
+func scalarBaseMultNonConstSlow(k *ModNScalar, result *JacobianPoint) {
+ ScalarMultNonConst(k, &jacobianG, result)
+}
+
+// scalarBaseMultNonConstFast computes k*G through the precomputed lookup
+// tables.
+func scalarBaseMultNonConstFast(k *ModNScalar, result *JacobianPoint) {
+ bytePoints := s256BytePoints()
+
+ // Start with the point at infinity.
+ result.X.Zero()
+ result.Y.Zero()
+ result.Z.Zero()
+
+ // bytePoints has all 256 byte points for each 8-bit window. The strategy
+ // is to add up the byte points. This is best understood by expressing k in
+ // base-256 which it already sort of is. Each "digit" in the 8-bit window
+ // can be looked up using bytePoints and added together.
+ kb := k.Bytes()
+ for i := 0; i < len(kb); i++ {
+ pt := &bytePoints[i][kb[i]]
+ AddNonConst(result, pt, result)
+ }
+}
+
+// isOnCurve returns whether or not the affine point (x,y) is on the curve.
+func isOnCurve(fx, fy *FieldVal) bool {
+ // Elliptic curve equation for secp256k1 is: y^2 = x^3 + 7
+ y2 := new(FieldVal).SquareVal(fy).Normalize()
+ result := new(FieldVal).SquareVal(fx).Mul(fx).AddInt(7).Normalize()
+ return y2.Equals(result)
+}
+
+// DecompressY attempts to calculate the Y coordinate for the given X coordinate
+// such that the result pair is a point on the secp256k1 curve. It adjusts Y
+// based on the desired oddness and returns whether or not it was successful
+// since not all X coordinates are valid.
+//
+// The magnitude of the provided X coordinate field val must be a max of 8 for a
+// correct result. The resulting Y field val will have a max magnitude of 2.
+func DecompressY(x *FieldVal, odd bool, resultY *FieldVal) bool {
+ // The curve equation for secp256k1 is: y^2 = x^3 + 7. Thus
+ // y = +-sqrt(x^3 + 7).
+ //
+ // The x coordinate must be invalid if there is no square root for the
+ // calculated rhs because it means the X coordinate is not for a point on
+ // the curve.
+ x3PlusB := new(FieldVal).SquareVal(x).Mul(x).AddInt(7)
+ if hasSqrt := resultY.SquareRootVal(x3PlusB); !hasSqrt {
+ return false
+ }
+ if resultY.Normalize().IsOdd() != odd {
+ resultY.Negate(1)
+ }
+ return true
+}
diff --git a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/curve_embedded.go b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/curve_embedded.go
new file mode 100644
index 0000000..1628831
--- /dev/null
+++ b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/curve_embedded.go
@@ -0,0 +1,14 @@
+// Copyright (c) 2024 The Decred developers
+// Use of this source code is governed by an ISC
+// license that can be found in the LICENSE file.
+
+//go:build tinygo
+
+package secp256k1
+
+// This file contains the variants suitable for
+// memory or storage constrained environments.
+
+func scalarBaseMultNonConst(k *ModNScalar, result *JacobianPoint) {
+ scalarBaseMultNonConstSlow(k, result)
+}
diff --git a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/curve_precompute.go b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/curve_precompute.go
new file mode 100644
index 0000000..cf84f77
--- /dev/null
+++ b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/curve_precompute.go
@@ -0,0 +1,14 @@
+// Copyright (c) 2024 The Decred developers
+// Use of this source code is governed by an ISC
+// license that can be found in the LICENSE file.
+
+//go:build !tinygo
+
+package secp256k1
+
+// This file contains the variants that don't fit in
+// memory or storage constrained environments.
+
+func scalarBaseMultNonConst(k *ModNScalar, result *JacobianPoint) {
+ scalarBaseMultNonConstFast(k, result)
+}
diff --git a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/doc.go b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/doc.go
new file mode 100644
index 0000000..ac01e23
--- /dev/null
+++ b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/doc.go
@@ -0,0 +1,59 @@
+// Copyright (c) 2013-2014 The btcsuite developers
+// Copyright (c) 2015-2022 The Decred developers
+// Use of this source code is governed by an ISC
+// license that can be found in the LICENSE file.
+
+/*
+Package secp256k1 implements optimized secp256k1 elliptic curve operations in
+pure Go.
+
+This package provides an optimized pure Go implementation of elliptic curve
+cryptography operations over the secp256k1 curve as well as data structures and
+functions for working with public and private secp256k1 keys. See
+https://www.secg.org/sec2-v2.pdf for details on the standard.
+
+In addition, sub packages are provided to produce, verify, parse, and serialize
+ECDSA signatures and EC-Schnorr-DCRv0 (a custom Schnorr-based signature scheme
+specific to Decred) signatures. See the README.md files in the relevant sub
+packages for more details about those aspects.
+
+An overview of the features provided by this package are as follows:
+
+ - Private key generation, serialization, and parsing
+ - Public key generation, serialization and parsing per ANSI X9.62-1998
+ - Parses uncompressed, compressed, and hybrid public keys
+ - Serializes uncompressed and compressed public keys
+ - Specialized types for performing optimized and constant time field operations
+ - FieldVal type for working modulo the secp256k1 field prime
+ - ModNScalar type for working modulo the secp256k1 group order
+ - Elliptic curve operations in Jacobian projective coordinates
+ - Point addition
+ - Point doubling
+ - Scalar multiplication with an arbitrary point
+ - Scalar multiplication with the base point (group generator)
+ - Point decompression from a given x coordinate
+ - Nonce generation via RFC6979 with support for extra data and version
+ information that can be used to prevent nonce reuse between signing
+ algorithms
+
+It also provides an implementation of the Go standard library crypto/elliptic
+Curve interface via the S256 function so that it may be used with other packages
+in the standard library such as crypto/tls, crypto/x509, and crypto/ecdsa.
+However, in the case of ECDSA, it is highly recommended to use the ecdsa sub
+package of this package instead since it is optimized specifically for secp256k1
+and is significantly faster as a result.
+
+Although this package was primarily written for dcrd, it has intentionally been
+designed so it can be used as a standalone package for any projects needing to
+use optimized secp256k1 elliptic curve cryptography.
+
+Finally, a comprehensive suite of tests is provided to provide a high level of
+quality assurance.
+
+# Use of secp256k1 in Decred
+
+At the time of this writing, the primary public key cryptography in widespread
+use on the Decred network used to secure coins is based on elliptic curves
+defined by the secp256k1 domain parameters.
+*/
+package secp256k1
diff --git a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/ecdh.go b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/ecdh.go
new file mode 100644
index 0000000..96869a3
--- /dev/null
+++ b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/ecdh.go
@@ -0,0 +1,21 @@
+// Copyright (c) 2015 The btcsuite developers
+// Copyright (c) 2015-2023 The Decred developers
+// Use of this source code is governed by an ISC
+// license that can be found in the LICENSE file.
+
+package secp256k1
+
+// GenerateSharedSecret generates a shared secret based on a private key and a
+// public key using Diffie-Hellman key exchange (ECDH) (RFC 5903).
+// RFC5903 Section 9 states we should only return x.
+//
+// It is recommended to securely hash the result before using as a cryptographic
+// key.
+func GenerateSharedSecret(privkey *PrivateKey, pubkey *PublicKey) []byte {
+ var point, result JacobianPoint
+ pubkey.AsJacobian(&point)
+ ScalarMultNonConst(&privkey.Key, &point, &result)
+ result.ToAffine()
+ xBytes := result.X.Bytes()
+ return xBytes[:]
+}
diff --git a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/ellipticadaptor.go b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/ellipticadaptor.go
new file mode 100644
index 0000000..4202264
--- /dev/null
+++ b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/ellipticadaptor.go
@@ -0,0 +1,255 @@
+// Copyright 2020-2022 The Decred developers
+// Use of this source code is governed by an ISC
+// license that can be found in the LICENSE file.
+
+package secp256k1
+
+// References:
+// [SECG]: Recommended Elliptic Curve Domain Parameters
+// https://www.secg.org/sec2-v2.pdf
+//
+// [GECC]: Guide to Elliptic Curve Cryptography (Hankerson, Menezes, Vanstone)
+
+import (
+ "crypto/ecdsa"
+ "crypto/elliptic"
+ "math/big"
+)
+
+// CurveParams contains the parameters for the secp256k1 curve.
+type CurveParams struct {
+ // P is the prime used in the secp256k1 field.
+ P *big.Int
+
+ // N is the order of the secp256k1 curve group generated by the base point.
+ N *big.Int
+
+ // Gx and Gy are the x and y coordinate of the base point, respectively.
+ Gx, Gy *big.Int
+
+ // BitSize is the size of the underlying secp256k1 field in bits.
+ BitSize int
+
+ // H is the cofactor of the secp256k1 curve.
+ H int
+
+ // ByteSize is simply the bit size / 8 and is provided for convenience
+ // since it is calculated repeatedly.
+ ByteSize int
+}
+
+// Curve parameters taken from [SECG] section 2.4.1.
+var curveParams = CurveParams{
+ P: fromHex("fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f"),
+ N: fromHex("fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141"),
+ Gx: fromHex("79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798"),
+ Gy: fromHex("483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8"),
+ BitSize: 256,
+ H: 1,
+ ByteSize: 256 / 8,
+}
+
+// Params returns the secp256k1 curve parameters for convenience.
+func Params() *CurveParams {
+ return &curveParams
+}
+
+// KoblitzCurve provides an implementation for secp256k1 that fits the ECC Curve
+// interface from crypto/elliptic.
+type KoblitzCurve struct {
+ *elliptic.CurveParams
+}
+
+// bigAffineToJacobian takes an affine point (x, y) as big integers and converts
+// it to Jacobian point with Z=1.
+func bigAffineToJacobian(x, y *big.Int, result *JacobianPoint) {
+ result.X.SetByteSlice(x.Bytes())
+ result.Y.SetByteSlice(y.Bytes())
+ result.Z.SetInt(1)
+}
+
+// jacobianToBigAffine takes a Jacobian point (x, y, z) as field values and
+// converts it to an affine point as big integers.
+func jacobianToBigAffine(point *JacobianPoint) (*big.Int, *big.Int) {
+ point.ToAffine()
+
+ // Convert the field values for the now affine point to big.Ints.
+ x3, y3 := new(big.Int), new(big.Int)
+ x3.SetBytes(point.X.Bytes()[:])
+ y3.SetBytes(point.Y.Bytes()[:])
+ return x3, y3
+}
+
+// Params returns the parameters for the curve.
+//
+// This is part of the elliptic.Curve interface implementation.
+func (curve *KoblitzCurve) Params() *elliptic.CurveParams {
+ return curve.CurveParams
+}
+
+// IsOnCurve returns whether or not the affine point (x,y) is on the curve.
+//
+// This is part of the elliptic.Curve interface implementation. This function
+// differs from the crypto/elliptic algorithm since a = 0 not -3.
+func (curve *KoblitzCurve) IsOnCurve(x, y *big.Int) bool {
+ // Convert big ints to a Jacobian point for faster arithmetic.
+ var point JacobianPoint
+ bigAffineToJacobian(x, y, &point)
+ return isOnCurve(&point.X, &point.Y)
+}
+
+// Add returns the sum of (x1,y1) and (x2,y2).
+//
+// This is part of the elliptic.Curve interface implementation.
+func (curve *KoblitzCurve) Add(x1, y1, x2, y2 *big.Int) (*big.Int, *big.Int) {
+ // The point at infinity is the identity according to the group law for
+ // elliptic curve cryptography. Thus, ∞ + P = P and P + ∞ = P.
+ if x1.Sign() == 0 && y1.Sign() == 0 {
+ return x2, y2
+ }
+ if x2.Sign() == 0 && y2.Sign() == 0 {
+ return x1, y1
+ }
+
+ // Convert the affine coordinates from big integers to Jacobian points,
+ // do the point addition in Jacobian projective space, and convert the
+ // Jacobian point back to affine big.Ints.
+ var p1, p2, result JacobianPoint
+ bigAffineToJacobian(x1, y1, &p1)
+ bigAffineToJacobian(x2, y2, &p2)
+ AddNonConst(&p1, &p2, &result)
+ return jacobianToBigAffine(&result)
+}
+
+// Double returns 2*(x1,y1).
+//
+// This is part of the elliptic.Curve interface implementation.
+func (curve *KoblitzCurve) Double(x1, y1 *big.Int) (*big.Int, *big.Int) {
+ if y1.Sign() == 0 {
+ return new(big.Int), new(big.Int)
+ }
+
+ // Convert the affine coordinates from big integers to Jacobian points,
+ // do the point doubling in Jacobian projective space, and convert the
+ // Jacobian point back to affine big.Ints.
+ var point, result JacobianPoint
+ bigAffineToJacobian(x1, y1, &point)
+ DoubleNonConst(&point, &result)
+ return jacobianToBigAffine(&result)
+}
+
+// moduloReduce reduces k from more than 32 bytes to 32 bytes and under. This
+// is done by doing a simple modulo curve.N. We can do this since G^N = 1 and
+// thus any other valid point on the elliptic curve has the same order.
+func moduloReduce(k []byte) []byte {
+ // Since the order of G is curve.N, we can use a much smaller number by
+ // doing modulo curve.N
+ if len(k) > curveParams.ByteSize {
+ tmpK := new(big.Int).SetBytes(k)
+ tmpK.Mod(tmpK, curveParams.N)
+ return tmpK.Bytes()
+ }
+
+ return k
+}
+
+// ScalarMult returns k*(Bx, By) where k is a big endian integer.
+//
+// This is part of the elliptic.Curve interface implementation.
+func (curve *KoblitzCurve) ScalarMult(Bx, By *big.Int, k []byte) (*big.Int, *big.Int) {
+ // Convert the affine coordinates from big integers to Jacobian points,
+ // do the multiplication in Jacobian projective space, and convert the
+ // Jacobian point back to affine big.Ints.
+ var kModN ModNScalar
+ kModN.SetByteSlice(moduloReduce(k))
+ var point, result JacobianPoint
+ bigAffineToJacobian(Bx, By, &point)
+ ScalarMultNonConst(&kModN, &point, &result)
+ return jacobianToBigAffine(&result)
+}
+
+// ScalarBaseMult returns k*G where G is the base point of the group and k is a
+// big endian integer.
+//
+// This is part of the elliptic.Curve interface implementation.
+func (curve *KoblitzCurve) ScalarBaseMult(k []byte) (*big.Int, *big.Int) {
+ // Perform the multiplication and convert the Jacobian point back to affine
+ // big.Ints.
+ var kModN ModNScalar
+ kModN.SetByteSlice(moduloReduce(k))
+ var result JacobianPoint
+ ScalarBaseMultNonConst(&kModN, &result)
+ return jacobianToBigAffine(&result)
+}
+
+// X returns the x coordinate of the public key.
+func (p *PublicKey) X() *big.Int {
+ return new(big.Int).SetBytes(p.x.Bytes()[:])
+}
+
+// Y returns the y coordinate of the public key.
+func (p *PublicKey) Y() *big.Int {
+ return new(big.Int).SetBytes(p.y.Bytes()[:])
+}
+
+// ToECDSA returns the public key as a *ecdsa.PublicKey.
+func (p *PublicKey) ToECDSA() *ecdsa.PublicKey {
+ return &ecdsa.PublicKey{
+ Curve: S256(),
+ X: p.X(),
+ Y: p.Y(),
+ }
+}
+
+// ToECDSA returns the private key as a *ecdsa.PrivateKey.
+func (p *PrivateKey) ToECDSA() *ecdsa.PrivateKey {
+ var privKeyBytes [PrivKeyBytesLen]byte
+ p.Key.PutBytes(&privKeyBytes)
+ var result JacobianPoint
+ ScalarBaseMultNonConst(&p.Key, &result)
+ x, y := jacobianToBigAffine(&result)
+ newPrivKey := &ecdsa.PrivateKey{
+ PublicKey: ecdsa.PublicKey{
+ Curve: S256(),
+ X: x,
+ Y: y,
+ },
+ D: new(big.Int).SetBytes(privKeyBytes[:]),
+ }
+ zeroArray32(&privKeyBytes)
+ return newPrivKey
+}
+
+// fromHex converts the passed hex string into a big integer pointer and will
+// panic is there is an error. This is only provided for the hard-coded
+// constants so errors in the source code can bet detected. It will only (and
+// must only) be called for initialization purposes.
+func fromHex(s string) *big.Int {
+ if s == "" {
+ return big.NewInt(0)
+ }
+ r, ok := new(big.Int).SetString(s, 16)
+ if !ok {
+ panic("invalid hex in source file: " + s)
+ }
+ return r
+}
+
+// secp256k1 is a global instance of the KoblitzCurve implementation which in
+// turn embeds and implements elliptic.CurveParams.
+var secp256k1 = &KoblitzCurve{
+ CurveParams: &elliptic.CurveParams{
+ P: curveParams.P,
+ N: curveParams.N,
+ B: fromHex("0000000000000000000000000000000000000000000000000000000000000007"),
+ Gx: curveParams.Gx,
+ Gy: curveParams.Gy,
+ BitSize: curveParams.BitSize,
+ Name: "secp256k1",
+ },
+}
+
+// S256 returns an elliptic.Curve which implements secp256k1.
+func S256() *KoblitzCurve {
+ return secp256k1
+}
diff --git a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/error.go b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/error.go
new file mode 100644
index 0000000..ac8c451
--- /dev/null
+++ b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/error.go
@@ -0,0 +1,67 @@
+// Copyright (c) 2020 The Decred developers
+// Use of this source code is governed by an ISC
+// license that can be found in the LICENSE file.
+
+package secp256k1
+
+// ErrorKind identifies a kind of error. It has full support for errors.Is and
+// errors.As, so the caller can directly check against an error kind when
+// determining the reason for an error.
+type ErrorKind string
+
+// These constants are used to identify a specific RuleError.
+const (
+ // ErrPubKeyInvalidLen indicates that the length of a serialized public
+ // key is not one of the allowed lengths.
+ ErrPubKeyInvalidLen = ErrorKind("ErrPubKeyInvalidLen")
+
+ // ErrPubKeyInvalidFormat indicates an attempt was made to parse a public
+ // key that does not specify one of the supported formats.
+ ErrPubKeyInvalidFormat = ErrorKind("ErrPubKeyInvalidFormat")
+
+ // ErrPubKeyXTooBig indicates that the x coordinate for a public key
+ // is greater than or equal to the prime of the field underlying the group.
+ ErrPubKeyXTooBig = ErrorKind("ErrPubKeyXTooBig")
+
+ // ErrPubKeyYTooBig indicates that the y coordinate for a public key is
+ // greater than or equal to the prime of the field underlying the group.
+ ErrPubKeyYTooBig = ErrorKind("ErrPubKeyYTooBig")
+
+ // ErrPubKeyNotOnCurve indicates that a public key is not a point on the
+ // secp256k1 curve.
+ ErrPubKeyNotOnCurve = ErrorKind("ErrPubKeyNotOnCurve")
+
+ // ErrPubKeyMismatchedOddness indicates that a hybrid public key specified
+ // an oddness of the y coordinate that does not match the actual oddness of
+ // the provided y coordinate.
+ ErrPubKeyMismatchedOddness = ErrorKind("ErrPubKeyMismatchedOddness")
+)
+
+// Error satisfies the error interface and prints human-readable errors.
+func (e ErrorKind) Error() string {
+ return string(e)
+}
+
+// Error identifies an error related to public key cryptography using a
+// sec256k1 curve. It has full support for errors.Is and errors.As, so the
+// caller can ascertain the specific reason for the error by checking
+// the underlying error.
+type Error struct {
+ Err error
+ Description string
+}
+
+// Error satisfies the error interface and prints human-readable errors.
+func (e Error) Error() string {
+ return e.Description
+}
+
+// Unwrap returns the underlying wrapped error.
+func (e Error) Unwrap() error {
+ return e.Err
+}
+
+// makeError creates an Error given a set of arguments.
+func makeError(kind ErrorKind, desc string) Error {
+ return Error{Err: kind, Description: desc}
+}
diff --git a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/field.go b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/field.go
new file mode 100644
index 0000000..494b209
--- /dev/null
+++ b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/field.go
@@ -0,0 +1,1680 @@
+// Copyright (c) 2013-2014 The btcsuite developers
+// Copyright (c) 2015-2023 The Decred developers
+// Copyright (c) 2013-2023 Dave Collins
+// Use of this source code is governed by an ISC
+// license that can be found in the LICENSE file.
+
+package secp256k1
+
+// References:
+// [HAC]: Handbook of Applied Cryptography Menezes, van Oorschot, Vanstone.
+// http://cacr.uwaterloo.ca/hac/
+
+// All elliptic curve operations for secp256k1 are done in a finite field
+// characterized by a 256-bit prime. Given this precision is larger than the
+// biggest available native type, obviously some form of bignum math is needed.
+// This package implements specialized fixed-precision field arithmetic rather
+// than relying on an arbitrary-precision arithmetic package such as math/big
+// for dealing with the field math since the size is known. As a result, rather
+// large performance gains are achieved by taking advantage of many
+// optimizations not available to arbitrary-precision arithmetic and generic
+// modular arithmetic algorithms.
+//
+// There are various ways to internally represent each finite field element.
+// For example, the most obvious representation would be to use an array of 4
+// uint64s (64 bits * 4 = 256 bits). However, that representation suffers from
+// a couple of issues. First, there is no native Go type large enough to handle
+// the intermediate results while adding or multiplying two 64-bit numbers, and
+// second there is no space left for overflows when performing the intermediate
+// arithmetic between each array element which would lead to expensive carry
+// propagation.
+//
+// Given the above, this implementation represents the field elements as
+// 10 uint32s with each word (array entry) treated as base 2^26. This was
+// chosen for the following reasons:
+// 1) Most systems at the current time are 64-bit (or at least have 64-bit
+// registers available for specialized purposes such as MMX) so the
+// intermediate results can typically be done using a native register (and
+// using uint64s to avoid the need for additional half-word arithmetic)
+// 2) In order to allow addition of the internal words without having to
+// propagate the carry, the max normalized value for each register must
+// be less than the number of bits available in the register
+// 3) Since we're dealing with 32-bit values, 64-bits of overflow is a
+// reasonable choice for #2
+// 4) Given the need for 256-bits of precision and the properties stated in #1,
+// #2, and #3, the representation which best accommodates this is 10 uint32s
+// with base 2^26 (26 bits * 10 = 260 bits, so the final word only needs 22
+// bits) which leaves the desired 64 bits (32 * 10 = 320, 320 - 256 = 64) for
+// overflow
+//
+// Since it is so important that the field arithmetic is extremely fast for high
+// performance crypto, this type does not perform any validation where it
+// ordinarily would. See the documentation for FieldVal for more details.
+
+import (
+ "encoding/hex"
+)
+
+// Constants used to make the code more readable.
+const (
+ twoBitsMask = 0x3
+ fourBitsMask = 0xf
+ sixBitsMask = 0x3f
+ eightBitsMask = 0xff
+)
+
+// Constants related to the field representation.
+const (
+ // fieldWords is the number of words used to internally represent the
+ // 256-bit value.
+ fieldWords = 10
+
+ // fieldBase is the exponent used to form the numeric base of each word.
+ // 2^(fieldBase*i) where i is the word position.
+ fieldBase = 26
+
+ // fieldBaseMask is the mask for the bits in each word needed to
+ // represent the numeric base of each word (except the most significant
+ // word).
+ fieldBaseMask = (1 << fieldBase) - 1
+
+ // fieldMSBBits is the number of bits in the most significant word used
+ // to represent the value.
+ fieldMSBBits = 256 - (fieldBase * (fieldWords - 1))
+
+ // fieldMSBMask is the mask for the bits in the most significant word
+ // needed to represent the value.
+ fieldMSBMask = (1 << fieldMSBBits) - 1
+
+ // These fields provide convenient access to each of the words of the
+ // secp256k1 prime in the internal field representation to improve code
+ // readability.
+ fieldPrimeWordZero = 0x03fffc2f
+ fieldPrimeWordOne = 0x03ffffbf
+ fieldPrimeWordTwo = 0x03ffffff
+ fieldPrimeWordThree = 0x03ffffff
+ fieldPrimeWordFour = 0x03ffffff
+ fieldPrimeWordFive = 0x03ffffff
+ fieldPrimeWordSix = 0x03ffffff
+ fieldPrimeWordSeven = 0x03ffffff
+ fieldPrimeWordEight = 0x03ffffff
+ fieldPrimeWordNine = 0x003fffff
+)
+
+// FieldVal implements optimized fixed-precision arithmetic over the
+// secp256k1 finite field. This means all arithmetic is performed modulo
+//
+// 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f.
+//
+// WARNING: Since it is so important for the field arithmetic to be extremely
+// fast for high performance crypto, this type does not perform any validation
+// of documented preconditions where it ordinarily would. As a result, it is
+// IMPERATIVE for callers to understand some key concepts that are described
+// below and ensure the methods are called with the necessary preconditions that
+// each method is documented with. For example, some methods only give the
+// correct result if the field value is normalized and others require the field
+// values involved to have a maximum magnitude and THERE ARE NO EXPLICIT CHECKS
+// TO ENSURE THOSE PRECONDITIONS ARE SATISFIED. This does, unfortunately, make
+// the type more difficult to use correctly and while I typically prefer to
+// ensure all state and input is valid for most code, this is a bit of an
+// exception because those extra checks really add up in what ends up being
+// critical hot paths.
+//
+// The first key concept when working with this type is normalization. In order
+// to avoid the need to propagate a ton of carries, the internal representation
+// provides additional overflow bits for each word of the overall 256-bit value.
+// This means that there are multiple internal representations for the same
+// value and, as a result, any methods that rely on comparison of the value,
+// such as equality and oddness determination, require the caller to provide a
+// normalized value.
+//
+// The second key concept when working with this type is magnitude. As
+// previously mentioned, the internal representation provides additional
+// overflow bits which means that the more math operations that are performed on
+// the field value between normalizations, the more those overflow bits
+// accumulate. The magnitude is effectively that maximum possible number of
+// those overflow bits that could possibly be required as a result of a given
+// operation. Since there are only a limited number of overflow bits available,
+// this implies that the max possible magnitude MUST be tracked by the caller
+// and the caller MUST normalize the field value if a given operation would
+// cause the magnitude of the result to exceed the max allowed value.
+//
+// IMPORTANT: The max allowed magnitude of a field value is 64.
+type FieldVal struct {
+ // Each 256-bit value is represented as 10 32-bit integers in base 2^26.
+ // This provides 6 bits of overflow in each word (10 bits in the most
+ // significant word) for a total of 64 bits of overflow (9*6 + 10 = 64). It
+ // only implements the arithmetic needed for elliptic curve operations.
+ //
+ // The following depicts the internal representation:
+ // -----------------------------------------------------------------
+ // | n[9] | n[8] | ... | n[0] |
+ // | 32 bits available | 32 bits available | ... | 32 bits available |
+ // | 22 bits for value | 26 bits for value | ... | 26 bits for value |
+ // | 10 bits overflow | 6 bits overflow | ... | 6 bits overflow |
+ // | Mult: 2^(26*9) | Mult: 2^(26*8) | ... | Mult: 2^(26*0) |
+ // -----------------------------------------------------------------
+ //
+ // For example, consider the number 2^49 + 1. It would be represented as:
+ // n[0] = 1
+ // n[1] = 2^23
+ // n[2..9] = 0
+ //
+ // The full 256-bit value is then calculated by looping i from 9..0 and
+ // doing sum(n[i] * 2^(26i)) like so:
+ // n[9] * 2^(26*9) = 0 * 2^234 = 0
+ // n[8] * 2^(26*8) = 0 * 2^208 = 0
+ // ...
+ // n[1] * 2^(26*1) = 2^23 * 2^26 = 2^49
+ // n[0] * 2^(26*0) = 1 * 2^0 = 1
+ // Sum: 0 + 0 + ... + 2^49 + 1 = 2^49 + 1
+ n [10]uint32
+}
+
+// String returns the field value as a normalized human-readable hex string.
+//
+// Preconditions: None
+// Output Normalized: Field is not modified -- same as input value
+// Output Max Magnitude: Field is not modified -- same as input value
+func (f FieldVal) String() string {
+ // f is a copy, so it's safe to normalize it without mutating the original.
+ f.Normalize()
+ return hex.EncodeToString(f.Bytes()[:])
+}
+
+// Zero sets the field value to zero in constant time. A newly created field
+// value is already set to zero. This function can be useful to clear an
+// existing field value for reuse.
+//
+// Preconditions: None
+// Output Normalized: Yes
+// Output Max Magnitude: 1
+func (f *FieldVal) Zero() {
+ f.n[0] = 0
+ f.n[1] = 0
+ f.n[2] = 0
+ f.n[3] = 0
+ f.n[4] = 0
+ f.n[5] = 0
+ f.n[6] = 0
+ f.n[7] = 0
+ f.n[8] = 0
+ f.n[9] = 0
+}
+
+// Set sets the field value equal to the passed value in constant time. The
+// normalization and magnitude of the two fields will be identical.
+//
+// The field value is returned to support chaining. This enables syntax like:
+// f := new(FieldVal).Set(f2).Add(1) so that f = f2 + 1 where f2 is not
+// modified.
+//
+// Preconditions: None
+// Output Normalized: Same as input value
+// Output Max Magnitude: Same as input value
+func (f *FieldVal) Set(val *FieldVal) *FieldVal {
+ *f = *val
+ return f
+}
+
+// SetInt sets the field value to the passed integer in constant time. This is
+// a convenience function since it is fairly common to perform some arithmetic
+// with small native integers.
+//
+// The field value is returned to support chaining. This enables syntax such
+// as f := new(FieldVal).SetInt(2).Mul(f2) so that f = 2 * f2.
+//
+// Preconditions: None
+// Output Normalized: Yes
+// Output Max Magnitude: 1
+func (f *FieldVal) SetInt(ui uint16) *FieldVal {
+ f.Zero()
+ f.n[0] = uint32(ui)
+ return f
+}
+
+// SetBytes packs the passed 32-byte big-endian value into the internal field
+// value representation in constant time. SetBytes interprets the provided
+// array as a 256-bit big-endian unsigned integer, packs it into the internal
+// field value representation, and returns either 1 if it is greater than or
+// equal to the field prime (aka it overflowed) or 0 otherwise in constant time.
+//
+// Note that a bool is not used here because it is not possible in Go to convert
+// from a bool to numeric value in constant time and many constant-time
+// operations require a numeric value.
+//
+// Preconditions: None
+// Output Normalized: Yes if no overflow, no otherwise
+// Output Max Magnitude: 1
+func (f *FieldVal) SetBytes(b *[32]byte) uint32 {
+ // Pack the 256 total bits across the 10 uint32 words with a max of
+ // 26-bits per word. This could be done with a couple of for loops,
+ // but this unrolled version is significantly faster. Benchmarks show
+ // this is about 34 times faster than the variant which uses loops.
+ f.n[0] = uint32(b[31]) | uint32(b[30])<<8 | uint32(b[29])<<16 |
+ (uint32(b[28])&twoBitsMask)<<24
+ f.n[1] = uint32(b[28])>>2 | uint32(b[27])<<6 | uint32(b[26])<<14 |
+ (uint32(b[25])&fourBitsMask)<<22
+ f.n[2] = uint32(b[25])>>4 | uint32(b[24])<<4 | uint32(b[23])<<12 |
+ (uint32(b[22])&sixBitsMask)<<20
+ f.n[3] = uint32(b[22])>>6 | uint32(b[21])<<2 | uint32(b[20])<<10 |
+ uint32(b[19])<<18
+ f.n[4] = uint32(b[18]) | uint32(b[17])<<8 | uint32(b[16])<<16 |
+ (uint32(b[15])&twoBitsMask)<<24
+ f.n[5] = uint32(b[15])>>2 | uint32(b[14])<<6 | uint32(b[13])<<14 |
+ (uint32(b[12])&fourBitsMask)<<22
+ f.n[6] = uint32(b[12])>>4 | uint32(b[11])<<4 | uint32(b[10])<<12 |
+ (uint32(b[9])&sixBitsMask)<<20
+ f.n[7] = uint32(b[9])>>6 | uint32(b[8])<<2 | uint32(b[7])<<10 |
+ uint32(b[6])<<18
+ f.n[8] = uint32(b[5]) | uint32(b[4])<<8 | uint32(b[3])<<16 |
+ (uint32(b[2])&twoBitsMask)<<24
+ f.n[9] = uint32(b[2])>>2 | uint32(b[1])<<6 | uint32(b[0])<<14
+
+ // The intuition here is that the field value is greater than the prime if
+ // one of the higher individual words is greater than corresponding word of
+ // the prime and all higher words in the field value are equal to their
+ // corresponding word of the prime. Since this type is modulo the prime,
+ // being equal is also an overflow back to 0.
+ //
+ // Note that because the input is 32 bytes and it was just packed into the
+ // field representation, the only words that can possibly be greater are
+ // zero and one, because ceil(log_2(2^256 - 1 - P)) = 33 bits max and the
+ // internal field representation encodes 26 bits with each word.
+ //
+ // Thus, there is no need to test if the upper words of the field value
+ // exceeds them, hence, only equality is checked for them.
+ highWordsEq := constantTimeEq(f.n[9], fieldPrimeWordNine)
+ highWordsEq &= constantTimeEq(f.n[8], fieldPrimeWordEight)
+ highWordsEq &= constantTimeEq(f.n[7], fieldPrimeWordSeven)
+ highWordsEq &= constantTimeEq(f.n[6], fieldPrimeWordSix)
+ highWordsEq &= constantTimeEq(f.n[5], fieldPrimeWordFive)
+ highWordsEq &= constantTimeEq(f.n[4], fieldPrimeWordFour)
+ highWordsEq &= constantTimeEq(f.n[3], fieldPrimeWordThree)
+ highWordsEq &= constantTimeEq(f.n[2], fieldPrimeWordTwo)
+ overflow := highWordsEq & constantTimeGreater(f.n[1], fieldPrimeWordOne)
+ highWordsEq &= constantTimeEq(f.n[1], fieldPrimeWordOne)
+ overflow |= highWordsEq & constantTimeGreaterOrEq(f.n[0], fieldPrimeWordZero)
+
+ return overflow
+}
+
+// SetByteSlice interprets the provided slice as a 256-bit big-endian unsigned
+// integer (meaning it is truncated to the first 32 bytes), packs it into the
+// internal field value representation, and returns whether or not the resulting
+// truncated 256-bit integer is greater than or equal to the field prime (aka it
+// overflowed) in constant time.
+//
+// Note that since passing a slice with more than 32 bytes is truncated, it is
+// possible that the truncated value is less than the field prime and hence it
+// will not be reported as having overflowed in that case. It is up to the
+// caller to decide whether it needs to provide numbers of the appropriate size
+// or it if is acceptable to use this function with the described truncation and
+// overflow behavior.
+//
+// Preconditions: None
+// Output Normalized: Yes if no overflow, no otherwise
+// Output Max Magnitude: 1
+func (f *FieldVal) SetByteSlice(b []byte) bool {
+ var b32 [32]byte
+ b = b[:constantTimeMin(uint32(len(b)), 32)]
+ copy(b32[:], b32[:32-len(b)])
+ copy(b32[32-len(b):], b)
+ result := f.SetBytes(&b32)
+ zeroArray32(&b32)
+ return result != 0
+}
+
+// Normalize normalizes the internal field words into the desired range and
+// performs fast modular reduction over the secp256k1 prime by making use of the
+// special form of the prime in constant time.
+//
+// Preconditions: None
+// Output Normalized: Yes
+// Output Max Magnitude: 1
+func (f *FieldVal) Normalize() *FieldVal {
+ // The field representation leaves 6 bits of overflow in each word so
+ // intermediate calculations can be performed without needing to
+ // propagate the carry to each higher word during the calculations. In
+ // order to normalize, we need to "compact" the full 256-bit value to
+ // the right while propagating any carries through to the high order
+ // word.
+ //
+ // Since this field is doing arithmetic modulo the secp256k1 prime, we
+ // also need to perform modular reduction over the prime.
+ //
+ // Per [HAC] section 14.3.4: Reduction method of moduli of special form,
+ // when the modulus is of the special form m = b^t - c, highly efficient
+ // reduction can be achieved.
+ //
+ // The secp256k1 prime is equivalent to 2^256 - 4294968273, so it fits
+ // this criteria.
+ //
+ // 4294968273 in field representation (base 2^26) is:
+ // n[0] = 977
+ // n[1] = 64
+ // That is to say (2^26 * 64) + 977 = 4294968273
+ //
+ // The algorithm presented in the referenced section typically repeats
+ // until the quotient is zero. However, due to our field representation
+ // we already know to within one reduction how many times we would need
+ // to repeat as it's the uppermost bits of the high order word. Thus we
+ // can simply multiply the magnitude by the field representation of the
+ // prime and do a single iteration. After this step there might be an
+ // additional carry to bit 256 (bit 22 of the high order word).
+ t9 := f.n[9]
+ m := t9 >> fieldMSBBits
+ t9 = t9 & fieldMSBMask
+ t0 := f.n[0] + m*977
+ t1 := (t0 >> fieldBase) + f.n[1] + (m << 6)
+ t0 = t0 & fieldBaseMask
+ t2 := (t1 >> fieldBase) + f.n[2]
+ t1 = t1 & fieldBaseMask
+ t3 := (t2 >> fieldBase) + f.n[3]
+ t2 = t2 & fieldBaseMask
+ t4 := (t3 >> fieldBase) + f.n[4]
+ t3 = t3 & fieldBaseMask
+ t5 := (t4 >> fieldBase) + f.n[5]
+ t4 = t4 & fieldBaseMask
+ t6 := (t5 >> fieldBase) + f.n[6]
+ t5 = t5 & fieldBaseMask
+ t7 := (t6 >> fieldBase) + f.n[7]
+ t6 = t6 & fieldBaseMask
+ t8 := (t7 >> fieldBase) + f.n[8]
+ t7 = t7 & fieldBaseMask
+ t9 = (t8 >> fieldBase) + t9
+ t8 = t8 & fieldBaseMask
+
+ // At this point, the magnitude is guaranteed to be one, however, the
+ // value could still be greater than the prime if there was either a
+ // carry through to bit 256 (bit 22 of the higher order word) or the
+ // value is greater than or equal to the field characteristic. The
+ // following determines if either or these conditions are true and does
+ // the final reduction in constant time.
+ //
+ // Also note that 'm' will be zero when neither of the aforementioned
+ // conditions are true and the value will not be changed when 'm' is zero.
+ m = constantTimeEq(t9, fieldMSBMask)
+ m &= constantTimeEq(t8&t7&t6&t5&t4&t3&t2, fieldBaseMask)
+ m &= constantTimeGreater(t1+64+((t0+977)>>fieldBase), fieldBaseMask)
+ m |= t9 >> fieldMSBBits
+ t0 = t0 + m*977
+ t1 = (t0 >> fieldBase) + t1 + (m << 6)
+ t0 = t0 & fieldBaseMask
+ t2 = (t1 >> fieldBase) + t2
+ t1 = t1 & fieldBaseMask
+ t3 = (t2 >> fieldBase) + t3
+ t2 = t2 & fieldBaseMask
+ t4 = (t3 >> fieldBase) + t4
+ t3 = t3 & fieldBaseMask
+ t5 = (t4 >> fieldBase) + t5
+ t4 = t4 & fieldBaseMask
+ t6 = (t5 >> fieldBase) + t6
+ t5 = t5 & fieldBaseMask
+ t7 = (t6 >> fieldBase) + t7
+ t6 = t6 & fieldBaseMask
+ t8 = (t7 >> fieldBase) + t8
+ t7 = t7 & fieldBaseMask
+ t9 = (t8 >> fieldBase) + t9
+ t8 = t8 & fieldBaseMask
+ t9 = t9 & fieldMSBMask // Remove potential multiple of 2^256.
+
+ // Finally, set the normalized and reduced words.
+ f.n[0] = t0
+ f.n[1] = t1
+ f.n[2] = t2
+ f.n[3] = t3
+ f.n[4] = t4
+ f.n[5] = t5
+ f.n[6] = t6
+ f.n[7] = t7
+ f.n[8] = t8
+ f.n[9] = t9
+ return f
+}
+
+// PutBytesUnchecked unpacks the field value to a 32-byte big-endian value
+// directly into the passed byte slice in constant time. The target slice must
+// have at least 32 bytes available or it will panic.
+//
+// There is a similar function, PutBytes, which unpacks the field value into a
+// 32-byte array directly. This version is provided since it can be useful
+// to write directly into part of a larger buffer without needing a separate
+// allocation.
+//
+// Preconditions:
+// - The field value MUST be normalized
+// - The target slice MUST have at least 32 bytes available
+func (f *FieldVal) PutBytesUnchecked(b []byte) {
+ // Unpack the 256 total bits from the 10 uint32 words with a max of
+ // 26-bits per word. This could be done with a couple of for loops,
+ // but this unrolled version is a bit faster. Benchmarks show this is
+ // about 10 times faster than the variant which uses loops.
+ b[31] = byte(f.n[0] & eightBitsMask)
+ b[30] = byte((f.n[0] >> 8) & eightBitsMask)
+ b[29] = byte((f.n[0] >> 16) & eightBitsMask)
+ b[28] = byte((f.n[0]>>24)&twoBitsMask | (f.n[1]&sixBitsMask)<<2)
+ b[27] = byte((f.n[1] >> 6) & eightBitsMask)
+ b[26] = byte((f.n[1] >> 14) & eightBitsMask)
+ b[25] = byte((f.n[1]>>22)&fourBitsMask | (f.n[2]&fourBitsMask)<<4)
+ b[24] = byte((f.n[2] >> 4) & eightBitsMask)
+ b[23] = byte((f.n[2] >> 12) & eightBitsMask)
+ b[22] = byte((f.n[2]>>20)&sixBitsMask | (f.n[3]&twoBitsMask)<<6)
+ b[21] = byte((f.n[3] >> 2) & eightBitsMask)
+ b[20] = byte((f.n[3] >> 10) & eightBitsMask)
+ b[19] = byte((f.n[3] >> 18) & eightBitsMask)
+ b[18] = byte(f.n[4] & eightBitsMask)
+ b[17] = byte((f.n[4] >> 8) & eightBitsMask)
+ b[16] = byte((f.n[4] >> 16) & eightBitsMask)
+ b[15] = byte((f.n[4]>>24)&twoBitsMask | (f.n[5]&sixBitsMask)<<2)
+ b[14] = byte((f.n[5] >> 6) & eightBitsMask)
+ b[13] = byte((f.n[5] >> 14) & eightBitsMask)
+ b[12] = byte((f.n[5]>>22)&fourBitsMask | (f.n[6]&fourBitsMask)<<4)
+ b[11] = byte((f.n[6] >> 4) & eightBitsMask)
+ b[10] = byte((f.n[6] >> 12) & eightBitsMask)
+ b[9] = byte((f.n[6]>>20)&sixBitsMask | (f.n[7]&twoBitsMask)<<6)
+ b[8] = byte((f.n[7] >> 2) & eightBitsMask)
+ b[7] = byte((f.n[7] >> 10) & eightBitsMask)
+ b[6] = byte((f.n[7] >> 18) & eightBitsMask)
+ b[5] = byte(f.n[8] & eightBitsMask)
+ b[4] = byte((f.n[8] >> 8) & eightBitsMask)
+ b[3] = byte((f.n[8] >> 16) & eightBitsMask)
+ b[2] = byte((f.n[8]>>24)&twoBitsMask | (f.n[9]&sixBitsMask)<<2)
+ b[1] = byte((f.n[9] >> 6) & eightBitsMask)
+ b[0] = byte((f.n[9] >> 14) & eightBitsMask)
+}
+
+// PutBytes unpacks the field value to a 32-byte big-endian value using the
+// passed byte array in constant time.
+//
+// There is a similar function, PutBytesUnchecked, which unpacks the field value
+// into a slice that must have at least 32 bytes available. This version is
+// provided since it can be useful to write directly into an array that is type
+// checked.
+//
+// Alternatively, there is also Bytes, which unpacks the field value into a new
+// array and returns that which can sometimes be more ergonomic in applications
+// that aren't concerned about an additional copy.
+//
+// Preconditions:
+// - The field value MUST be normalized
+func (f *FieldVal) PutBytes(b *[32]byte) {
+ f.PutBytesUnchecked(b[:])
+}
+
+// Bytes unpacks the field value to a 32-byte big-endian value in constant time.
+//
+// See PutBytes and PutBytesUnchecked for variants that allow an array or slice
+// to be passed which can be useful to cut down on the number of allocations by
+// allowing the caller to reuse a buffer or write directly into part of a larger
+// buffer.
+//
+// Preconditions:
+// - The field value MUST be normalized
+func (f *FieldVal) Bytes() *[32]byte {
+ b := new([32]byte)
+ f.PutBytesUnchecked(b[:])
+ return b
+}
+
+// IsZeroBit returns 1 when the field value is equal to zero or 0 otherwise in
+// constant time.
+//
+// Note that a bool is not used here because it is not possible in Go to convert
+// from a bool to numeric value in constant time and many constant-time
+// operations require a numeric value. See IsZero for the version that returns
+// a bool.
+//
+// Preconditions:
+// - The field value MUST be normalized
+func (f *FieldVal) IsZeroBit() uint32 {
+ // The value can only be zero if no bits are set in any of the words.
+ // This is a constant time implementation.
+ bits := f.n[0] | f.n[1] | f.n[2] | f.n[3] | f.n[4] |
+ f.n[5] | f.n[6] | f.n[7] | f.n[8] | f.n[9]
+
+ return constantTimeEq(bits, 0)
+}
+
+// IsZero returns whether or not the field value is equal to zero in constant
+// time.
+//
+// Preconditions:
+// - The field value MUST be normalized
+func (f *FieldVal) IsZero() bool {
+ // The value can only be zero if no bits are set in any of the words.
+ // This is a constant time implementation.
+ bits := f.n[0] | f.n[1] | f.n[2] | f.n[3] | f.n[4] |
+ f.n[5] | f.n[6] | f.n[7] | f.n[8] | f.n[9]
+
+ return bits == 0
+}
+
+// IsOneBit returns 1 when the field value is equal to one or 0 otherwise in
+// constant time.
+//
+// Note that a bool is not used here because it is not possible in Go to convert
+// from a bool to numeric value in constant time and many constant-time
+// operations require a numeric value. See IsOne for the version that returns a
+// bool.
+//
+// Preconditions:
+// - The field value MUST be normalized
+func (f *FieldVal) IsOneBit() uint32 {
+ // The value can only be one if the single lowest significant bit is set in
+ // the first word and no other bits are set in any of the other words.
+ // This is a constant time implementation.
+ bits := (f.n[0] ^ 1) | f.n[1] | f.n[2] | f.n[3] | f.n[4] | f.n[5] |
+ f.n[6] | f.n[7] | f.n[8] | f.n[9]
+
+ return constantTimeEq(bits, 0)
+}
+
+// IsOne returns whether or not the field value is equal to one in constant
+// time.
+//
+// Preconditions:
+// - The field value MUST be normalized
+func (f *FieldVal) IsOne() bool {
+ // The value can only be one if the single lowest significant bit is set in
+ // the first word and no other bits are set in any of the other words.
+ // This is a constant time implementation.
+ bits := (f.n[0] ^ 1) | f.n[1] | f.n[2] | f.n[3] | f.n[4] | f.n[5] |
+ f.n[6] | f.n[7] | f.n[8] | f.n[9]
+
+ return bits == 0
+}
+
+// IsOddBit returns 1 when the field value is an odd number or 0 otherwise in
+// constant time.
+//
+// Note that a bool is not used here because it is not possible in Go to convert
+// from a bool to numeric value in constant time and many constant-time
+// operations require a numeric value. See IsOdd for the version that returns a
+// bool.
+//
+// Preconditions:
+// - The field value MUST be normalized
+func (f *FieldVal) IsOddBit() uint32 {
+ // Only odd numbers have the bottom bit set.
+ return f.n[0] & 1
+}
+
+// IsOdd returns whether or not the field value is an odd number in constant
+// time.
+//
+// Preconditions:
+// - The field value MUST be normalized
+func (f *FieldVal) IsOdd() bool {
+ // Only odd numbers have the bottom bit set.
+ return f.n[0]&1 == 1
+}
+
+// Equals returns whether or not the two field values are the same in constant
+// time.
+//
+// Preconditions:
+// - Both field values being compared MUST be normalized
+func (f *FieldVal) Equals(val *FieldVal) bool {
+ // Xor only sets bits when they are different, so the two field values
+ // can only be the same if no bits are set after xoring each word.
+ // This is a constant time implementation.
+ bits := (f.n[0] ^ val.n[0]) | (f.n[1] ^ val.n[1]) | (f.n[2] ^ val.n[2]) |
+ (f.n[3] ^ val.n[3]) | (f.n[4] ^ val.n[4]) | (f.n[5] ^ val.n[5]) |
+ (f.n[6] ^ val.n[6]) | (f.n[7] ^ val.n[7]) | (f.n[8] ^ val.n[8]) |
+ (f.n[9] ^ val.n[9])
+
+ return bits == 0
+}
+
+// NegateVal negates the passed value and stores the result in f in constant
+// time. The caller must provide the magnitude of the passed value for a
+// correct result.
+//
+// The field value is returned to support chaining. This enables syntax like:
+// f.NegateVal(f2).AddInt(1) so that f = -f2 + 1.
+//
+// Preconditions:
+// - The max magnitude MUST be 63
+// Output Normalized: No
+// Output Max Magnitude: Input magnitude + 1
+func (f *FieldVal) NegateVal(val *FieldVal, magnitude uint32) *FieldVal {
+ // Negation in the field is just the prime minus the value. However,
+ // in order to allow negation against a field value without having to
+ // normalize/reduce it first, multiply by the magnitude (that is how
+ // "far" away it is from the normalized value) to adjust. Also, since
+ // negating a value pushes it one more order of magnitude away from the
+ // normalized range, add 1 to compensate.
+ //
+ // For some intuition here, imagine you're performing mod 12 arithmetic
+ // (picture a clock) and you are negating the number 7. So you start at
+ // 12 (which is of course 0 under mod 12) and count backwards (left on
+ // the clock) 7 times to arrive at 5. Notice this is just 12-7 = 5.
+ // Now, assume you're starting with 19, which is a number that is
+ // already larger than the modulus and congruent to 7 (mod 12). When a
+ // value is already in the desired range, its magnitude is 1. Since 19
+ // is an additional "step", its magnitude (mod 12) is 2. Since any
+ // multiple of the modulus is congruent to zero (mod m), the answer can
+ // be shortcut by simply multiplying the magnitude by the modulus and
+ // subtracting. Keeping with the example, this would be (2*12)-19 = 5.
+ f.n[0] = (magnitude+1)*fieldPrimeWordZero - val.n[0]
+ f.n[1] = (magnitude+1)*fieldPrimeWordOne - val.n[1]
+ f.n[2] = (magnitude+1)*fieldBaseMask - val.n[2]
+ f.n[3] = (magnitude+1)*fieldBaseMask - val.n[3]
+ f.n[4] = (magnitude+1)*fieldBaseMask - val.n[4]
+ f.n[5] = (magnitude+1)*fieldBaseMask - val.n[5]
+ f.n[6] = (magnitude+1)*fieldBaseMask - val.n[6]
+ f.n[7] = (magnitude+1)*fieldBaseMask - val.n[7]
+ f.n[8] = (magnitude+1)*fieldBaseMask - val.n[8]
+ f.n[9] = (magnitude+1)*fieldMSBMask - val.n[9]
+
+ return f
+}
+
+// Negate negates the field value in constant time. The existing field value is
+// modified. The caller must provide the magnitude of the field value for a
+// correct result.
+//
+// The field value is returned to support chaining. This enables syntax like:
+// f.Negate().AddInt(1) so that f = -f + 1.
+//
+// Preconditions:
+// - The max magnitude MUST be 63
+// Output Normalized: No
+// Output Max Magnitude: Input magnitude + 1
+func (f *FieldVal) Negate(magnitude uint32) *FieldVal {
+ return f.NegateVal(f, magnitude)
+}
+
+// AddInt adds the passed integer to the existing field value and stores the
+// result in f in constant time. This is a convenience function since it is
+// fairly common to perform some arithmetic with small native integers.
+//
+// The field value is returned to support chaining. This enables syntax like:
+// f.AddInt(1).Add(f2) so that f = f + 1 + f2.
+//
+// Preconditions:
+// - The field value MUST have a max magnitude of 63
+// Output Normalized: No
+// Output Max Magnitude: Existing field magnitude + 1
+func (f *FieldVal) AddInt(ui uint16) *FieldVal {
+ // Since the field representation intentionally provides overflow bits,
+ // it's ok to use carryless addition as the carry bit is safely part of
+ // the word and will be normalized out.
+ f.n[0] += uint32(ui)
+
+ return f
+}
+
+// Add adds the passed value to the existing field value and stores the result
+// in f in constant time.
+//
+// The field value is returned to support chaining. This enables syntax like:
+// f.Add(f2).AddInt(1) so that f = f + f2 + 1.
+//
+// Preconditions:
+// - The sum of the magnitudes of the two field values MUST be a max of 64
+// Output Normalized: No
+// Output Max Magnitude: Sum of the magnitude of the two individual field values
+func (f *FieldVal) Add(val *FieldVal) *FieldVal {
+ // Since the field representation intentionally provides overflow bits,
+ // it's ok to use carryless addition as the carry bit is safely part of
+ // each word and will be normalized out. This could obviously be done
+ // in a loop, but the unrolled version is faster.
+ f.n[0] += val.n[0]
+ f.n[1] += val.n[1]
+ f.n[2] += val.n[2]
+ f.n[3] += val.n[3]
+ f.n[4] += val.n[4]
+ f.n[5] += val.n[5]
+ f.n[6] += val.n[6]
+ f.n[7] += val.n[7]
+ f.n[8] += val.n[8]
+ f.n[9] += val.n[9]
+
+ return f
+}
+
+// Add2 adds the passed two field values together and stores the result in f in
+// constant time.
+//
+// The field value is returned to support chaining. This enables syntax like:
+// f3.Add2(f, f2).AddInt(1) so that f3 = f + f2 + 1.
+//
+// Preconditions:
+// - The sum of the magnitudes of the two field values MUST be a max of 64
+// Output Normalized: No
+// Output Max Magnitude: Sum of the magnitude of the two field values
+func (f *FieldVal) Add2(val *FieldVal, val2 *FieldVal) *FieldVal {
+ // Since the field representation intentionally provides overflow bits,
+ // it's ok to use carryless addition as the carry bit is safely part of
+ // each word and will be normalized out. This could obviously be done
+ // in a loop, but the unrolled version is faster.
+ f.n[0] = val.n[0] + val2.n[0]
+ f.n[1] = val.n[1] + val2.n[1]
+ f.n[2] = val.n[2] + val2.n[2]
+ f.n[3] = val.n[3] + val2.n[3]
+ f.n[4] = val.n[4] + val2.n[4]
+ f.n[5] = val.n[5] + val2.n[5]
+ f.n[6] = val.n[6] + val2.n[6]
+ f.n[7] = val.n[7] + val2.n[7]
+ f.n[8] = val.n[8] + val2.n[8]
+ f.n[9] = val.n[9] + val2.n[9]
+
+ return f
+}
+
+// MulInt multiplies the field value by the passed int and stores the result in
+// f in constant time. Note that this function can overflow if multiplying the
+// value by any of the individual words exceeds a max uint32. Therefore it is
+// important that the caller ensures no overflows will occur before using this
+// function.
+//
+// The field value is returned to support chaining. This enables syntax like:
+// f.MulInt(2).Add(f2) so that f = 2 * f + f2.
+//
+// Preconditions:
+// - The field value magnitude multiplied by given val MUST be a max of 64
+// Output Normalized: No
+// Output Max Magnitude: Existing field magnitude times the provided integer val
+func (f *FieldVal) MulInt(val uint8) *FieldVal {
+ // Since each word of the field representation can hold up to
+ // 32 - fieldBase extra bits which will be normalized out, it's safe
+ // to multiply each word without using a larger type or carry
+ // propagation so long as the values won't overflow a uint32. This
+ // could obviously be done in a loop, but the unrolled version is
+ // faster.
+ ui := uint32(val)
+ f.n[0] *= ui
+ f.n[1] *= ui
+ f.n[2] *= ui
+ f.n[3] *= ui
+ f.n[4] *= ui
+ f.n[5] *= ui
+ f.n[6] *= ui
+ f.n[7] *= ui
+ f.n[8] *= ui
+ f.n[9] *= ui
+
+ return f
+}
+
+// Mul multiplies the passed value to the existing field value and stores the
+// result in f in constant time. Note that this function can overflow if
+// multiplying any of the individual words exceeds a max uint32. In practice,
+// this means the magnitude of either value involved in the multiplication must
+// be a max of 8.
+//
+// The field value is returned to support chaining. This enables syntax like:
+// f.Mul(f2).AddInt(1) so that f = (f * f2) + 1.
+//
+// Preconditions:
+// - Both field values MUST have a max magnitude of 8
+// Output Normalized: No
+// Output Max Magnitude: 1
+func (f *FieldVal) Mul(val *FieldVal) *FieldVal {
+ return f.Mul2(f, val)
+}
+
+// Mul2 multiplies the passed two field values together and stores the result in
+// f in constant time. Note that this function can overflow if multiplying any
+// of the individual words exceeds a max uint32. In practice, this means the
+// magnitude of either value involved in the multiplication must be a max of 8.
+//
+// The field value is returned to support chaining. This enables syntax like:
+// f3.Mul2(f, f2).AddInt(1) so that f3 = (f * f2) + 1.
+//
+// Preconditions:
+// - Both input field values MUST have a max magnitude of 8
+// Output Normalized: No
+// Output Max Magnitude: 1
+func (f *FieldVal) Mul2(val *FieldVal, val2 *FieldVal) *FieldVal {
+ // This could be done with a couple of for loops and an array to store
+ // the intermediate terms, but this unrolled version is significantly
+ // faster.
+
+ // Terms for 2^(fieldBase*0).
+ m := uint64(val.n[0]) * uint64(val2.n[0])
+ t0 := m & fieldBaseMask
+
+ // Terms for 2^(fieldBase*1).
+ m = (m >> fieldBase) +
+ uint64(val.n[0])*uint64(val2.n[1]) +
+ uint64(val.n[1])*uint64(val2.n[0])
+ t1 := m & fieldBaseMask
+
+ // Terms for 2^(fieldBase*2).
+ m = (m >> fieldBase) +
+ uint64(val.n[0])*uint64(val2.n[2]) +
+ uint64(val.n[1])*uint64(val2.n[1]) +
+ uint64(val.n[2])*uint64(val2.n[0])
+ t2 := m & fieldBaseMask
+
+ // Terms for 2^(fieldBase*3).
+ m = (m >> fieldBase) +
+ uint64(val.n[0])*uint64(val2.n[3]) +
+ uint64(val.n[1])*uint64(val2.n[2]) +
+ uint64(val.n[2])*uint64(val2.n[1]) +
+ uint64(val.n[3])*uint64(val2.n[0])
+ t3 := m & fieldBaseMask
+
+ // Terms for 2^(fieldBase*4).
+ m = (m >> fieldBase) +
+ uint64(val.n[0])*uint64(val2.n[4]) +
+ uint64(val.n[1])*uint64(val2.n[3]) +
+ uint64(val.n[2])*uint64(val2.n[2]) +
+ uint64(val.n[3])*uint64(val2.n[1]) +
+ uint64(val.n[4])*uint64(val2.n[0])
+ t4 := m & fieldBaseMask
+
+ // Terms for 2^(fieldBase*5).
+ m = (m >> fieldBase) +
+ uint64(val.n[0])*uint64(val2.n[5]) +
+ uint64(val.n[1])*uint64(val2.n[4]) +
+ uint64(val.n[2])*uint64(val2.n[3]) +
+ uint64(val.n[3])*uint64(val2.n[2]) +
+ uint64(val.n[4])*uint64(val2.n[1]) +
+ uint64(val.n[5])*uint64(val2.n[0])
+ t5 := m & fieldBaseMask
+
+ // Terms for 2^(fieldBase*6).
+ m = (m >> fieldBase) +
+ uint64(val.n[0])*uint64(val2.n[6]) +
+ uint64(val.n[1])*uint64(val2.n[5]) +
+ uint64(val.n[2])*uint64(val2.n[4]) +
+ uint64(val.n[3])*uint64(val2.n[3]) +
+ uint64(val.n[4])*uint64(val2.n[2]) +
+ uint64(val.n[5])*uint64(val2.n[1]) +
+ uint64(val.n[6])*uint64(val2.n[0])
+ t6 := m & fieldBaseMask
+
+ // Terms for 2^(fieldBase*7).
+ m = (m >> fieldBase) +
+ uint64(val.n[0])*uint64(val2.n[7]) +
+ uint64(val.n[1])*uint64(val2.n[6]) +
+ uint64(val.n[2])*uint64(val2.n[5]) +
+ uint64(val.n[3])*uint64(val2.n[4]) +
+ uint64(val.n[4])*uint64(val2.n[3]) +
+ uint64(val.n[5])*uint64(val2.n[2]) +
+ uint64(val.n[6])*uint64(val2.n[1]) +
+ uint64(val.n[7])*uint64(val2.n[0])
+ t7 := m & fieldBaseMask
+
+ // Terms for 2^(fieldBase*8).
+ m = (m >> fieldBase) +
+ uint64(val.n[0])*uint64(val2.n[8]) +
+ uint64(val.n[1])*uint64(val2.n[7]) +
+ uint64(val.n[2])*uint64(val2.n[6]) +
+ uint64(val.n[3])*uint64(val2.n[5]) +
+ uint64(val.n[4])*uint64(val2.n[4]) +
+ uint64(val.n[5])*uint64(val2.n[3]) +
+ uint64(val.n[6])*uint64(val2.n[2]) +
+ uint64(val.n[7])*uint64(val2.n[1]) +
+ uint64(val.n[8])*uint64(val2.n[0])
+ t8 := m & fieldBaseMask
+
+ // Terms for 2^(fieldBase*9).
+ m = (m >> fieldBase) +
+ uint64(val.n[0])*uint64(val2.n[9]) +
+ uint64(val.n[1])*uint64(val2.n[8]) +
+ uint64(val.n[2])*uint64(val2.n[7]) +
+ uint64(val.n[3])*uint64(val2.n[6]) +
+ uint64(val.n[4])*uint64(val2.n[5]) +
+ uint64(val.n[5])*uint64(val2.n[4]) +
+ uint64(val.n[6])*uint64(val2.n[3]) +
+ uint64(val.n[7])*uint64(val2.n[2]) +
+ uint64(val.n[8])*uint64(val2.n[1]) +
+ uint64(val.n[9])*uint64(val2.n[0])
+ t9 := m & fieldBaseMask
+
+ // Terms for 2^(fieldBase*10).
+ m = (m >> fieldBase) +
+ uint64(val.n[1])*uint64(val2.n[9]) +
+ uint64(val.n[2])*uint64(val2.n[8]) +
+ uint64(val.n[3])*uint64(val2.n[7]) +
+ uint64(val.n[4])*uint64(val2.n[6]) +
+ uint64(val.n[5])*uint64(val2.n[5]) +
+ uint64(val.n[6])*uint64(val2.n[4]) +
+ uint64(val.n[7])*uint64(val2.n[3]) +
+ uint64(val.n[8])*uint64(val2.n[2]) +
+ uint64(val.n[9])*uint64(val2.n[1])
+ t10 := m & fieldBaseMask
+
+ // Terms for 2^(fieldBase*11).
+ m = (m >> fieldBase) +
+ uint64(val.n[2])*uint64(val2.n[9]) +
+ uint64(val.n[3])*uint64(val2.n[8]) +
+ uint64(val.n[4])*uint64(val2.n[7]) +
+ uint64(val.n[5])*uint64(val2.n[6]) +
+ uint64(val.n[6])*uint64(val2.n[5]) +
+ uint64(val.n[7])*uint64(val2.n[4]) +
+ uint64(val.n[8])*uint64(val2.n[3]) +
+ uint64(val.n[9])*uint64(val2.n[2])
+ t11 := m & fieldBaseMask
+
+ // Terms for 2^(fieldBase*12).
+ m = (m >> fieldBase) +
+ uint64(val.n[3])*uint64(val2.n[9]) +
+ uint64(val.n[4])*uint64(val2.n[8]) +
+ uint64(val.n[5])*uint64(val2.n[7]) +
+ uint64(val.n[6])*uint64(val2.n[6]) +
+ uint64(val.n[7])*uint64(val2.n[5]) +
+ uint64(val.n[8])*uint64(val2.n[4]) +
+ uint64(val.n[9])*uint64(val2.n[3])
+ t12 := m & fieldBaseMask
+
+ // Terms for 2^(fieldBase*13).
+ m = (m >> fieldBase) +
+ uint64(val.n[4])*uint64(val2.n[9]) +
+ uint64(val.n[5])*uint64(val2.n[8]) +
+ uint64(val.n[6])*uint64(val2.n[7]) +
+ uint64(val.n[7])*uint64(val2.n[6]) +
+ uint64(val.n[8])*uint64(val2.n[5]) +
+ uint64(val.n[9])*uint64(val2.n[4])
+ t13 := m & fieldBaseMask
+
+ // Terms for 2^(fieldBase*14).
+ m = (m >> fieldBase) +
+ uint64(val.n[5])*uint64(val2.n[9]) +
+ uint64(val.n[6])*uint64(val2.n[8]) +
+ uint64(val.n[7])*uint64(val2.n[7]) +
+ uint64(val.n[8])*uint64(val2.n[6]) +
+ uint64(val.n[9])*uint64(val2.n[5])
+ t14 := m & fieldBaseMask
+
+ // Terms for 2^(fieldBase*15).
+ m = (m >> fieldBase) +
+ uint64(val.n[6])*uint64(val2.n[9]) +
+ uint64(val.n[7])*uint64(val2.n[8]) +
+ uint64(val.n[8])*uint64(val2.n[7]) +
+ uint64(val.n[9])*uint64(val2.n[6])
+ t15 := m & fieldBaseMask
+
+ // Terms for 2^(fieldBase*16).
+ m = (m >> fieldBase) +
+ uint64(val.n[7])*uint64(val2.n[9]) +
+ uint64(val.n[8])*uint64(val2.n[8]) +
+ uint64(val.n[9])*uint64(val2.n[7])
+ t16 := m & fieldBaseMask
+
+ // Terms for 2^(fieldBase*17).
+ m = (m >> fieldBase) +
+ uint64(val.n[8])*uint64(val2.n[9]) +
+ uint64(val.n[9])*uint64(val2.n[8])
+ t17 := m & fieldBaseMask
+
+ // Terms for 2^(fieldBase*18).
+ m = (m >> fieldBase) + uint64(val.n[9])*uint64(val2.n[9])
+ t18 := m & fieldBaseMask
+
+ // What's left is for 2^(fieldBase*19).
+ t19 := m >> fieldBase
+
+ // At this point, all of the terms are grouped into their respective
+ // base.
+ //
+ // Per [HAC] section 14.3.4: Reduction method of moduli of special form,
+ // when the modulus is of the special form m = b^t - c, highly efficient
+ // reduction can be achieved per the provided algorithm.
+ //
+ // The secp256k1 prime is equivalent to 2^256 - 4294968273, so it fits
+ // this criteria.
+ //
+ // 4294968273 in field representation (base 2^26) is:
+ // n[0] = 977
+ // n[1] = 64
+ // That is to say (2^26 * 64) + 977 = 4294968273
+ //
+ // Since each word is in base 26, the upper terms (t10 and up) start
+ // at 260 bits (versus the final desired range of 256 bits), so the
+ // field representation of 'c' from above needs to be adjusted for the
+ // extra 4 bits by multiplying it by 2^4 = 16. 4294968273 * 16 =
+ // 68719492368. Thus, the adjusted field representation of 'c' is:
+ // n[0] = 977 * 16 = 15632
+ // n[1] = 64 * 16 = 1024
+ // That is to say (2^26 * 1024) + 15632 = 68719492368
+ //
+ // To reduce the final term, t19, the entire 'c' value is needed instead
+ // of only n[0] because there are no more terms left to handle n[1].
+ // This means there might be some magnitude left in the upper bits that
+ // is handled below.
+ m = t0 + t10*15632
+ t0 = m & fieldBaseMask
+ m = (m >> fieldBase) + t1 + t10*1024 + t11*15632
+ t1 = m & fieldBaseMask
+ m = (m >> fieldBase) + t2 + t11*1024 + t12*15632
+ t2 = m & fieldBaseMask
+ m = (m >> fieldBase) + t3 + t12*1024 + t13*15632
+ t3 = m & fieldBaseMask
+ m = (m >> fieldBase) + t4 + t13*1024 + t14*15632
+ t4 = m & fieldBaseMask
+ m = (m >> fieldBase) + t5 + t14*1024 + t15*15632
+ t5 = m & fieldBaseMask
+ m = (m >> fieldBase) + t6 + t15*1024 + t16*15632
+ t6 = m & fieldBaseMask
+ m = (m >> fieldBase) + t7 + t16*1024 + t17*15632
+ t7 = m & fieldBaseMask
+ m = (m >> fieldBase) + t8 + t17*1024 + t18*15632
+ t8 = m & fieldBaseMask
+ m = (m >> fieldBase) + t9 + t18*1024 + t19*68719492368
+ t9 = m & fieldMSBMask
+ m = m >> fieldMSBBits
+
+ // At this point, if the magnitude is greater than 0, the overall value
+ // is greater than the max possible 256-bit value. In particular, it is
+ // "how many times larger" than the max value it is.
+ //
+ // The algorithm presented in [HAC] section 14.3.4 repeats until the
+ // quotient is zero. However, due to the above, we already know at
+ // least how many times we would need to repeat as it's the value
+ // currently in m. Thus we can simply multiply the magnitude by the
+ // field representation of the prime and do a single iteration. Notice
+ // that nothing will be changed when the magnitude is zero, so we could
+ // skip this in that case, however always running regardless allows it
+ // to run in constant time. The final result will be in the range
+ // 0 <= result <= prime + (2^64 - c), so it is guaranteed to have a
+ // magnitude of 1, but it is denormalized.
+ d := t0 + m*977
+ f.n[0] = uint32(d & fieldBaseMask)
+ d = (d >> fieldBase) + t1 + m*64
+ f.n[1] = uint32(d & fieldBaseMask)
+ f.n[2] = uint32((d >> fieldBase) + t2)
+ f.n[3] = uint32(t3)
+ f.n[4] = uint32(t4)
+ f.n[5] = uint32(t5)
+ f.n[6] = uint32(t6)
+ f.n[7] = uint32(t7)
+ f.n[8] = uint32(t8)
+ f.n[9] = uint32(t9)
+
+ return f
+}
+
+// SquareRootVal either calculates the square root of the passed value when it
+// exists or the square root of the negation of the value when it does not exist
+// and stores the result in f in constant time. The return flag is true when
+// the calculated square root is for the passed value itself and false when it
+// is for its negation.
+//
+// Note that this function can overflow if multiplying any of the individual
+// words exceeds a max uint32. In practice, this means the magnitude of the
+// field must be a max of 8 to prevent overflow. The magnitude of the result
+// will be 1.
+//
+// Preconditions:
+// - The input field value MUST have a max magnitude of 8
+// Output Normalized: No
+// Output Max Magnitude: 1
+func (f *FieldVal) SquareRootVal(val *FieldVal) bool {
+ // This uses the Tonelli-Shanks method for calculating the square root of
+ // the value when it exists. The key principles of the method follow.
+ //
+ // Fermat's little theorem states that for a nonzero number 'a' and prime
+ // 'p', a^(p-1) ≡ 1 (mod p).
+ //
+ // Further, Euler's criterion states that an integer 'a' has a square root
+ // (aka is a quadratic residue) modulo a prime if a^((p-1)/2) ≡ 1 (mod p)
+ // and, conversely, when it does NOT have a square root (aka 'a' is a
+ // non-residue) a^((p-1)/2) ≡ -1 (mod p).
+ //
+ // This can be seen by considering that Fermat's little theorem can be
+ // written as (a^((p-1)/2) - 1)(a^((p-1)/2) + 1) ≡ 0 (mod p). Therefore,
+ // one of the two factors must be 0. Then, when a ≡ x^2 (aka 'a' is a
+ // quadratic residue), (x^2)^((p-1)/2) ≡ x^(p-1) ≡ 1 (mod p) which implies
+ // the first factor must be zero. Finally, per Lagrange's theorem, the
+ // non-residues are the only remaining possible solutions and thus must make
+ // the second factor zero to satisfy Fermat's little theorem implying that
+ // a^((p-1)/2) ≡ -1 (mod p) for that case.
+ //
+ // The Tonelli-Shanks method uses these facts along with factoring out
+ // powers of two to solve a congruence that results in either the solution
+ // when the square root exists or the square root of the negation of the
+ // value when it does not. In the case of primes that are ≡ 3 (mod 4), the
+ // possible solutions are r = ±a^((p+1)/4) (mod p). Therefore, either r^2 ≡
+ // a (mod p) is true in which case ±r are the two solutions, or r^2 ≡ -a
+ // (mod p) in which case 'a' is a non-residue and there are no solutions.
+ //
+ // The secp256k1 prime is ≡ 3 (mod 4), so this result applies.
+ //
+ // In other words, calculate a^((p+1)/4) and then square it and check it
+ // against the original value to determine if it is actually the square
+ // root.
+ //
+ // In order to efficiently compute a^((p+1)/4), (p+1)/4 needs to be split
+ // into a sequence of squares and multiplications that minimizes the number
+ // of multiplications needed (since they are more costly than squarings).
+ //
+ // The secp256k1 prime + 1 / 4 is 2^254 - 2^30 - 244. In binary, that is:
+ //
+ // 00111111 11111111 11111111 11111111
+ // 11111111 11111111 11111111 11111111
+ // 11111111 11111111 11111111 11111111
+ // 11111111 11111111 11111111 11111111
+ // 11111111 11111111 11111111 11111111
+ // 11111111 11111111 11111111 11111111
+ // 11111111 11111111 11111111 11111111
+ // 10111111 11111111 11111111 00001100
+ //
+ // Notice that can be broken up into three windows of consecutive 1s (in
+ // order of least to most significant) as:
+ //
+ // 6-bit window with two bits set (bits 4, 5, 6, 7 unset)
+ // 23-bit window with 22 bits set (bit 30 unset)
+ // 223-bit window with all 223 bits set
+ //
+ // Thus, the groups of 1 bits in each window forms the set:
+ // S = {2, 22, 223}.
+ //
+ // The strategy is to calculate a^(2^n - 1) for each grouping via an
+ // addition chain with a sliding window.
+ //
+ // The addition chain used is (credits to Peter Dettman):
+ // (0,0),(1,0),(2,2),(3,2),(4,1),(5,5),(6,6),(7,7),(8,8),(9,7),(10,2)
+ // => 2^1 2^[2] 2^3 2^6 2^9 2^11 2^[22] 2^44 2^88 2^176 2^220 2^[223]
+ //
+ // This has a cost of 254 field squarings and 13 field multiplications.
+ var a, a2, a3, a6, a9, a11, a22, a44, a88, a176, a220, a223 FieldVal
+ a.Set(val)
+ a2.SquareVal(&a).Mul(&a) // a2 = a^(2^2 - 1)
+ a3.SquareVal(&a2).Mul(&a) // a3 = a^(2^3 - 1)
+ a6.SquareVal(&a3).Square().Square() // a6 = a^(2^6 - 2^3)
+ a6.Mul(&a3) // a6 = a^(2^6 - 1)
+ a9.SquareVal(&a6).Square().Square() // a9 = a^(2^9 - 2^3)
+ a9.Mul(&a3) // a9 = a^(2^9 - 1)
+ a11.SquareVal(&a9).Square() // a11 = a^(2^11 - 2^2)
+ a11.Mul(&a2) // a11 = a^(2^11 - 1)
+ a22.SquareVal(&a11).Square().Square().Square().Square() // a22 = a^(2^16 - 2^5)
+ a22.Square().Square().Square().Square().Square() // a22 = a^(2^21 - 2^10)
+ a22.Square() // a22 = a^(2^22 - 2^11)
+ a22.Mul(&a11) // a22 = a^(2^22 - 1)
+ a44.SquareVal(&a22).Square().Square().Square().Square() // a44 = a^(2^27 - 2^5)
+ a44.Square().Square().Square().Square().Square() // a44 = a^(2^32 - 2^10)
+ a44.Square().Square().Square().Square().Square() // a44 = a^(2^37 - 2^15)
+ a44.Square().Square().Square().Square().Square() // a44 = a^(2^42 - 2^20)
+ a44.Square().Square() // a44 = a^(2^44 - 2^22)
+ a44.Mul(&a22) // a44 = a^(2^44 - 1)
+ a88.SquareVal(&a44).Square().Square().Square().Square() // a88 = a^(2^49 - 2^5)
+ a88.Square().Square().Square().Square().Square() // a88 = a^(2^54 - 2^10)
+ a88.Square().Square().Square().Square().Square() // a88 = a^(2^59 - 2^15)
+ a88.Square().Square().Square().Square().Square() // a88 = a^(2^64 - 2^20)
+ a88.Square().Square().Square().Square().Square() // a88 = a^(2^69 - 2^25)
+ a88.Square().Square().Square().Square().Square() // a88 = a^(2^74 - 2^30)
+ a88.Square().Square().Square().Square().Square() // a88 = a^(2^79 - 2^35)
+ a88.Square().Square().Square().Square().Square() // a88 = a^(2^84 - 2^40)
+ a88.Square().Square().Square().Square() // a88 = a^(2^88 - 2^44)
+ a88.Mul(&a44) // a88 = a^(2^88 - 1)
+ a176.SquareVal(&a88).Square().Square().Square().Square() // a176 = a^(2^93 - 2^5)
+ a176.Square().Square().Square().Square().Square() // a176 = a^(2^98 - 2^10)
+ a176.Square().Square().Square().Square().Square() // a176 = a^(2^103 - 2^15)
+ a176.Square().Square().Square().Square().Square() // a176 = a^(2^108 - 2^20)
+ a176.Square().Square().Square().Square().Square() // a176 = a^(2^113 - 2^25)
+ a176.Square().Square().Square().Square().Square() // a176 = a^(2^118 - 2^30)
+ a176.Square().Square().Square().Square().Square() // a176 = a^(2^123 - 2^35)
+ a176.Square().Square().Square().Square().Square() // a176 = a^(2^128 - 2^40)
+ a176.Square().Square().Square().Square().Square() // a176 = a^(2^133 - 2^45)
+ a176.Square().Square().Square().Square().Square() // a176 = a^(2^138 - 2^50)
+ a176.Square().Square().Square().Square().Square() // a176 = a^(2^143 - 2^55)
+ a176.Square().Square().Square().Square().Square() // a176 = a^(2^148 - 2^60)
+ a176.Square().Square().Square().Square().Square() // a176 = a^(2^153 - 2^65)
+ a176.Square().Square().Square().Square().Square() // a176 = a^(2^158 - 2^70)
+ a176.Square().Square().Square().Square().Square() // a176 = a^(2^163 - 2^75)
+ a176.Square().Square().Square().Square().Square() // a176 = a^(2^168 - 2^80)
+ a176.Square().Square().Square().Square().Square() // a176 = a^(2^173 - 2^85)
+ a176.Square().Square().Square() // a176 = a^(2^176 - 2^88)
+ a176.Mul(&a88) // a176 = a^(2^176 - 1)
+ a220.SquareVal(&a176).Square().Square().Square().Square() // a220 = a^(2^181 - 2^5)
+ a220.Square().Square().Square().Square().Square() // a220 = a^(2^186 - 2^10)
+ a220.Square().Square().Square().Square().Square() // a220 = a^(2^191 - 2^15)
+ a220.Square().Square().Square().Square().Square() // a220 = a^(2^196 - 2^20)
+ a220.Square().Square().Square().Square().Square() // a220 = a^(2^201 - 2^25)
+ a220.Square().Square().Square().Square().Square() // a220 = a^(2^206 - 2^30)
+ a220.Square().Square().Square().Square().Square() // a220 = a^(2^211 - 2^35)
+ a220.Square().Square().Square().Square().Square() // a220 = a^(2^216 - 2^40)
+ a220.Square().Square().Square().Square() // a220 = a^(2^220 - 2^44)
+ a220.Mul(&a44) // a220 = a^(2^220 - 1)
+ a223.SquareVal(&a220).Square().Square() // a223 = a^(2^223 - 2^3)
+ a223.Mul(&a3) // a223 = a^(2^223 - 1)
+
+ f.SquareVal(&a223).Square().Square().Square().Square() // f = a^(2^228 - 2^5)
+ f.Square().Square().Square().Square().Square() // f = a^(2^233 - 2^10)
+ f.Square().Square().Square().Square().Square() // f = a^(2^238 - 2^15)
+ f.Square().Square().Square().Square().Square() // f = a^(2^243 - 2^20)
+ f.Square().Square().Square() // f = a^(2^246 - 2^23)
+ f.Mul(&a22) // f = a^(2^246 - 2^22 - 1)
+ f.Square().Square().Square().Square().Square() // f = a^(2^251 - 2^27 - 2^5)
+ f.Square() // f = a^(2^252 - 2^28 - 2^6)
+ f.Mul(&a2) // f = a^(2^252 - 2^28 - 2^6 - 2^1 - 1)
+ f.Square().Square() // f = a^(2^254 - 2^30 - 2^8 - 2^3 - 2^2)
+ // // = a^(2^254 - 2^30 - 244)
+ // // = a^((p+1)/4)
+
+ // Ensure the calculated result is actually the square root by squaring it
+ // and checking against the original value.
+ var sqr FieldVal
+ return sqr.SquareVal(f).Normalize().Equals(val.Normalize())
+}
+
+// Square squares the field value in constant time. The existing field value is
+// modified. Note that this function can overflow if multiplying any of the
+// individual words exceeds a max uint32. In practice, this means the magnitude
+// of the field must be a max of 8 to prevent overflow.
+//
+// The field value is returned to support chaining. This enables syntax like:
+// f.Square().Mul(f2) so that f = f^2 * f2.
+//
+// Preconditions:
+// - The field value MUST have a max magnitude of 8
+// Output Normalized: No
+// Output Max Magnitude: 1
+func (f *FieldVal) Square() *FieldVal {
+ return f.SquareVal(f)
+}
+
+// SquareVal squares the passed value and stores the result in f in constant
+// time. Note that this function can overflow if multiplying any of the
+// individual words exceeds a max uint32. In practice, this means the magnitude
+// of the field being squared must be a max of 8 to prevent overflow.
+//
+// The field value is returned to support chaining. This enables syntax like:
+// f3.SquareVal(f).Mul(f) so that f3 = f^2 * f = f^3.
+//
+// Preconditions:
+// - The input field value MUST have a max magnitude of 8
+// Output Normalized: No
+// Output Max Magnitude: 1
+func (f *FieldVal) SquareVal(val *FieldVal) *FieldVal {
+ // This could be done with a couple of for loops and an array to store
+ // the intermediate terms, but this unrolled version is significantly
+ // faster.
+
+ // Terms for 2^(fieldBase*0).
+ m := uint64(val.n[0]) * uint64(val.n[0])
+ t0 := m & fieldBaseMask
+
+ // Terms for 2^(fieldBase*1).
+ m = (m >> fieldBase) + 2*uint64(val.n[0])*uint64(val.n[1])
+ t1 := m & fieldBaseMask
+
+ // Terms for 2^(fieldBase*2).
+ m = (m >> fieldBase) +
+ 2*uint64(val.n[0])*uint64(val.n[2]) +
+ uint64(val.n[1])*uint64(val.n[1])
+ t2 := m & fieldBaseMask
+
+ // Terms for 2^(fieldBase*3).
+ m = (m >> fieldBase) +
+ 2*uint64(val.n[0])*uint64(val.n[3]) +
+ 2*uint64(val.n[1])*uint64(val.n[2])
+ t3 := m & fieldBaseMask
+
+ // Terms for 2^(fieldBase*4).
+ m = (m >> fieldBase) +
+ 2*uint64(val.n[0])*uint64(val.n[4]) +
+ 2*uint64(val.n[1])*uint64(val.n[3]) +
+ uint64(val.n[2])*uint64(val.n[2])
+ t4 := m & fieldBaseMask
+
+ // Terms for 2^(fieldBase*5).
+ m = (m >> fieldBase) +
+ 2*uint64(val.n[0])*uint64(val.n[5]) +
+ 2*uint64(val.n[1])*uint64(val.n[4]) +
+ 2*uint64(val.n[2])*uint64(val.n[3])
+ t5 := m & fieldBaseMask
+
+ // Terms for 2^(fieldBase*6).
+ m = (m >> fieldBase) +
+ 2*uint64(val.n[0])*uint64(val.n[6]) +
+ 2*uint64(val.n[1])*uint64(val.n[5]) +
+ 2*uint64(val.n[2])*uint64(val.n[4]) +
+ uint64(val.n[3])*uint64(val.n[3])
+ t6 := m & fieldBaseMask
+
+ // Terms for 2^(fieldBase*7).
+ m = (m >> fieldBase) +
+ 2*uint64(val.n[0])*uint64(val.n[7]) +
+ 2*uint64(val.n[1])*uint64(val.n[6]) +
+ 2*uint64(val.n[2])*uint64(val.n[5]) +
+ 2*uint64(val.n[3])*uint64(val.n[4])
+ t7 := m & fieldBaseMask
+
+ // Terms for 2^(fieldBase*8).
+ m = (m >> fieldBase) +
+ 2*uint64(val.n[0])*uint64(val.n[8]) +
+ 2*uint64(val.n[1])*uint64(val.n[7]) +
+ 2*uint64(val.n[2])*uint64(val.n[6]) +
+ 2*uint64(val.n[3])*uint64(val.n[5]) +
+ uint64(val.n[4])*uint64(val.n[4])
+ t8 := m & fieldBaseMask
+
+ // Terms for 2^(fieldBase*9).
+ m = (m >> fieldBase) +
+ 2*uint64(val.n[0])*uint64(val.n[9]) +
+ 2*uint64(val.n[1])*uint64(val.n[8]) +
+ 2*uint64(val.n[2])*uint64(val.n[7]) +
+ 2*uint64(val.n[3])*uint64(val.n[6]) +
+ 2*uint64(val.n[4])*uint64(val.n[5])
+ t9 := m & fieldBaseMask
+
+ // Terms for 2^(fieldBase*10).
+ m = (m >> fieldBase) +
+ 2*uint64(val.n[1])*uint64(val.n[9]) +
+ 2*uint64(val.n[2])*uint64(val.n[8]) +
+ 2*uint64(val.n[3])*uint64(val.n[7]) +
+ 2*uint64(val.n[4])*uint64(val.n[6]) +
+ uint64(val.n[5])*uint64(val.n[5])
+ t10 := m & fieldBaseMask
+
+ // Terms for 2^(fieldBase*11).
+ m = (m >> fieldBase) +
+ 2*uint64(val.n[2])*uint64(val.n[9]) +
+ 2*uint64(val.n[3])*uint64(val.n[8]) +
+ 2*uint64(val.n[4])*uint64(val.n[7]) +
+ 2*uint64(val.n[5])*uint64(val.n[6])
+ t11 := m & fieldBaseMask
+
+ // Terms for 2^(fieldBase*12).
+ m = (m >> fieldBase) +
+ 2*uint64(val.n[3])*uint64(val.n[9]) +
+ 2*uint64(val.n[4])*uint64(val.n[8]) +
+ 2*uint64(val.n[5])*uint64(val.n[7]) +
+ uint64(val.n[6])*uint64(val.n[6])
+ t12 := m & fieldBaseMask
+
+ // Terms for 2^(fieldBase*13).
+ m = (m >> fieldBase) +
+ 2*uint64(val.n[4])*uint64(val.n[9]) +
+ 2*uint64(val.n[5])*uint64(val.n[8]) +
+ 2*uint64(val.n[6])*uint64(val.n[7])
+ t13 := m & fieldBaseMask
+
+ // Terms for 2^(fieldBase*14).
+ m = (m >> fieldBase) +
+ 2*uint64(val.n[5])*uint64(val.n[9]) +
+ 2*uint64(val.n[6])*uint64(val.n[8]) +
+ uint64(val.n[7])*uint64(val.n[7])
+ t14 := m & fieldBaseMask
+
+ // Terms for 2^(fieldBase*15).
+ m = (m >> fieldBase) +
+ 2*uint64(val.n[6])*uint64(val.n[9]) +
+ 2*uint64(val.n[7])*uint64(val.n[8])
+ t15 := m & fieldBaseMask
+
+ // Terms for 2^(fieldBase*16).
+ m = (m >> fieldBase) +
+ 2*uint64(val.n[7])*uint64(val.n[9]) +
+ uint64(val.n[8])*uint64(val.n[8])
+ t16 := m & fieldBaseMask
+
+ // Terms for 2^(fieldBase*17).
+ m = (m >> fieldBase) + 2*uint64(val.n[8])*uint64(val.n[9])
+ t17 := m & fieldBaseMask
+
+ // Terms for 2^(fieldBase*18).
+ m = (m >> fieldBase) + uint64(val.n[9])*uint64(val.n[9])
+ t18 := m & fieldBaseMask
+
+ // What's left is for 2^(fieldBase*19).
+ t19 := m >> fieldBase
+
+ // At this point, all of the terms are grouped into their respective
+ // base.
+ //
+ // Per [HAC] section 14.3.4: Reduction method of moduli of special form,
+ // when the modulus is of the special form m = b^t - c, highly efficient
+ // reduction can be achieved per the provided algorithm.
+ //
+ // The secp256k1 prime is equivalent to 2^256 - 4294968273, so it fits
+ // this criteria.
+ //
+ // 4294968273 in field representation (base 2^26) is:
+ // n[0] = 977
+ // n[1] = 64
+ // That is to say (2^26 * 64) + 977 = 4294968273
+ //
+ // Since each word is in base 26, the upper terms (t10 and up) start
+ // at 260 bits (versus the final desired range of 256 bits), so the
+ // field representation of 'c' from above needs to be adjusted for the
+ // extra 4 bits by multiplying it by 2^4 = 16. 4294968273 * 16 =
+ // 68719492368. Thus, the adjusted field representation of 'c' is:
+ // n[0] = 977 * 16 = 15632
+ // n[1] = 64 * 16 = 1024
+ // That is to say (2^26 * 1024) + 15632 = 68719492368
+ //
+ // To reduce the final term, t19, the entire 'c' value is needed instead
+ // of only n[0] because there are no more terms left to handle n[1].
+ // This means there might be some magnitude left in the upper bits that
+ // is handled below.
+ m = t0 + t10*15632
+ t0 = m & fieldBaseMask
+ m = (m >> fieldBase) + t1 + t10*1024 + t11*15632
+ t1 = m & fieldBaseMask
+ m = (m >> fieldBase) + t2 + t11*1024 + t12*15632
+ t2 = m & fieldBaseMask
+ m = (m >> fieldBase) + t3 + t12*1024 + t13*15632
+ t3 = m & fieldBaseMask
+ m = (m >> fieldBase) + t4 + t13*1024 + t14*15632
+ t4 = m & fieldBaseMask
+ m = (m >> fieldBase) + t5 + t14*1024 + t15*15632
+ t5 = m & fieldBaseMask
+ m = (m >> fieldBase) + t6 + t15*1024 + t16*15632
+ t6 = m & fieldBaseMask
+ m = (m >> fieldBase) + t7 + t16*1024 + t17*15632
+ t7 = m & fieldBaseMask
+ m = (m >> fieldBase) + t8 + t17*1024 + t18*15632
+ t8 = m & fieldBaseMask
+ m = (m >> fieldBase) + t9 + t18*1024 + t19*68719492368
+ t9 = m & fieldMSBMask
+ m = m >> fieldMSBBits
+
+ // At this point, if the magnitude is greater than 0, the overall value
+ // is greater than the max possible 256-bit value. In particular, it is
+ // "how many times larger" than the max value it is.
+ //
+ // The algorithm presented in [HAC] section 14.3.4 repeats until the
+ // quotient is zero. However, due to the above, we already know at
+ // least how many times we would need to repeat as it's the value
+ // currently in m. Thus we can simply multiply the magnitude by the
+ // field representation of the prime and do a single iteration. Notice
+ // that nothing will be changed when the magnitude is zero, so we could
+ // skip this in that case, however always running regardless allows it
+ // to run in constant time. The final result will be in the range
+ // 0 <= result <= prime + (2^64 - c), so it is guaranteed to have a
+ // magnitude of 1, but it is denormalized.
+ n := t0 + m*977
+ f.n[0] = uint32(n & fieldBaseMask)
+ n = (n >> fieldBase) + t1 + m*64
+ f.n[1] = uint32(n & fieldBaseMask)
+ f.n[2] = uint32((n >> fieldBase) + t2)
+ f.n[3] = uint32(t3)
+ f.n[4] = uint32(t4)
+ f.n[5] = uint32(t5)
+ f.n[6] = uint32(t6)
+ f.n[7] = uint32(t7)
+ f.n[8] = uint32(t8)
+ f.n[9] = uint32(t9)
+
+ return f
+}
+
+// Inverse finds the modular multiplicative inverse of the field value in
+// constant time. The existing field value is modified.
+//
+// The field value is returned to support chaining. This enables syntax like:
+// f.Inverse().Mul(f2) so that f = f^-1 * f2.
+//
+// Preconditions:
+// - The field value MUST have a max magnitude of 8
+// Output Normalized: No
+// Output Max Magnitude: 1
+func (f *FieldVal) Inverse() *FieldVal {
+ // Fermat's little theorem states that for a nonzero number a and prime
+ // p, a^(p-1) ≡ 1 (mod p). Since the multiplicative inverse is
+ // a*b ≡ 1 (mod p), it follows that b ≡ a*a^(p-2) ≡ a^(p-1) ≡ 1 (mod p).
+ // Thus, a^(p-2) is the multiplicative inverse.
+ //
+ // In order to efficiently compute a^(p-2), p-2 needs to be split into
+ // a sequence of squares and multiplications that minimizes the number
+ // of multiplications needed (since they are more costly than
+ // squarings). Intermediate results are saved and reused as well.
+ //
+ // The secp256k1 prime - 2 is 2^256 - 4294968275.
+ //
+ // This has a cost of 258 field squarings and 33 field multiplications.
+ var a2, a3, a4, a10, a11, a21, a42, a45, a63, a1019, a1023 FieldVal
+ a2.SquareVal(f)
+ a3.Mul2(&a2, f)
+ a4.SquareVal(&a2)
+ a10.SquareVal(&a4).Mul(&a2)
+ a11.Mul2(&a10, f)
+ a21.Mul2(&a10, &a11)
+ a42.SquareVal(&a21)
+ a45.Mul2(&a42, &a3)
+ a63.Mul2(&a42, &a21)
+ a1019.SquareVal(&a63).Square().Square().Square().Mul(&a11)
+ a1023.Mul2(&a1019, &a4)
+ f.Set(&a63) // f = a^(2^6 - 1)
+ f.Square().Square().Square().Square().Square() // f = a^(2^11 - 32)
+ f.Square().Square().Square().Square().Square() // f = a^(2^16 - 1024)
+ f.Mul(&a1023) // f = a^(2^16 - 1)
+ f.Square().Square().Square().Square().Square() // f = a^(2^21 - 32)
+ f.Square().Square().Square().Square().Square() // f = a^(2^26 - 1024)
+ f.Mul(&a1023) // f = a^(2^26 - 1)
+ f.Square().Square().Square().Square().Square() // f = a^(2^31 - 32)
+ f.Square().Square().Square().Square().Square() // f = a^(2^36 - 1024)
+ f.Mul(&a1023) // f = a^(2^36 - 1)
+ f.Square().Square().Square().Square().Square() // f = a^(2^41 - 32)
+ f.Square().Square().Square().Square().Square() // f = a^(2^46 - 1024)
+ f.Mul(&a1023) // f = a^(2^46 - 1)
+ f.Square().Square().Square().Square().Square() // f = a^(2^51 - 32)
+ f.Square().Square().Square().Square().Square() // f = a^(2^56 - 1024)
+ f.Mul(&a1023) // f = a^(2^56 - 1)
+ f.Square().Square().Square().Square().Square() // f = a^(2^61 - 32)
+ f.Square().Square().Square().Square().Square() // f = a^(2^66 - 1024)
+ f.Mul(&a1023) // f = a^(2^66 - 1)
+ f.Square().Square().Square().Square().Square() // f = a^(2^71 - 32)
+ f.Square().Square().Square().Square().Square() // f = a^(2^76 - 1024)
+ f.Mul(&a1023) // f = a^(2^76 - 1)
+ f.Square().Square().Square().Square().Square() // f = a^(2^81 - 32)
+ f.Square().Square().Square().Square().Square() // f = a^(2^86 - 1024)
+ f.Mul(&a1023) // f = a^(2^86 - 1)
+ f.Square().Square().Square().Square().Square() // f = a^(2^91 - 32)
+ f.Square().Square().Square().Square().Square() // f = a^(2^96 - 1024)
+ f.Mul(&a1023) // f = a^(2^96 - 1)
+ f.Square().Square().Square().Square().Square() // f = a^(2^101 - 32)
+ f.Square().Square().Square().Square().Square() // f = a^(2^106 - 1024)
+ f.Mul(&a1023) // f = a^(2^106 - 1)
+ f.Square().Square().Square().Square().Square() // f = a^(2^111 - 32)
+ f.Square().Square().Square().Square().Square() // f = a^(2^116 - 1024)
+ f.Mul(&a1023) // f = a^(2^116 - 1)
+ f.Square().Square().Square().Square().Square() // f = a^(2^121 - 32)
+ f.Square().Square().Square().Square().Square() // f = a^(2^126 - 1024)
+ f.Mul(&a1023) // f = a^(2^126 - 1)
+ f.Square().Square().Square().Square().Square() // f = a^(2^131 - 32)
+ f.Square().Square().Square().Square().Square() // f = a^(2^136 - 1024)
+ f.Mul(&a1023) // f = a^(2^136 - 1)
+ f.Square().Square().Square().Square().Square() // f = a^(2^141 - 32)
+ f.Square().Square().Square().Square().Square() // f = a^(2^146 - 1024)
+ f.Mul(&a1023) // f = a^(2^146 - 1)
+ f.Square().Square().Square().Square().Square() // f = a^(2^151 - 32)
+ f.Square().Square().Square().Square().Square() // f = a^(2^156 - 1024)
+ f.Mul(&a1023) // f = a^(2^156 - 1)
+ f.Square().Square().Square().Square().Square() // f = a^(2^161 - 32)
+ f.Square().Square().Square().Square().Square() // f = a^(2^166 - 1024)
+ f.Mul(&a1023) // f = a^(2^166 - 1)
+ f.Square().Square().Square().Square().Square() // f = a^(2^171 - 32)
+ f.Square().Square().Square().Square().Square() // f = a^(2^176 - 1024)
+ f.Mul(&a1023) // f = a^(2^176 - 1)
+ f.Square().Square().Square().Square().Square() // f = a^(2^181 - 32)
+ f.Square().Square().Square().Square().Square() // f = a^(2^186 - 1024)
+ f.Mul(&a1023) // f = a^(2^186 - 1)
+ f.Square().Square().Square().Square().Square() // f = a^(2^191 - 32)
+ f.Square().Square().Square().Square().Square() // f = a^(2^196 - 1024)
+ f.Mul(&a1023) // f = a^(2^196 - 1)
+ f.Square().Square().Square().Square().Square() // f = a^(2^201 - 32)
+ f.Square().Square().Square().Square().Square() // f = a^(2^206 - 1024)
+ f.Mul(&a1023) // f = a^(2^206 - 1)
+ f.Square().Square().Square().Square().Square() // f = a^(2^211 - 32)
+ f.Square().Square().Square().Square().Square() // f = a^(2^216 - 1024)
+ f.Mul(&a1023) // f = a^(2^216 - 1)
+ f.Square().Square().Square().Square().Square() // f = a^(2^221 - 32)
+ f.Square().Square().Square().Square().Square() // f = a^(2^226 - 1024)
+ f.Mul(&a1019) // f = a^(2^226 - 5)
+ f.Square().Square().Square().Square().Square() // f = a^(2^231 - 160)
+ f.Square().Square().Square().Square().Square() // f = a^(2^236 - 5120)
+ f.Mul(&a1023) // f = a^(2^236 - 4097)
+ f.Square().Square().Square().Square().Square() // f = a^(2^241 - 131104)
+ f.Square().Square().Square().Square().Square() // f = a^(2^246 - 4195328)
+ f.Mul(&a1023) // f = a^(2^246 - 4194305)
+ f.Square().Square().Square().Square().Square() // f = a^(2^251 - 134217760)
+ f.Square().Square().Square().Square().Square() // f = a^(2^256 - 4294968320)
+ return f.Mul(&a45) // f = a^(2^256 - 4294968275) = a^(p-2)
+}
+
+// IsGtOrEqPrimeMinusOrder returns whether or not the field value exceeds the
+// group order divided by 2 in constant time.
+//
+// Preconditions:
+// - The field value MUST be normalized
+func (f *FieldVal) IsGtOrEqPrimeMinusOrder() bool {
+ // The secp256k1 prime is equivalent to 2^256 - 4294968273 and the group
+ // order is 2^256 - 432420386565659656852420866394968145599. Thus,
+ // the prime minus the group order is:
+ // 432420386565659656852420866390673177326
+ //
+ // In hex that is:
+ // 0x00000000 00000000 00000000 00000001 45512319 50b75fc4 402da172 2fc9baee
+ //
+ // Converting that to field representation (base 2^26) is:
+ //
+ // n[0] = 0x03c9baee
+ // n[1] = 0x03685c8b
+ // n[2] = 0x01fc4402
+ // n[3] = 0x006542dd
+ // n[4] = 0x01455123
+ //
+ // This can be verified with the following test code:
+ // pMinusN := new(big.Int).Sub(curveParams.P, curveParams.N)
+ // var fv FieldVal
+ // fv.SetByteSlice(pMinusN.Bytes())
+ // t.Logf("%x", fv.n)
+ //
+ // Outputs: [3c9baee 3685c8b 1fc4402 6542dd 1455123 0 0 0 0 0]
+ const (
+ pMinusNWordZero = 0x03c9baee
+ pMinusNWordOne = 0x03685c8b
+ pMinusNWordTwo = 0x01fc4402
+ pMinusNWordThree = 0x006542dd
+ pMinusNWordFour = 0x01455123
+ pMinusNWordFive = 0x00000000
+ pMinusNWordSix = 0x00000000
+ pMinusNWordSeven = 0x00000000
+ pMinusNWordEight = 0x00000000
+ pMinusNWordNine = 0x00000000
+ )
+
+ // The intuition here is that the value is greater than field prime minus
+ // the group order if one of the higher individual words is greater than the
+ // corresponding word and all higher words in the value are equal.
+ result := constantTimeGreater(f.n[9], pMinusNWordNine)
+ highWordsEqual := constantTimeEq(f.n[9], pMinusNWordNine)
+ result |= highWordsEqual & constantTimeGreater(f.n[8], pMinusNWordEight)
+ highWordsEqual &= constantTimeEq(f.n[8], pMinusNWordEight)
+ result |= highWordsEqual & constantTimeGreater(f.n[7], pMinusNWordSeven)
+ highWordsEqual &= constantTimeEq(f.n[7], pMinusNWordSeven)
+ result |= highWordsEqual & constantTimeGreater(f.n[6], pMinusNWordSix)
+ highWordsEqual &= constantTimeEq(f.n[6], pMinusNWordSix)
+ result |= highWordsEqual & constantTimeGreater(f.n[5], pMinusNWordFive)
+ highWordsEqual &= constantTimeEq(f.n[5], pMinusNWordFive)
+ result |= highWordsEqual & constantTimeGreater(f.n[4], pMinusNWordFour)
+ highWordsEqual &= constantTimeEq(f.n[4], pMinusNWordFour)
+ result |= highWordsEqual & constantTimeGreater(f.n[3], pMinusNWordThree)
+ highWordsEqual &= constantTimeEq(f.n[3], pMinusNWordThree)
+ result |= highWordsEqual & constantTimeGreater(f.n[2], pMinusNWordTwo)
+ highWordsEqual &= constantTimeEq(f.n[2], pMinusNWordTwo)
+ result |= highWordsEqual & constantTimeGreater(f.n[1], pMinusNWordOne)
+ highWordsEqual &= constantTimeEq(f.n[1], pMinusNWordOne)
+ result |= highWordsEqual & constantTimeGreaterOrEq(f.n[0], pMinusNWordZero)
+
+ return result != 0
+}
diff --git a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/loadprecomputed.go b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/loadprecomputed.go
new file mode 100644
index 0000000..91c3d37
--- /dev/null
+++ b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/loadprecomputed.go
@@ -0,0 +1,91 @@
+// Copyright 2015 The btcsuite developers
+// Copyright (c) 2015-2022 The Decred developers
+// Use of this source code is governed by an ISC
+// license that can be found in the LICENSE file.
+
+package secp256k1
+
+import (
+ "compress/zlib"
+ "encoding/base64"
+ "io"
+ "strings"
+ "sync"
+)
+
+//go:generate go run genprecomps.go
+
+// bytePointTable describes a table used to house pre-computed values for
+// accelerating scalar base multiplication.
+type bytePointTable [32][256]JacobianPoint
+
+// compressedBytePointsFn is set to a real function by the code generation to
+// return the compressed pre-computed values for accelerating scalar base
+// multiplication.
+var compressedBytePointsFn func() string
+
+// s256BytePoints houses pre-computed values used to accelerate scalar base
+// multiplication such that they are only loaded on first use.
+var s256BytePoints = func() func() *bytePointTable {
+ // mustLoadBytePoints decompresses and deserializes the pre-computed byte
+ // points used to accelerate scalar base multiplication for the secp256k1
+ // curve.
+ //
+ // This approach is used since it allows the compile to use significantly
+ // less ram and be performed much faster than it is with hard-coding the
+ // final in-memory data structure. At the same time, it is quite fast to
+ // generate the in-memory data structure on first use with this approach
+ // versus computing the table.
+ //
+ // It will panic on any errors because the data is hard coded and thus any
+ // errors means something is wrong in the source code.
+ var data *bytePointTable
+ mustLoadBytePoints := func() {
+ // There will be no byte points to load when generating them.
+ if compressedBytePointsFn == nil {
+ return
+ }
+ bp := compressedBytePointsFn()
+
+ // Decompress the pre-computed table used to accelerate scalar base
+ // multiplication.
+ decoder := base64.NewDecoder(base64.StdEncoding, strings.NewReader(bp))
+ r, err := zlib.NewReader(decoder)
+ if err != nil {
+ panic(err)
+ }
+ serialized, err := io.ReadAll(r)
+ if err != nil {
+ panic(err)
+ }
+
+ // Deserialize the precomputed byte points and set the memory table to
+ // them.
+ offset := 0
+ var bytePoints bytePointTable
+ for byteNum := 0; byteNum < len(bytePoints); byteNum++ {
+ // All points in this window.
+ for i := 0; i < len(bytePoints[byteNum]); i++ {
+ p := &bytePoints[byteNum][i]
+ p.X.SetByteSlice(serialized[offset:])
+ offset += 32
+ p.Y.SetByteSlice(serialized[offset:])
+ offset += 32
+ p.Z.SetInt(1)
+ }
+ }
+ data = &bytePoints
+ }
+
+ // Return a closure that initializes the data on first access. This is done
+ // because the table takes a non-trivial amount of memory and initializing
+ // it unconditionally would cause anything that imports the package, either
+ // directly, or indirectly via transitive deps, to use that memory even if
+ // the caller never accesses any parts of the package that actually needs
+ // access to it.
+ var loadBytePointsOnce sync.Once
+ return func() *bytePointTable {
+ loadBytePointsOnce.Do(mustLoadBytePoints)
+ return data
+ }
+}()
diff --git a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/modnscalar.go b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/modnscalar.go
new file mode 100644
index 0000000..91940b1
--- /dev/null
+++ b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/modnscalar.go
@@ -0,0 +1,1105 @@
+// Copyright (c) 2020-2023 The Decred developers
+// Use of this source code is governed by an ISC
+// license that can be found in the LICENSE file.
+
+package secp256k1
+
+import (
+ "encoding/hex"
+ "math/big"
+)
+
+// References:
+// [SECG]: Recommended Elliptic Curve Domain Parameters
+// https://www.secg.org/sec2-v2.pdf
+//
+// [HAC]: Handbook of Applied Cryptography Menezes, van Oorschot, Vanstone.
+// http://cacr.uwaterloo.ca/hac/
+
+// Many elliptic curve operations require working with scalars in a finite field
+// characterized by the order of the group underlying the secp256k1 curve.
+// Given this precision is larger than the biggest available native type,
+// obviously some form of bignum math is needed. This code implements
+// specialized fixed-precision field arithmetic rather than relying on an
+// arbitrary-precision arithmetic package such as math/big for dealing with the
+// math modulo the group order since the size is known. As a result, rather
+// large performance gains are achieved by taking advantage of many
+// optimizations not available to arbitrary-precision arithmetic and generic
+// modular arithmetic algorithms.
+//
+// There are various ways to internally represent each element. For example,
+// the most obvious representation would be to use an array of 4 uint64s (64
+// bits * 4 = 256 bits). However, that representation suffers from the fact
+// that there is no native Go type large enough to handle the intermediate
+// results while adding or multiplying two 64-bit numbers.
+//
+// Given the above, this implementation represents the field elements as 8
+// uint32s with each word (array entry) treated as base 2^32. This was chosen
+// because most systems at the current time are 64-bit (or at least have 64-bit
+// registers available for specialized purposes such as MMX) so the intermediate
+// results can typically be done using a native register (and using uint64s to
+// avoid the need for additional half-word arithmetic)
+
+const (
+ // These fields provide convenient access to each of the words of the
+ // secp256k1 curve group order N to improve code readability.
+ //
+ // The group order of the curve per [SECG] is:
+ // 0xffffffff ffffffff ffffffff fffffffe baaedce6 af48a03b bfd25e8c d0364141
+ //
+ // nolint: dupword
+ orderWordZero uint32 = 0xd0364141
+ orderWordOne uint32 = 0xbfd25e8c
+ orderWordTwo uint32 = 0xaf48a03b
+ orderWordThree uint32 = 0xbaaedce6
+ orderWordFour uint32 = 0xfffffffe
+ orderWordFive uint32 = 0xffffffff
+ orderWordSix uint32 = 0xffffffff
+ orderWordSeven uint32 = 0xffffffff
+
+ // These fields provide convenient access to each of the words of the two's
+ // complement of the secp256k1 curve group order N to improve code
+ // readability.
+ //
+ // The two's complement of the group order is:
+ // 0x00000000 00000000 00000000 00000001 45512319 50b75fc4 402da173 2fc9bebf
+ orderComplementWordZero uint32 = (^orderWordZero) + 1
+ orderComplementWordOne uint32 = ^orderWordOne
+ orderComplementWordTwo uint32 = ^orderWordTwo
+ orderComplementWordThree uint32 = ^orderWordThree
+ //orderComplementWordFour uint32 = ^orderWordFour // unused
+ //orderComplementWordFive uint32 = ^orderWordFive // unused
+ //orderComplementWordSix uint32 = ^orderWordSix // unused
+ //orderComplementWordSeven uint32 = ^orderWordSeven // unused
+
+ // These fields provide convenient access to each of the words of the
+ // secp256k1 curve group order N / 2 to improve code readability and avoid
+ // the need to recalculate them.
+ //
+ // The half order of the secp256k1 curve group is:
+ // 0x7fffffff ffffffff ffffffff ffffffff 5d576e73 57a4501d dfe92f46 681b20a0
+ //
+ // nolint: dupword
+ halfOrderWordZero uint32 = 0x681b20a0
+ halfOrderWordOne uint32 = 0xdfe92f46
+ halfOrderWordTwo uint32 = 0x57a4501d
+ halfOrderWordThree uint32 = 0x5d576e73
+ halfOrderWordFour uint32 = 0xffffffff
+ halfOrderWordFive uint32 = 0xffffffff
+ halfOrderWordSix uint32 = 0xffffffff
+ halfOrderWordSeven uint32 = 0x7fffffff
+
+ // uint32Mask is simply a mask with all bits set for a uint32 and is used to
+ // improve the readability of the code.
+ uint32Mask = 0xffffffff
+)
+
+var (
+ // zero32 is an array of 32 bytes used for the purposes of zeroing and is
+ // defined here to avoid extra allocations.
+ zero32 = [32]byte{}
+)
+
+// ModNScalar implements optimized 256-bit constant-time fixed-precision
+// arithmetic over the secp256k1 group order. This means all arithmetic is
+// performed modulo:
+//
+// 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141
+//
+// It only implements the arithmetic needed for elliptic curve operations,
+// however, the operations that are not implemented can typically be worked
+// around if absolutely needed. For example, subtraction can be performed by
+// adding the negation.
+//
+// Should it be absolutely necessary, conversion to the standard library
+// math/big.Int can be accomplished by using the Bytes method, slicing the
+// resulting fixed-size array, and feeding it to big.Int.SetBytes. However,
+// that should typically be avoided when possible as conversion to big.Ints
+// requires allocations, is not constant time, and is slower when working modulo
+// the group order.
+type ModNScalar struct {
+ // The scalar is represented as 8 32-bit integers in base 2^32.
+ //
+ // The following depicts the internal representation:
+ // ---------------------------------------------------------
+ // | n[7] | n[6] | ... | n[0] |
+ // | 32 bits | 32 bits | ... | 32 bits |
+ // | Mult: 2^(32*7) | Mult: 2^(32*6) | ... | Mult: 2^(32*0) |
+ // ---------------------------------------------------------
+ //
+ // For example, consider the number 2^87 + 2^42 + 1. It would be
+ // represented as:
+ // n[0] = 1
+ // n[1] = 2^10
+ // n[2] = 2^23
+ // n[3..7] = 0
+ //
+ // The full 256-bit value is then calculated by looping i from 7..0 and
+ // doing sum(n[i] * 2^(32i)) like so:
+ // n[7] * 2^(32*7) = 0 * 2^224 = 0
+ // n[6] * 2^(32*6) = 0 * 2^192 = 0
+ // ...
+ // n[2] * 2^(32*2) = 2^23 * 2^64 = 2^87
+ // n[1] * 2^(32*1) = 2^10 * 2^32 = 2^42
+ // n[0] * 2^(32*0) = 1 * 2^0 = 1
+ // Sum: 0 + 0 + ... + 2^87 + 2^42 + 1 = 2^87 + 2^42 + 1
+ n [8]uint32
+}
+
+// String returns the scalar as a human-readable hex string.
+//
+// This is NOT constant time.
+func (s ModNScalar) String() string {
+ b := s.Bytes()
+ return hex.EncodeToString(b[:])
+}
+
+// Set sets the scalar equal to a copy of the passed one in constant time.
+//
+// The scalar is returned to support chaining. This enables syntax like:
+// s := new(ModNScalar).Set(s2).Add(1) so that s = s2 + 1 where s2 is not
+// modified.
+func (s *ModNScalar) Set(val *ModNScalar) *ModNScalar {
+ *s = *val
+ return s
+}
+
+// Zero sets the scalar to zero in constant time. A newly created scalar is
+// already set to zero. This function can be useful to clear an existing scalar
+// for reuse.
+func (s *ModNScalar) Zero() {
+ s.n[0] = 0
+ s.n[1] = 0
+ s.n[2] = 0
+ s.n[3] = 0
+ s.n[4] = 0
+ s.n[5] = 0
+ s.n[6] = 0
+ s.n[7] = 0
+}
+
+// IsZeroBit returns 1 when the scalar is equal to zero or 0 otherwise in
+// constant time.
+//
+// Note that a bool is not used here because it is not possible in Go to convert
+// from a bool to numeric value in constant time and many constant-time
+// operations require a numeric value. See IsZero for the version that returns
+// a bool.
+func (s *ModNScalar) IsZeroBit() uint32 {
+ // The scalar can only be zero if no bits are set in any of the words.
+ bits := s.n[0] | s.n[1] | s.n[2] | s.n[3] | s.n[4] | s.n[5] | s.n[6] | s.n[7]
+ return constantTimeEq(bits, 0)
+}
+
+// IsZero returns whether or not the scalar is equal to zero in constant time.
+func (s *ModNScalar) IsZero() bool {
+ // The scalar can only be zero if no bits are set in any of the words.
+ bits := s.n[0] | s.n[1] | s.n[2] | s.n[3] | s.n[4] | s.n[5] | s.n[6] | s.n[7]
+ return bits == 0
+}
+
+// SetInt sets the scalar to the passed integer in constant time. This is a
+// convenience function since it is fairly common to perform some arithmetic
+// with small native integers.
+//
+// The scalar is returned to support chaining. This enables syntax like:
+// s := new(ModNScalar).SetInt(2).Mul(s2) so that s = 2 * s2.
+func (s *ModNScalar) SetInt(ui uint32) *ModNScalar {
+ s.Zero()
+ s.n[0] = ui
+ return s
+}
+
+// constantTimeEq returns 1 if a == b or 0 otherwise in constant time.
+func constantTimeEq(a, b uint32) uint32 {
+ return uint32((uint64(a^b) - 1) >> 63)
+}
+
+// constantTimeNotEq returns 1 if a != b or 0 otherwise in constant time.
+func constantTimeNotEq(a, b uint32) uint32 {
+ return ^uint32((uint64(a^b)-1)>>63) & 1
+}
+
+// constantTimeLess returns 1 if a < b or 0 otherwise in constant time.
+func constantTimeLess(a, b uint32) uint32 {
+ return uint32((uint64(a) - uint64(b)) >> 63)
+}
+
+// constantTimeLessOrEq returns 1 if a <= b or 0 otherwise in constant time.
+func constantTimeLessOrEq(a, b uint32) uint32 {
+ return uint32((uint64(a) - uint64(b) - 1) >> 63)
+}
+
+// constantTimeGreater returns 1 if a > b or 0 otherwise in constant time.
+func constantTimeGreater(a, b uint32) uint32 {
+ return constantTimeLess(b, a)
+}
+
+// constantTimeGreaterOrEq returns 1 if a >= b or 0 otherwise in constant time.
+func constantTimeGreaterOrEq(a, b uint32) uint32 {
+ return constantTimeLessOrEq(b, a)
+}
+
+// constantTimeMin returns min(a,b) in constant time.
+func constantTimeMin(a, b uint32) uint32 {
+ return b ^ ((a ^ b) & -constantTimeLess(a, b))
+}
+
+// overflows determines if the current scalar is greater than or equal to the
+// group order in constant time and returns 1 if it is or 0 otherwise.
+func (s *ModNScalar) overflows() uint32 {
+ // The intuition here is that the scalar is greater than the group order if
+ // one of the higher individual words is greater than corresponding word of
+ // the group order and all higher words in the scalar are equal to their
+ // corresponding word of the group order. Since this type is modulo the
+ // group order, being equal is also an overflow back to 0.
+ //
+ // Note that the words 5, 6, and 7 are all the max uint32 value, so there is
+ // no need to test if those individual words of the scalar exceeds them,
+ // hence, only equality is checked for them.
+ highWordsEqual := constantTimeEq(s.n[7], orderWordSeven)
+ highWordsEqual &= constantTimeEq(s.n[6], orderWordSix)
+ highWordsEqual &= constantTimeEq(s.n[5], orderWordFive)
+ overflow := highWordsEqual & constantTimeGreater(s.n[4], orderWordFour)
+ highWordsEqual &= constantTimeEq(s.n[4], orderWordFour)
+ overflow |= highWordsEqual & constantTimeGreater(s.n[3], orderWordThree)
+ highWordsEqual &= constantTimeEq(s.n[3], orderWordThree)
+ overflow |= highWordsEqual & constantTimeGreater(s.n[2], orderWordTwo)
+ highWordsEqual &= constantTimeEq(s.n[2], orderWordTwo)
+ overflow |= highWordsEqual & constantTimeGreater(s.n[1], orderWordOne)
+ highWordsEqual &= constantTimeEq(s.n[1], orderWordOne)
+ overflow |= highWordsEqual & constantTimeGreaterOrEq(s.n[0], orderWordZero)
+
+ return overflow
+}
+
+// reduce256 reduces the current scalar modulo the group order in accordance
+// with the overflows parameter in constant time. The overflows parameter
+// specifies whether or not the scalar is known to be greater than the group
+// order and MUST either be 1 in the case it is or 0 in the case it is not for a
+// correct result.
+func (s *ModNScalar) reduce256(overflows uint32) {
+ // Notice that since s < 2^256 < 2N (where N is the group order), the max
+ // possible number of reductions required is one. Therefore, in the case a
+ // reduction is needed, it can be performed with a single subtraction of N.
+ // Also, recall that subtraction is equivalent to addition by the two's
+ // complement while ignoring the carry.
+ //
+ // When s >= N, the overflows parameter will be 1. Conversely, it will be 0
+ // when s < N. Thus multiplying by the overflows parameter will either
+ // result in 0 or the multiplicand itself.
+ //
+ // Combining the above along with the fact that s + 0 = s, the following is
+ // a constant time implementation that works by either adding 0 or the two's
+ // complement of N as needed.
+ //
+ // The final result will be in the range 0 <= s < N as expected.
+ overflows64 := uint64(overflows)
+ c := uint64(s.n[0]) + overflows64*uint64(orderComplementWordZero)
+ s.n[0] = uint32(c & uint32Mask)
+ c = (c >> 32) + uint64(s.n[1]) + overflows64*uint64(orderComplementWordOne)
+ s.n[1] = uint32(c & uint32Mask)
+ c = (c >> 32) + uint64(s.n[2]) + overflows64*uint64(orderComplementWordTwo)
+ s.n[2] = uint32(c & uint32Mask)
+ c = (c >> 32) + uint64(s.n[3]) + overflows64*uint64(orderComplementWordThree)
+ s.n[3] = uint32(c & uint32Mask)
+ c = (c >> 32) + uint64(s.n[4]) + overflows64 // * 1
+ s.n[4] = uint32(c & uint32Mask)
+ c = (c >> 32) + uint64(s.n[5]) // + overflows64 * 0
+ s.n[5] = uint32(c & uint32Mask)
+ c = (c >> 32) + uint64(s.n[6]) // + overflows64 * 0
+ s.n[6] = uint32(c & uint32Mask)
+ c = (c >> 32) + uint64(s.n[7]) // + overflows64 * 0
+ s.n[7] = uint32(c & uint32Mask)
+}
+
+// SetBytes interprets the provided array as a 256-bit big-endian unsigned
+// integer, reduces it modulo the group order, sets the scalar to the result,
+// and returns either 1 if it was reduced (aka it overflowed) or 0 otherwise in
+// constant time.
+//
+// Note that a bool is not used here because it is not possible in Go to convert
+// from a bool to numeric value in constant time and many constant-time
+// operations require a numeric value.
+func (s *ModNScalar) SetBytes(b *[32]byte) uint32 {
+ // Pack the 256 total bits across the 8 uint32 words. This could be done
+ // with a for loop, but benchmarks show this unrolled version is about 2
+ // times faster than the variant that uses a loop.
+ s.n[0] = uint32(b[31]) | uint32(b[30])<<8 | uint32(b[29])<<16 | uint32(b[28])<<24
+ s.n[1] = uint32(b[27]) | uint32(b[26])<<8 | uint32(b[25])<<16 | uint32(b[24])<<24
+ s.n[2] = uint32(b[23]) | uint32(b[22])<<8 | uint32(b[21])<<16 | uint32(b[20])<<24
+ s.n[3] = uint32(b[19]) | uint32(b[18])<<8 | uint32(b[17])<<16 | uint32(b[16])<<24
+ s.n[4] = uint32(b[15]) | uint32(b[14])<<8 | uint32(b[13])<<16 | uint32(b[12])<<24
+ s.n[5] = uint32(b[11]) | uint32(b[10])<<8 | uint32(b[9])<<16 | uint32(b[8])<<24
+ s.n[6] = uint32(b[7]) | uint32(b[6])<<8 | uint32(b[5])<<16 | uint32(b[4])<<24
+ s.n[7] = uint32(b[3]) | uint32(b[2])<<8 | uint32(b[1])<<16 | uint32(b[0])<<24
+
+ // The value might be >= N, so reduce it as required and return whether or
+ // not it was reduced.
+ needsReduce := s.overflows()
+ s.reduce256(needsReduce)
+ return needsReduce
+}
+
+// zeroArray32 zeroes the provided 32-byte buffer.
+func zeroArray32(b *[32]byte) {
+ copy(b[:], zero32[:])
+}
+
+// SetByteSlice interprets the provided slice as a 256-bit big-endian unsigned
+// integer (meaning it is truncated to the first 32 bytes), reduces it modulo
+// the group order, sets the scalar to the result, and returns whether or not
+// the resulting truncated 256-bit integer overflowed in constant time.
+//
+// Note that since passing a slice with more than 32 bytes is truncated, it is
+// possible that the truncated value is less than the order of the curve and
+// hence it will not be reported as having overflowed in that case. It is up to
+// the caller to decide whether it needs to provide numbers of the appropriate
+// size or it is acceptable to use this function with the described truncation
+// and overflow behavior.
+func (s *ModNScalar) SetByteSlice(b []byte) bool {
+ var b32 [32]byte
+ b = b[:constantTimeMin(uint32(len(b)), 32)]
+ copy(b32[:], b32[:32-len(b)])
+ copy(b32[32-len(b):], b)
+ result := s.SetBytes(&b32)
+ zeroArray32(&b32)
+ return result != 0
+}
+
+// PutBytesUnchecked unpacks the scalar to a 32-byte big-endian value directly
+// into the passed byte slice in constant time. The target slice must have at
+// least 32 bytes available or it will panic.
+//
+// There is a similar function, PutBytes, which unpacks the scalar into a
+// 32-byte array directly. This version is provided since it can be useful to
+// write directly into part of a larger buffer without needing a separate
+// allocation.
+//
+// Preconditions:
+// - The target slice MUST have at least 32 bytes available
+func (s *ModNScalar) PutBytesUnchecked(b []byte) {
+ // Unpack the 256 total bits from the 8 uint32 words. This could be done
+ // with a for loop, but benchmarks show this unrolled version is about 2
+ // times faster than the variant which uses a loop.
+ b[31] = byte(s.n[0])
+ b[30] = byte(s.n[0] >> 8)
+ b[29] = byte(s.n[0] >> 16)
+ b[28] = byte(s.n[0] >> 24)
+ b[27] = byte(s.n[1])
+ b[26] = byte(s.n[1] >> 8)
+ b[25] = byte(s.n[1] >> 16)
+ b[24] = byte(s.n[1] >> 24)
+ b[23] = byte(s.n[2])
+ b[22] = byte(s.n[2] >> 8)
+ b[21] = byte(s.n[2] >> 16)
+ b[20] = byte(s.n[2] >> 24)
+ b[19] = byte(s.n[3])
+ b[18] = byte(s.n[3] >> 8)
+ b[17] = byte(s.n[3] >> 16)
+ b[16] = byte(s.n[3] >> 24)
+ b[15] = byte(s.n[4])
+ b[14] = byte(s.n[4] >> 8)
+ b[13] = byte(s.n[4] >> 16)
+ b[12] = byte(s.n[4] >> 24)
+ b[11] = byte(s.n[5])
+ b[10] = byte(s.n[5] >> 8)
+ b[9] = byte(s.n[5] >> 16)
+ b[8] = byte(s.n[5] >> 24)
+ b[7] = byte(s.n[6])
+ b[6] = byte(s.n[6] >> 8)
+ b[5] = byte(s.n[6] >> 16)
+ b[4] = byte(s.n[6] >> 24)
+ b[3] = byte(s.n[7])
+ b[2] = byte(s.n[7] >> 8)
+ b[1] = byte(s.n[7] >> 16)
+ b[0] = byte(s.n[7] >> 24)
+}
+
+// PutBytes unpacks the scalar to a 32-byte big-endian value using the passed
+// byte array in constant time.
+//
+// There is a similar function, PutBytesUnchecked, which unpacks the scalar into
+// a slice that must have at least 32 bytes available. This version is provided
+// since it can be useful to write directly into an array that is type checked.
+//
+// Alternatively, there is also Bytes, which unpacks the scalar into a new array
+// and returns that which can sometimes be more ergonomic in applications that
+// aren't concerned about an additional copy.
+func (s *ModNScalar) PutBytes(b *[32]byte) {
+ s.PutBytesUnchecked(b[:])
+}
+
+// Bytes unpacks the scalar to a 32-byte big-endian value in constant time.
+//
+// See PutBytes and PutBytesUnchecked for variants that allow an array or slice
+// to be passed which can be useful to cut down on the number of allocations
+// by allowing the caller to reuse a buffer or write directly into part of a
+// larger buffer.
+func (s *ModNScalar) Bytes() [32]byte {
+ var b [32]byte
+ s.PutBytesUnchecked(b[:])
+ return b
+}
+
+// IsOdd returns whether or not the scalar is an odd number in constant time.
+func (s *ModNScalar) IsOdd() bool {
+ // Only odd numbers have the bottom bit set.
+ return s.n[0]&1 == 1
+}
+
+// Equals returns whether or not the two scalars are the same in constant time.
+func (s *ModNScalar) Equals(val *ModNScalar) bool {
+ // Xor only sets bits when they are different, so the two scalars can only
+ // be the same if no bits are set after xoring each word.
+ bits := (s.n[0] ^ val.n[0]) | (s.n[1] ^ val.n[1]) | (s.n[2] ^ val.n[2]) |
+ (s.n[3] ^ val.n[3]) | (s.n[4] ^ val.n[4]) | (s.n[5] ^ val.n[5]) |
+ (s.n[6] ^ val.n[6]) | (s.n[7] ^ val.n[7])
+
+ return bits == 0
+}
+
+// Add2 adds the passed two scalars together modulo the group order in constant
+// time and stores the result in s.
+//
+// The scalar is returned to support chaining. This enables syntax like:
+// s3.Add2(s, s2).AddInt(1) so that s3 = s + s2 + 1.
+func (s *ModNScalar) Add2(val1, val2 *ModNScalar) *ModNScalar {
+ c := uint64(val1.n[0]) + uint64(val2.n[0])
+ s.n[0] = uint32(c & uint32Mask)
+ c = (c >> 32) + uint64(val1.n[1]) + uint64(val2.n[1])
+ s.n[1] = uint32(c & uint32Mask)
+ c = (c >> 32) + uint64(val1.n[2]) + uint64(val2.n[2])
+ s.n[2] = uint32(c & uint32Mask)
+ c = (c >> 32) + uint64(val1.n[3]) + uint64(val2.n[3])
+ s.n[3] = uint32(c & uint32Mask)
+ c = (c >> 32) + uint64(val1.n[4]) + uint64(val2.n[4])
+ s.n[4] = uint32(c & uint32Mask)
+ c = (c >> 32) + uint64(val1.n[5]) + uint64(val2.n[5])
+ s.n[5] = uint32(c & uint32Mask)
+ c = (c >> 32) + uint64(val1.n[6]) + uint64(val2.n[6])
+ s.n[6] = uint32(c & uint32Mask)
+ c = (c >> 32) + uint64(val1.n[7]) + uint64(val2.n[7])
+ s.n[7] = uint32(c & uint32Mask)
+
+ // The result is now 256 bits, but it might still be >= N, so use the
+ // existing normal reduce method for 256-bit values.
+ s.reduce256(uint32(c>>32) + s.overflows())
+ return s
+}
+
+// Add adds the passed scalar to the existing one modulo the group order in
+// constant time and stores the result in s.
+//
+// The scalar is returned to support chaining. This enables syntax like:
+// s.Add(s2).AddInt(1) so that s = s + s2 + 1.
+func (s *ModNScalar) Add(val *ModNScalar) *ModNScalar {
+ return s.Add2(s, val)
+}
+
+// accumulator96 provides a 96-bit accumulator for use in the intermediate
+// calculations requiring more than 64-bits.
+type accumulator96 struct {
+ n [3]uint32
+}
+
+// Add adds the passed unsigned 64-bit value to the accumulator.
+func (a *accumulator96) Add(v uint64) {
+ low := uint32(v & uint32Mask)
+ hi := uint32(v >> 32)
+ a.n[0] += low
+ hi += constantTimeLess(a.n[0], low) // Carry if overflow in n[0].
+ a.n[1] += hi
+ a.n[2] += constantTimeLess(a.n[1], hi) // Carry if overflow in n[1].
+}
+
+// Rsh32 right shifts the accumulator by 32 bits.
+func (a *accumulator96) Rsh32() {
+ a.n[0] = a.n[1]
+ a.n[1] = a.n[2]
+ a.n[2] = 0
+}
+
+// reduce385 reduces the 385-bit intermediate result in the passed terms modulo
+// the group order in constant time and stores the result in s.
+func (s *ModNScalar) reduce385(t0, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12 uint64) {
+ // At this point, the intermediate result in the passed terms has been
+ // reduced to fit within 385 bits, so reduce it again using the same method
+ // described in reduce512. As before, the intermediate result will end up
+ // being reduced by another 127 bits to 258 bits, thus 9 32-bit terms are
+ // needed for this iteration. The reduced terms are assigned back to t0
+ // through t8.
+ //
+ // Note that several of the intermediate calculations require adding 64-bit
+ // products together which would overflow a uint64, so a 96-bit accumulator
+ // is used instead until the value is reduced enough to use native uint64s.
+
+ // Terms for 2^(32*0).
+ var acc accumulator96
+ acc.n[0] = uint32(t0) // == acc.Add(t0) because acc is guaranteed to be 0.
+ acc.Add(t8 * uint64(orderComplementWordZero))
+ t0 = uint64(acc.n[0])
+ acc.Rsh32()
+
+ // Terms for 2^(32*1).
+ acc.Add(t1)
+ acc.Add(t8 * uint64(orderComplementWordOne))
+ acc.Add(t9 * uint64(orderComplementWordZero))
+ t1 = uint64(acc.n[0])
+ acc.Rsh32()
+
+ // Terms for 2^(32*2).
+ acc.Add(t2)
+ acc.Add(t8 * uint64(orderComplementWordTwo))
+ acc.Add(t9 * uint64(orderComplementWordOne))
+ acc.Add(t10 * uint64(orderComplementWordZero))
+ t2 = uint64(acc.n[0])
+ acc.Rsh32()
+
+ // Terms for 2^(32*3).
+ acc.Add(t3)
+ acc.Add(t8 * uint64(orderComplementWordThree))
+ acc.Add(t9 * uint64(orderComplementWordTwo))
+ acc.Add(t10 * uint64(orderComplementWordOne))
+ acc.Add(t11 * uint64(orderComplementWordZero))
+ t3 = uint64(acc.n[0])
+ acc.Rsh32()
+
+ // Terms for 2^(32*4).
+ acc.Add(t4)
+ acc.Add(t8) // * uint64(orderComplementWordFour) // * 1
+ acc.Add(t9 * uint64(orderComplementWordThree))
+ acc.Add(t10 * uint64(orderComplementWordTwo))
+ acc.Add(t11 * uint64(orderComplementWordOne))
+ acc.Add(t12 * uint64(orderComplementWordZero))
+ t4 = uint64(acc.n[0])
+ acc.Rsh32()
+
+ // Terms for 2^(32*5).
+ acc.Add(t5)
+ // acc.Add(t8 * uint64(orderComplementWordFive)) // 0
+ acc.Add(t9) // * uint64(orderComplementWordFour) // * 1
+ acc.Add(t10 * uint64(orderComplementWordThree))
+ acc.Add(t11 * uint64(orderComplementWordTwo))
+ acc.Add(t12 * uint64(orderComplementWordOne))
+ t5 = uint64(acc.n[0])
+ acc.Rsh32()
+
+ // Terms for 2^(32*6).
+ acc.Add(t6)
+ // acc.Add(t8 * uint64(orderComplementWordSix)) // 0
+ // acc.Add(t9 * uint64(orderComplementWordFive)) // 0
+ acc.Add(t10) // * uint64(orderComplementWordFour) // * 1
+ acc.Add(t11 * uint64(orderComplementWordThree))
+ acc.Add(t12 * uint64(orderComplementWordTwo))
+ t6 = uint64(acc.n[0])
+ acc.Rsh32()
+
+ // Terms for 2^(32*7).
+ acc.Add(t7)
+ // acc.Add(t8 * uint64(orderComplementWordSeven)) // 0
+ // acc.Add(t9 * uint64(orderComplementWordSix)) // 0
+ // acc.Add(t10 * uint64(orderComplementWordFive)) // 0
+ acc.Add(t11) // * uint64(orderComplementWordFour) // * 1
+ acc.Add(t12 * uint64(orderComplementWordThree))
+ t7 = uint64(acc.n[0])
+ acc.Rsh32()
+
+ // Terms for 2^(32*8).
+ // acc.Add(t9 * uint64(orderComplementWordSeven)) // 0
+ // acc.Add(t10 * uint64(orderComplementWordSix)) // 0
+ // acc.Add(t11 * uint64(orderComplementWordFive)) // 0
+ acc.Add(t12) // * uint64(orderComplementWordFour) // * 1
+ t8 = uint64(acc.n[0])
+ // acc.Rsh32() // No need since not used after this. Guaranteed to be 0.
+
+ // NOTE: All of the remaining multiplications for this iteration result in 0
+ // as they all involve multiplying by combinations of the fifth, sixth, and
+ // seventh words of the two's complement of N, which are 0, so skip them.
+
+ // At this point, the result is reduced to fit within 258 bits, so reduce it
+ // again using a slightly modified version of the same method. The maximum
+ // value in t8 is 2 at this point and therefore multiplying it by each word
+ // of the two's complement of N and adding it to a 32-bit term will result
+ // in a maximum requirement of 33 bits, so it is safe to use native uint64s
+ // here for the intermediate term carry propagation.
+ //
+ // Also, since the maximum value in t8 is 2, this ends up reducing by
+ // another 2 bits to 256 bits.
+ c := t0 + t8*uint64(orderComplementWordZero)
+ s.n[0] = uint32(c & uint32Mask)
+ c = (c >> 32) + t1 + t8*uint64(orderComplementWordOne)
+ s.n[1] = uint32(c & uint32Mask)
+ c = (c >> 32) + t2 + t8*uint64(orderComplementWordTwo)
+ s.n[2] = uint32(c & uint32Mask)
+ c = (c >> 32) + t3 + t8*uint64(orderComplementWordThree)
+ s.n[3] = uint32(c & uint32Mask)
+ c = (c >> 32) + t4 + t8 // * uint64(orderComplementWordFour) == * 1
+ s.n[4] = uint32(c & uint32Mask)
+ c = (c >> 32) + t5 // + t8*uint64(orderComplementWordFive) == 0
+ s.n[5] = uint32(c & uint32Mask)
+ c = (c >> 32) + t6 // + t8*uint64(orderComplementWordSix) == 0
+ s.n[6] = uint32(c & uint32Mask)
+ c = (c >> 32) + t7 // + t8*uint64(orderComplementWordSeven) == 0
+ s.n[7] = uint32(c & uint32Mask)
+
+ // The result is now 256 bits, but it might still be >= N, so use the
+ // existing normal reduce method for 256-bit values.
+ s.reduce256(uint32(c>>32) + s.overflows())
+}
+
+// reduce512 reduces the 512-bit intermediate result in the passed terms modulo
+// the group order down to 385 bits in constant time and stores the result in s.
+func (s *ModNScalar) reduce512(t0, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15 uint64) {
+ // At this point, the intermediate result in the passed terms is grouped
+ // into the respective bases.
+ //
+ // Per [HAC] section 14.3.4: Reduction method of moduli of special form,
+ // when the modulus is of the special form m = b^t - c, where log_2(c) < t,
+ // highly efficient reduction can be achieved per the provided algorithm.
+ //
+ // The secp256k1 group order fits this criteria since it is:
+ // 2^256 - 432420386565659656852420866394968145599
+ //
+ // Technically the max possible value here is (N-1)^2 since the two scalars
+ // being multiplied are always mod N. Nevertheless, it is safer to consider
+ // it to be (2^256-1)^2 = 2^512 - 2^256 + 1 since it is the product of two
+ // 256-bit values.
+ //
+ // The algorithm is to reduce the result modulo the prime by subtracting
+ // multiples of the group order N. However, in order simplify carry
+ // propagation, this adds with the two's complement of N to achieve the same
+ // result.
+ //
+ // Since the two's complement of N has 127 leading zero bits, this will end
+ // up reducing the intermediate result from 512 bits to 385 bits, resulting
+ // in 13 32-bit terms. The reduced terms are assigned back to t0 through
+ // t12.
+ //
+ // Note that several of the intermediate calculations require adding 64-bit
+ // products together which would overflow a uint64, so a 96-bit accumulator
+ // is used instead.
+
+ // Terms for 2^(32*0).
+ var acc accumulator96
+ acc.n[0] = uint32(t0) // == acc.Add(t0) because acc is guaranteed to be 0.
+ acc.Add(t8 * uint64(orderComplementWordZero))
+ t0 = uint64(acc.n[0])
+ acc.Rsh32()
+
+ // Terms for 2^(32*1).
+ acc.Add(t1)
+ acc.Add(t8 * uint64(orderComplementWordOne))
+ acc.Add(t9 * uint64(orderComplementWordZero))
+ t1 = uint64(acc.n[0])
+ acc.Rsh32()
+
+ // Terms for 2^(32*2).
+ acc.Add(t2)
+ acc.Add(t8 * uint64(orderComplementWordTwo))
+ acc.Add(t9 * uint64(orderComplementWordOne))
+ acc.Add(t10 * uint64(orderComplementWordZero))
+ t2 = uint64(acc.n[0])
+ acc.Rsh32()
+
+ // Terms for 2^(32*3).
+ acc.Add(t3)
+ acc.Add(t8 * uint64(orderComplementWordThree))
+ acc.Add(t9 * uint64(orderComplementWordTwo))
+ acc.Add(t10 * uint64(orderComplementWordOne))
+ acc.Add(t11 * uint64(orderComplementWordZero))
+ t3 = uint64(acc.n[0])
+ acc.Rsh32()
+
+ // Terms for 2^(32*4).
+ acc.Add(t4)
+ acc.Add(t8) // * uint64(orderComplementWordFour) // * 1
+ acc.Add(t9 * uint64(orderComplementWordThree))
+ acc.Add(t10 * uint64(orderComplementWordTwo))
+ acc.Add(t11 * uint64(orderComplementWordOne))
+ acc.Add(t12 * uint64(orderComplementWordZero))
+ t4 = uint64(acc.n[0])
+ acc.Rsh32()
+
+ // Terms for 2^(32*5).
+ acc.Add(t5)
+ // acc.Add(t8 * uint64(orderComplementWordFive)) // 0
+ acc.Add(t9) // * uint64(orderComplementWordFour) // * 1
+ acc.Add(t10 * uint64(orderComplementWordThree))
+ acc.Add(t11 * uint64(orderComplementWordTwo))
+ acc.Add(t12 * uint64(orderComplementWordOne))
+ acc.Add(t13 * uint64(orderComplementWordZero))
+ t5 = uint64(acc.n[0])
+ acc.Rsh32()
+
+ // Terms for 2^(32*6).
+ acc.Add(t6)
+ // acc.Add(t8 * uint64(orderComplementWordSix)) // 0
+ // acc.Add(t9 * uint64(orderComplementWordFive)) // 0
+ acc.Add(t10) // * uint64(orderComplementWordFour)) // * 1
+ acc.Add(t11 * uint64(orderComplementWordThree))
+ acc.Add(t12 * uint64(orderComplementWordTwo))
+ acc.Add(t13 * uint64(orderComplementWordOne))
+ acc.Add(t14 * uint64(orderComplementWordZero))
+ t6 = uint64(acc.n[0])
+ acc.Rsh32()
+
+ // Terms for 2^(32*7).
+ acc.Add(t7)
+ // acc.Add(t8 * uint64(orderComplementWordSeven)) // 0
+ // acc.Add(t9 * uint64(orderComplementWordSix)) // 0
+ // acc.Add(t10 * uint64(orderComplementWordFive)) // 0
+ acc.Add(t11) // * uint64(orderComplementWordFour) // * 1
+ acc.Add(t12 * uint64(orderComplementWordThree))
+ acc.Add(t13 * uint64(orderComplementWordTwo))
+ acc.Add(t14 * uint64(orderComplementWordOne))
+ acc.Add(t15 * uint64(orderComplementWordZero))
+ t7 = uint64(acc.n[0])
+ acc.Rsh32()
+
+ // Terms for 2^(32*8).
+ // acc.Add(t9 * uint64(orderComplementWordSeven)) // 0
+ // acc.Add(t10 * uint64(orderComplementWordSix)) // 0
+ // acc.Add(t11 * uint64(orderComplementWordFive)) // 0
+ acc.Add(t12) // * uint64(orderComplementWordFour) // * 1
+ acc.Add(t13 * uint64(orderComplementWordThree))
+ acc.Add(t14 * uint64(orderComplementWordTwo))
+ acc.Add(t15 * uint64(orderComplementWordOne))
+ t8 = uint64(acc.n[0])
+ acc.Rsh32()
+
+ // Terms for 2^(32*9).
+ // acc.Add(t10 * uint64(orderComplementWordSeven)) // 0
+ // acc.Add(t11 * uint64(orderComplementWordSix)) // 0
+ // acc.Add(t12 * uint64(orderComplementWordFive)) // 0
+ acc.Add(t13) // * uint64(orderComplementWordFour) // * 1
+ acc.Add(t14 * uint64(orderComplementWordThree))
+ acc.Add(t15 * uint64(orderComplementWordTwo))
+ t9 = uint64(acc.n[0])
+ acc.Rsh32()
+
+ // Terms for 2^(32*10).
+ // acc.Add(t11 * uint64(orderComplementWordSeven)) // 0
+ // acc.Add(t12 * uint64(orderComplementWordSix)) // 0
+ // acc.Add(t13 * uint64(orderComplementWordFive)) // 0
+ acc.Add(t14) // * uint64(orderComplementWordFour) // * 1
+ acc.Add(t15 * uint64(orderComplementWordThree))
+ t10 = uint64(acc.n[0])
+ acc.Rsh32()
+
+ // Terms for 2^(32*11).
+ // acc.Add(t12 * uint64(orderComplementWordSeven)) // 0
+ // acc.Add(t13 * uint64(orderComplementWordSix)) // 0
+ // acc.Add(t14 * uint64(orderComplementWordFive)) // 0
+ acc.Add(t15) // * uint64(orderComplementWordFour) // * 1
+ t11 = uint64(acc.n[0])
+ acc.Rsh32()
+
+ // NOTE: All of the remaining multiplications for this iteration result in 0
+ // as they all involve multiplying by combinations of the fifth, sixth, and
+ // seventh words of the two's complement of N, which are 0, so skip them.
+
+ // Terms for 2^(32*12).
+ t12 = uint64(acc.n[0])
+ // acc.Rsh32() // No need since not used after this. Guaranteed to be 0.
+
+ // At this point, the result is reduced to fit within 385 bits, so reduce it
+ // again using the same method accordingly.
+ s.reduce385(t0, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12)
+}
+
+// Mul2 multiplies the passed two scalars together modulo the group order in
+// constant time and stores the result in s.
+//
+// The scalar is returned to support chaining. This enables syntax like:
+// s3.Mul2(s, s2).AddInt(1) so that s3 = (s * s2) + 1.
+func (s *ModNScalar) Mul2(val, val2 *ModNScalar) *ModNScalar {
+ // This could be done with for loops and an array to store the intermediate
+ // terms, but this unrolled version is significantly faster.
+
+ // The overall strategy employed here is:
+ // 1) Calculate the 512-bit product of the two scalars using the standard
+ // pencil-and-paper method.
+ // 2) Reduce the result modulo the prime by effectively subtracting
+ // multiples of the group order N (actually performed by adding multiples
+ // of the two's complement of N to avoid implementing subtraction).
+ // 3) Repeat step 2 noting that each iteration reduces the required number
+ // of bits by 127 because the two's complement of N has 127 leading zero
+ // bits.
+ // 4) Once reduced to 256 bits, call the existing reduce method to perform
+ // a final reduction as needed.
+ //
+ // Note that several of the intermediate calculations require adding 64-bit
+ // products together which would overflow a uint64, so a 96-bit accumulator
+ // is used instead.
+
+ // Terms for 2^(32*0).
+ var acc accumulator96
+ acc.Add(uint64(val.n[0]) * uint64(val2.n[0]))
+ t0 := uint64(acc.n[0])
+ acc.Rsh32()
+
+ // Terms for 2^(32*1).
+ acc.Add(uint64(val.n[0]) * uint64(val2.n[1]))
+ acc.Add(uint64(val.n[1]) * uint64(val2.n[0]))
+ t1 := uint64(acc.n[0])
+ acc.Rsh32()
+
+ // Terms for 2^(32*2).
+ acc.Add(uint64(val.n[0]) * uint64(val2.n[2]))
+ acc.Add(uint64(val.n[1]) * uint64(val2.n[1]))
+ acc.Add(uint64(val.n[2]) * uint64(val2.n[0]))
+ t2 := uint64(acc.n[0])
+ acc.Rsh32()
+
+ // Terms for 2^(32*3).
+ acc.Add(uint64(val.n[0]) * uint64(val2.n[3]))
+ acc.Add(uint64(val.n[1]) * uint64(val2.n[2]))
+ acc.Add(uint64(val.n[2]) * uint64(val2.n[1]))
+ acc.Add(uint64(val.n[3]) * uint64(val2.n[0]))
+ t3 := uint64(acc.n[0])
+ acc.Rsh32()
+
+ // Terms for 2^(32*4).
+ acc.Add(uint64(val.n[0]) * uint64(val2.n[4]))
+ acc.Add(uint64(val.n[1]) * uint64(val2.n[3]))
+ acc.Add(uint64(val.n[2]) * uint64(val2.n[2]))
+ acc.Add(uint64(val.n[3]) * uint64(val2.n[1]))
+ acc.Add(uint64(val.n[4]) * uint64(val2.n[0]))
+ t4 := uint64(acc.n[0])
+ acc.Rsh32()
+
+ // Terms for 2^(32*5).
+ acc.Add(uint64(val.n[0]) * uint64(val2.n[5]))
+ acc.Add(uint64(val.n[1]) * uint64(val2.n[4]))
+ acc.Add(uint64(val.n[2]) * uint64(val2.n[3]))
+ acc.Add(uint64(val.n[3]) * uint64(val2.n[2]))
+ acc.Add(uint64(val.n[4]) * uint64(val2.n[1]))
+ acc.Add(uint64(val.n[5]) * uint64(val2.n[0]))
+ t5 := uint64(acc.n[0])
+ acc.Rsh32()
+
+ // Terms for 2^(32*6).
+ acc.Add(uint64(val.n[0]) * uint64(val2.n[6]))
+ acc.Add(uint64(val.n[1]) * uint64(val2.n[5]))
+ acc.Add(uint64(val.n[2]) * uint64(val2.n[4]))
+ acc.Add(uint64(val.n[3]) * uint64(val2.n[3]))
+ acc.Add(uint64(val.n[4]) * uint64(val2.n[2]))
+ acc.Add(uint64(val.n[5]) * uint64(val2.n[1]))
+ acc.Add(uint64(val.n[6]) * uint64(val2.n[0]))
+ t6 := uint64(acc.n[0])
+ acc.Rsh32()
+
+ // Terms for 2^(32*7).
+ acc.Add(uint64(val.n[0]) * uint64(val2.n[7]))
+ acc.Add(uint64(val.n[1]) * uint64(val2.n[6]))
+ acc.Add(uint64(val.n[2]) * uint64(val2.n[5]))
+ acc.Add(uint64(val.n[3]) * uint64(val2.n[4]))
+ acc.Add(uint64(val.n[4]) * uint64(val2.n[3]))
+ acc.Add(uint64(val.n[5]) * uint64(val2.n[2]))
+ acc.Add(uint64(val.n[6]) * uint64(val2.n[1]))
+ acc.Add(uint64(val.n[7]) * uint64(val2.n[0]))
+ t7 := uint64(acc.n[0])
+ acc.Rsh32()
+
+ // Terms for 2^(32*8).
+ acc.Add(uint64(val.n[1]) * uint64(val2.n[7]))
+ acc.Add(uint64(val.n[2]) * uint64(val2.n[6]))
+ acc.Add(uint64(val.n[3]) * uint64(val2.n[5]))
+ acc.Add(uint64(val.n[4]) * uint64(val2.n[4]))
+ acc.Add(uint64(val.n[5]) * uint64(val2.n[3]))
+ acc.Add(uint64(val.n[6]) * uint64(val2.n[2]))
+ acc.Add(uint64(val.n[7]) * uint64(val2.n[1]))
+ t8 := uint64(acc.n[0])
+ acc.Rsh32()
+
+ // Terms for 2^(32*9).
+ acc.Add(uint64(val.n[2]) * uint64(val2.n[7]))
+ acc.Add(uint64(val.n[3]) * uint64(val2.n[6]))
+ acc.Add(uint64(val.n[4]) * uint64(val2.n[5]))
+ acc.Add(uint64(val.n[5]) * uint64(val2.n[4]))
+ acc.Add(uint64(val.n[6]) * uint64(val2.n[3]))
+ acc.Add(uint64(val.n[7]) * uint64(val2.n[2]))
+ t9 := uint64(acc.n[0])
+ acc.Rsh32()
+
+ // Terms for 2^(32*10).
+ acc.Add(uint64(val.n[3]) * uint64(val2.n[7]))
+ acc.Add(uint64(val.n[4]) * uint64(val2.n[6]))
+ acc.Add(uint64(val.n[5]) * uint64(val2.n[5]))
+ acc.Add(uint64(val.n[6]) * uint64(val2.n[4]))
+ acc.Add(uint64(val.n[7]) * uint64(val2.n[3]))
+ t10 := uint64(acc.n[0])
+ acc.Rsh32()
+
+ // Terms for 2^(32*11).
+ acc.Add(uint64(val.n[4]) * uint64(val2.n[7]))
+ acc.Add(uint64(val.n[5]) * uint64(val2.n[6]))
+ acc.Add(uint64(val.n[6]) * uint64(val2.n[5]))
+ acc.Add(uint64(val.n[7]) * uint64(val2.n[4]))
+ t11 := uint64(acc.n[0])
+ acc.Rsh32()
+
+ // Terms for 2^(32*12).
+ acc.Add(uint64(val.n[5]) * uint64(val2.n[7]))
+ acc.Add(uint64(val.n[6]) * uint64(val2.n[6]))
+ acc.Add(uint64(val.n[7]) * uint64(val2.n[5]))
+ t12 := uint64(acc.n[0])
+ acc.Rsh32()
+
+ // Terms for 2^(32*13).
+ acc.Add(uint64(val.n[6]) * uint64(val2.n[7]))
+ acc.Add(uint64(val.n[7]) * uint64(val2.n[6]))
+ t13 := uint64(acc.n[0])
+ acc.Rsh32()
+
+ // Terms for 2^(32*14).
+ acc.Add(uint64(val.n[7]) * uint64(val2.n[7]))
+ t14 := uint64(acc.n[0])
+ acc.Rsh32()
+
+ // What's left is for 2^(32*15).
+ t15 := uint64(acc.n[0])
+ // acc.Rsh32() // No need since not used after this. Guaranteed to be 0.
+
+ // At this point, all of the terms are grouped into their respective base
+ // and occupy up to 512 bits. Reduce the result accordingly.
+ s.reduce512(t0, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14,
+ t15)
+ return s
+}
+
+// Mul multiplies the passed scalar with the existing one modulo the group order
+// in constant time and stores the result in s.
+//
+// The scalar is returned to support chaining. This enables syntax like:
+// s.Mul(s2).AddInt(1) so that s = (s * s2) + 1.
+func (s *ModNScalar) Mul(val *ModNScalar) *ModNScalar {
+ return s.Mul2(s, val)
+}
+
+// SquareVal squares the passed scalar modulo the group order in constant time
+// and stores the result in s.
+//
+// The scalar is returned to support chaining. This enables syntax like:
+// s3.SquareVal(s).Mul(s) so that s3 = s^2 * s = s^3.
+func (s *ModNScalar) SquareVal(val *ModNScalar) *ModNScalar {
+ // This could technically be optimized slightly to take advantage of the
+ // fact that many of the intermediate calculations in squaring are just
+ // doubling, however, benchmarking has shown that due to the need to use a
+ // 96-bit accumulator, any savings are essentially offset by that and
+ // consequently there is no real difference in performance over just
+ // multiplying the value by itself to justify the extra code for now. This
+ // can be revisited in the future if it becomes a bottleneck in practice.
+
+ return s.Mul2(val, val)
+}
+
+// Square squares the scalar modulo the group order in constant time. The
+// existing scalar is modified.
+//
+// The scalar is returned to support chaining. This enables syntax like:
+// s.Square().Mul(s2) so that s = s^2 * s2.
+func (s *ModNScalar) Square() *ModNScalar {
+ return s.SquareVal(s)
+}
+
+// NegateVal negates the passed scalar modulo the group order and stores the
+// result in s in constant time.
+//
+// The scalar is returned to support chaining. This enables syntax like:
+// s.NegateVal(s2).AddInt(1) so that s = -s2 + 1.
+func (s *ModNScalar) NegateVal(val *ModNScalar) *ModNScalar {
+ // Since the scalar is already in the range 0 <= val < N, where N is the
+ // group order, negation modulo the group order is just the group order
+ // minus the value. This implies that the result will always be in the
+ // desired range with the sole exception of 0 because N - 0 = N itself.
+ //
+ // Therefore, in order to avoid the need to reduce the result for every
+ // other case in order to achieve constant time, this creates a mask that is
+ // all 0s in the case of the scalar being negated is 0 and all 1s otherwise
+ // and bitwise ands that mask with each word.
+ //
+ // Finally, to simplify the carry propagation, this adds the two's
+ // complement of the scalar to N in order to achieve the same result.
+ bits := val.n[0] | val.n[1] | val.n[2] | val.n[3] | val.n[4] | val.n[5] |
+ val.n[6] | val.n[7]
+ mask := uint64(uint32Mask * constantTimeNotEq(bits, 0))
+ c := uint64(orderWordZero) + (uint64(^val.n[0]) + 1)
+ s.n[0] = uint32(c & mask)
+ c = (c >> 32) + uint64(orderWordOne) + uint64(^val.n[1])
+ s.n[1] = uint32(c & mask)
+ c = (c >> 32) + uint64(orderWordTwo) + uint64(^val.n[2])
+ s.n[2] = uint32(c & mask)
+ c = (c >> 32) + uint64(orderWordThree) + uint64(^val.n[3])
+ s.n[3] = uint32(c & mask)
+ c = (c >> 32) + uint64(orderWordFour) + uint64(^val.n[4])
+ s.n[4] = uint32(c & mask)
+ c = (c >> 32) + uint64(orderWordFive) + uint64(^val.n[5])
+ s.n[5] = uint32(c & mask)
+ c = (c >> 32) + uint64(orderWordSix) + uint64(^val.n[6])
+ s.n[6] = uint32(c & mask)
+ c = (c >> 32) + uint64(orderWordSeven) + uint64(^val.n[7])
+ s.n[7] = uint32(c & mask)
+ return s
+}
+
+// Negate negates the scalar modulo the group order in constant time. The
+// existing scalar is modified.
+//
+// The scalar is returned to support chaining. This enables syntax like:
+// s.Negate().AddInt(1) so that s = -s + 1.
+func (s *ModNScalar) Negate() *ModNScalar {
+ return s.NegateVal(s)
+}
+
+// InverseValNonConst finds the modular multiplicative inverse of the passed
+// scalar and stores result in s in *non-constant* time.
+//
+// The scalar is returned to support chaining. This enables syntax like:
+// s3.InverseVal(s1).Mul(s2) so that s3 = s1^-1 * s2.
+func (s *ModNScalar) InverseValNonConst(val *ModNScalar) *ModNScalar {
+ // This is making use of big integers for now. Ideally it will be replaced
+ // with an implementation that does not depend on big integers.
+ valBytes := val.Bytes()
+ bigVal := new(big.Int).SetBytes(valBytes[:])
+ bigVal.ModInverse(bigVal, curveParams.N)
+ s.SetByteSlice(bigVal.Bytes())
+ return s
+}
+
+// InverseNonConst finds the modular multiplicative inverse of the scalar in
+// *non-constant* time. The existing scalar is modified.
+//
+// The scalar is returned to support chaining. This enables syntax like:
+// s.Inverse().Mul(s2) so that s = s^-1 * s2.
+func (s *ModNScalar) InverseNonConst() *ModNScalar {
+ return s.InverseValNonConst(s)
+}
+
+// IsOverHalfOrder returns whether or not the scalar exceeds the group order
+// divided by 2 in constant time.
+func (s *ModNScalar) IsOverHalfOrder() bool {
+ // The intuition here is that the scalar is greater than half of the group
+ // order if one of the higher individual words is greater than the
+ // corresponding word of the half group order and all higher words in the
+ // scalar are equal to their corresponding word of the half group order.
+ //
+ // Note that the words 4, 5, and 6 are all the max uint32 value, so there is
+ // no need to test if those individual words of the scalar exceeds them,
+ // hence, only equality is checked for them.
+ result := constantTimeGreater(s.n[7], halfOrderWordSeven)
+ highWordsEqual := constantTimeEq(s.n[7], halfOrderWordSeven)
+ highWordsEqual &= constantTimeEq(s.n[6], halfOrderWordSix)
+ highWordsEqual &= constantTimeEq(s.n[5], halfOrderWordFive)
+ highWordsEqual &= constantTimeEq(s.n[4], halfOrderWordFour)
+ result |= highWordsEqual & constantTimeGreater(s.n[3], halfOrderWordThree)
+ highWordsEqual &= constantTimeEq(s.n[3], halfOrderWordThree)
+ result |= highWordsEqual & constantTimeGreater(s.n[2], halfOrderWordTwo)
+ highWordsEqual &= constantTimeEq(s.n[2], halfOrderWordTwo)
+ result |= highWordsEqual & constantTimeGreater(s.n[1], halfOrderWordOne)
+ highWordsEqual &= constantTimeEq(s.n[1], halfOrderWordOne)
+ result |= highWordsEqual & constantTimeGreater(s.n[0], halfOrderWordZero)
+
+ return result != 0
+}
diff --git a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/nonce.go b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/nonce.go
new file mode 100644
index 0000000..81b205d
--- /dev/null
+++ b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/nonce.go
@@ -0,0 +1,263 @@
+// Copyright (c) 2013-2014 The btcsuite developers
+// Copyright (c) 2015-2020 The Decred developers
+// Use of this source code is governed by an ISC
+// license that can be found in the LICENSE file.
+
+package secp256k1
+
+import (
+ "bytes"
+ "crypto/sha256"
+ "hash"
+)
+
+// References:
+// [GECC]: Guide to Elliptic Curve Cryptography (Hankerson, Menezes, Vanstone)
+//
+// [ISO/IEC 8825-1]: Information technology — ASN.1 encoding rules:
+// Specification of Basic Encoding Rules (BER), Canonical Encoding Rules
+// (CER) and Distinguished Encoding Rules (DER)
+//
+// [SEC1]: Elliptic Curve Cryptography (May 31, 2009, Version 2.0)
+// https://www.secg.org/sec1-v2.pdf
+
+var (
+ // singleZero is used during RFC6979 nonce generation. It is provided
+ // here to avoid the need to create it multiple times.
+ singleZero = []byte{0x00}
+
+ // zeroInitializer is used during RFC6979 nonce generation. It is provided
+ // here to avoid the need to create it multiple times.
+ zeroInitializer = bytes.Repeat([]byte{0x00}, sha256.BlockSize)
+
+ // singleOne is used during RFC6979 nonce generation. It is provided
+ // here to avoid the need to create it multiple times.
+ singleOne = []byte{0x01}
+
+ // oneInitializer is used during RFC6979 nonce generation. It is provided
+ // here to avoid the need to create it multiple times.
+ oneInitializer = bytes.Repeat([]byte{0x01}, sha256.Size)
+)
+
+// hmacsha256 implements a resettable version of HMAC-SHA256.
+type hmacsha256 struct {
+ inner, outer hash.Hash
+ ipad, opad [sha256.BlockSize]byte
+}
+
+// Write adds data to the running hash.
+func (h *hmacsha256) Write(p []byte) {
+ h.inner.Write(p)
+}
+
+// initKey initializes the HMAC-SHA256 instance to the provided key.
+func (h *hmacsha256) initKey(key []byte) {
+ // Hash the key if it is too large.
+ if len(key) > sha256.BlockSize {
+ h.outer.Write(key)
+ key = h.outer.Sum(nil)
+ }
+ copy(h.ipad[:], key)
+ copy(h.opad[:], key)
+ for i := range h.ipad {
+ h.ipad[i] ^= 0x36
+ }
+ for i := range h.opad {
+ h.opad[i] ^= 0x5c
+ }
+ h.inner.Write(h.ipad[:])
+}
+
+// ResetKey resets the HMAC-SHA256 to its initial state and then initializes it
+// with the provided key. It is equivalent to creating a new instance with the
+// provided key without allocating more memory.
+func (h *hmacsha256) ResetKey(key []byte) {
+ h.inner.Reset()
+ h.outer.Reset()
+ copy(h.ipad[:], zeroInitializer)
+ copy(h.opad[:], zeroInitializer)
+ h.initKey(key)
+}
+
+// Resets the HMAC-SHA256 to its initial state using the current key.
+func (h *hmacsha256) Reset() {
+ h.inner.Reset()
+ h.inner.Write(h.ipad[:])
+}
+
+// Sum returns the hash of the written data.
+func (h *hmacsha256) Sum() []byte {
+ h.outer.Reset()
+ h.outer.Write(h.opad[:])
+ h.outer.Write(h.inner.Sum(nil))
+ return h.outer.Sum(nil)
+}
+
+// newHMACSHA256 returns a new HMAC-SHA256 hasher using the provided key.
+func newHMACSHA256(key []byte) *hmacsha256 {
+ h := new(hmacsha256)
+ h.inner = sha256.New()
+ h.outer = sha256.New()
+ h.initKey(key)
+ return h
+}
+
+// NonceRFC6979 generates a nonce deterministically according to RFC 6979 using
+// HMAC-SHA256 for the hashing function. It takes a 32-byte hash as an input
+// and returns a 32-byte nonce to be used for deterministic signing. The extra
+// and version arguments are optional, but allow additional data to be added to
+// the input of the HMAC. When provided, the extra data must be 32-bytes and
+// version must be 16 bytes or they will be ignored.
+//
+// Finally, the extraIterations parameter provides a method to produce a stream
+// of deterministic nonces to ensure the signing code is able to produce a nonce
+// that results in a valid signature in the extremely unlikely event the
+// original nonce produced results in an invalid signature (e.g. R == 0).
+// Signing code should start with 0 and increment it if necessary.
+func NonceRFC6979(privKey []byte, hash []byte, extra []byte, version []byte, extraIterations uint32) *ModNScalar {
+ // Input to HMAC is the 32-byte private key and the 32-byte hash. In
+ // addition, it may include the optional 32-byte extra data and 16-byte
+ // version. Create a fixed-size array to avoid extra allocs and slice it
+ // properly.
+ const (
+ privKeyLen = 32
+ hashLen = 32
+ extraLen = 32
+ versionLen = 16
+ )
+ var keyBuf [privKeyLen + hashLen + extraLen + versionLen]byte
+
+ // Truncate rightmost bytes of private key and hash if they are too long and
+ // leave left padding of zeros when they're too short.
+ if len(privKey) > privKeyLen {
+ privKey = privKey[:privKeyLen]
+ }
+ if len(hash) > hashLen {
+ hash = hash[:hashLen]
+ }
+ offset := privKeyLen - len(privKey) // Zero left padding if needed.
+ offset += copy(keyBuf[offset:], privKey)
+ offset += hashLen - len(hash) // Zero left padding if needed.
+ offset += copy(keyBuf[offset:], hash)
+ if len(extra) == extraLen {
+ offset += copy(keyBuf[offset:], extra)
+ if len(version) == versionLen {
+ offset += copy(keyBuf[offset:], version)
+ }
+ } else if len(version) == versionLen {
+ // When the version was specified, but not the extra data, leave the
+ // extra data portion all zero.
+ offset += privKeyLen
+ offset += copy(keyBuf[offset:], version)
+ }
+ key := keyBuf[:offset]
+
+ // Step B.
+ //
+ // V = 0x01 0x01 0x01 ... 0x01 such that the length of V, in bits, is
+ // equal to 8*ceil(hashLen/8).
+ //
+ // Note that since the hash length is a multiple of 8 for the chosen hash
+ // function in this optimized implementation, the result is just the hash
+ // length, so avoid the extra calculations. Also, since it isn't modified,
+ // start with a global value.
+ v := oneInitializer
+
+ // Step C (Go zeroes all allocated memory).
+ //
+ // K = 0x00 0x00 0x00 ... 0x00 such that the length of K, in bits, is
+ // equal to 8*ceil(hashLen/8).
+ //
+ // As above, since the hash length is a multiple of 8 for the chosen hash
+ // function in this optimized implementation, the result is just the hash
+ // length, so avoid the extra calculations.
+ k := zeroInitializer[:hashLen]
+
+ // Step D.
+ //
+ // K = HMAC_K(V || 0x00 || int2octets(x) || bits2octets(h1))
+ //
+ // Note that key is the "int2octets(x) || bits2octets(h1)" portion along
+ // with potential additional data as described by section 3.6 of the RFC.
+ hasher := newHMACSHA256(k)
+ hasher.Write(oneInitializer)
+ hasher.Write(singleZero[:])
+ hasher.Write(key)
+ k = hasher.Sum()
+
+ // Step E.
+ //
+ // V = HMAC_K(V)
+ hasher.ResetKey(k)
+ hasher.Write(v)
+ v = hasher.Sum()
+
+ // Step F.
+ //
+ // K = HMAC_K(V || 0x01 || int2octets(x) || bits2octets(h1))
+ //
+ // Note that key is the "int2octets(x) || bits2octets(h1)" portion along
+ // with potential additional data as described by section 3.6 of the RFC.
+ hasher.Reset()
+ hasher.Write(v)
+ hasher.Write(singleOne[:])
+ hasher.Write(key[:])
+ k = hasher.Sum()
+
+ // Step G.
+ //
+ // V = HMAC_K(V)
+ hasher.ResetKey(k)
+ hasher.Write(v)
+ v = hasher.Sum()
+
+ // Step H.
+ //
+ // Repeat until the value is nonzero and less than the curve order.
+ var generated uint32
+ for {
+ // Step H1 and H2.
+ //
+ // Set T to the empty sequence. The length of T (in bits) is denoted
+ // tlen; thus, at that point, tlen = 0.
+ //
+ // While tlen < qlen, do the following:
+ // V = HMAC_K(V)
+ // T = T || V
+ //
+ // Note that because the hash function output is the same length as the
+ // private key in this optimized implementation, there is no need to
+ // loop or create an intermediate T.
+ hasher.Reset()
+ hasher.Write(v)
+ v = hasher.Sum()
+
+ // Step H3.
+ //
+ // k = bits2int(T)
+ // If k is within the range [1,q-1], return it.
+ //
+ // Otherwise, compute:
+ // K = HMAC_K(V || 0x00)
+ // V = HMAC_K(V)
+ var secret ModNScalar
+ overflow := secret.SetByteSlice(v)
+ if !overflow && !secret.IsZero() {
+ generated++
+ if generated > extraIterations {
+ return &secret
+ }
+ }
+
+ // K = HMAC_K(V || 0x00)
+ hasher.Reset()
+ hasher.Write(v)
+ hasher.Write(singleZero[:])
+ k = hasher.Sum()
+
+ // V = HMAC_K(V)
+ hasher.ResetKey(k)
+ hasher.Write(v)
+ v = hasher.Sum()
+ }
+}
diff --git a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/privkey.go b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/privkey.go
new file mode 100644
index 0000000..ca3e8da
--- /dev/null
+++ b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/privkey.go
@@ -0,0 +1,111 @@
+// Copyright (c) 2013-2014 The btcsuite developers
+// Copyright (c) 2015-2023 The Decred developers
+// Use of this source code is governed by an ISC
+// license that can be found in the LICENSE file.
+
+package secp256k1
+
+import (
+ cryptorand "crypto/rand"
+ "io"
+)
+
+// PrivateKey provides facilities for working with secp256k1 private keys within
+// this package and includes functionality such as serializing and parsing them
+// as well as computing their associated public key.
+type PrivateKey struct {
+ Key ModNScalar
+}
+
+// NewPrivateKey instantiates a new private key from a scalar encoded as a
+// big integer.
+func NewPrivateKey(key *ModNScalar) *PrivateKey {
+ return &PrivateKey{Key: *key}
+}
+
+// PrivKeyFromBytes returns a private based on the provided byte slice which is
+// interpreted as an unsigned 256-bit big-endian integer in the range [0, N-1],
+// where N is the order of the curve.
+//
+// WARNING: This means passing a slice with more than 32 bytes is truncated and
+// that truncated value is reduced modulo N. Further, 0 is not a valid private
+// key. It is up to the caller to provide a value in the appropriate range of
+// [1, N-1]. Failure to do so will either result in an invalid private key or
+// potentially weak private keys that have bias that could be exploited.
+//
+// This function primarily exists to provide a mechanism for converting
+// serialized private keys that are already known to be good.
+//
+// Typically callers should make use of GeneratePrivateKey or
+// GeneratePrivateKeyFromRand when creating private keys since they properly
+// handle generation of appropriate values.
+func PrivKeyFromBytes(privKeyBytes []byte) *PrivateKey {
+ var privKey PrivateKey
+ privKey.Key.SetByteSlice(privKeyBytes)
+ return &privKey
+}
+
+// generatePrivateKey generates and returns a new private key that is suitable
+// for use with secp256k1 using the provided reader as a source of entropy. The
+// provided reader must be a source of cryptographically secure randomness to
+// avoid weak private keys.
+func generatePrivateKey(rand io.Reader) (*PrivateKey, error) {
+ // The group order is close enough to 2^256 that there is only roughly a 1
+ // in 2^128 chance of generating an invalid private key, so this loop will
+ // virtually never run more than a single iteration in practice.
+ var key PrivateKey
+ var b32 [32]byte
+ for valid := false; !valid; {
+ if _, err := io.ReadFull(rand, b32[:]); err != nil {
+ return nil, err
+ }
+
+ // The private key is only valid when it is in the range [1, N-1], where
+ // N is the order of the curve.
+ overflow := key.Key.SetBytes(&b32)
+ valid = (key.Key.IsZeroBit() | overflow) == 0
+ }
+ zeroArray32(&b32)
+
+ return &key, nil
+}
+
+// GeneratePrivateKey generates and returns a new cryptographically secure
+// private key that is suitable for use with secp256k1.
+func GeneratePrivateKey() (*PrivateKey, error) {
+ return generatePrivateKey(cryptorand.Reader)
+}
+
+// GeneratePrivateKeyFromRand generates a private key that is suitable for use
+// with secp256k1 using the provided reader as a source of entropy. The
+// provided reader must be a source of cryptographically secure randomness, such
+// as [crypto/rand.Reader], to avoid weak private keys.
+func GeneratePrivateKeyFromRand(rand io.Reader) (*PrivateKey, error) {
+ return generatePrivateKey(rand)
+}
+
+// PubKey computes and returns the public key corresponding to this private key.
+func (p *PrivateKey) PubKey() *PublicKey {
+ var result JacobianPoint
+ ScalarBaseMultNonConst(&p.Key, &result)
+ result.ToAffine()
+ return NewPublicKey(&result.X, &result.Y)
+}
+
+// Zero manually clears the memory associated with the private key. This can be
+// used to explicitly clear key material from memory for enhanced security
+// against memory scraping.
+func (p *PrivateKey) Zero() {
+ p.Key.Zero()
+}
+
+// PrivKeyBytesLen defines the length in bytes of a serialized private key.
+const PrivKeyBytesLen = 32
+
+// Serialize returns the private key as a 256-bit big-endian binary-encoded
+// number, padded to a length of 32 bytes.
+func (p PrivateKey) Serialize() []byte {
+ var privKeyBytes [PrivKeyBytesLen]byte
+ p.Key.PutBytes(&privKeyBytes)
+ return privKeyBytes[:]
+}
diff --git a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/pubkey.go b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/pubkey.go
new file mode 100644
index 0000000..54c54be
--- /dev/null
+++ b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/pubkey.go
@@ -0,0 +1,237 @@
+// Copyright (c) 2013-2014 The btcsuite developers
+// Copyright (c) 2015-2022 The Decred developers
+// Use of this source code is governed by an ISC
+// license that can be found in the LICENSE file.
+
+package secp256k1
+
+// References:
+// [SEC1] Elliptic Curve Cryptography
+// https://www.secg.org/sec1-v2.pdf
+//
+// [SEC2] Recommended Elliptic Curve Domain Parameters
+// https://www.secg.org/sec2-v2.pdf
+//
+// [ANSI X9.62-1998] Public Key Cryptography For The Financial Services
+// Industry: The Elliptic Curve Digital Signature Algorithm (ECDSA)
+
+import (
+ "fmt"
+)
+
+const (
+ // PubKeyBytesLenCompressed is the number of bytes of a serialized
+ // compressed public key.
+ PubKeyBytesLenCompressed = 33
+
+ // PubKeyBytesLenUncompressed is the number of bytes of a serialized
+ // uncompressed public key.
+ PubKeyBytesLenUncompressed = 65
+
+ // PubKeyFormatCompressedEven is the identifier prefix byte for a public key
+ // whose Y coordinate is even when serialized in the compressed format per
+ // section 2.3.4 of [SEC1](https://secg.org/sec1-v2.pdf#subsubsection.2.3.4).
+ PubKeyFormatCompressedEven byte = 0x02
+
+ // PubKeyFormatCompressedOdd is the identifier prefix byte for a public key
+ // whose Y coordinate is odd when serialized in the compressed format per
+ // section 2.3.4 of [SEC1](https://secg.org/sec1-v2.pdf#subsubsection.2.3.4).
+ PubKeyFormatCompressedOdd byte = 0x03
+
+ // PubKeyFormatUncompressed is the identifier prefix byte for a public key
+ // when serialized according in the uncompressed format per section 2.3.3 of
+ // [SEC1](https://secg.org/sec1-v2.pdf#subsubsection.2.3.3).
+ PubKeyFormatUncompressed byte = 0x04
+
+ // PubKeyFormatHybridEven is the identifier prefix byte for a public key
+ // whose Y coordinate is even when serialized according to the hybrid format
+ // per section 4.3.6 of [ANSI X9.62-1998].
+ //
+ // NOTE: This format makes little sense in practice an therefore this
+ // package will not produce public keys serialized in this format. However,
+ // it will parse them since they exist in the wild.
+ PubKeyFormatHybridEven byte = 0x06
+
+ // PubKeyFormatHybridOdd is the identifier prefix byte for a public key
+ // whose Y coordingate is odd when serialized according to the hybrid format
+ // per section 4.3.6 of [ANSI X9.62-1998].
+ //
+ // NOTE: This format makes little sense in practice an therefore this
+ // package will not produce public keys serialized in this format. However,
+ // it will parse them since they exist in the wild.
+ PubKeyFormatHybridOdd byte = 0x07
+)
+
+// PublicKey provides facilities for efficiently working with secp256k1 public
+// keys within this package and includes functions to serialize in both
+// uncompressed and compressed SEC (Standards for Efficient Cryptography)
+// formats.
+type PublicKey struct {
+ x FieldVal
+ y FieldVal
+}
+
+// NewPublicKey instantiates a new public key with the given x and y
+// coordinates.
+//
+// It should be noted that, unlike ParsePubKey, since this accepts arbitrary x
+// and y coordinates, it allows creation of public keys that are not valid
+// points on the secp256k1 curve. The IsOnCurve method of the returned instance
+// can be used to determine validity.
+func NewPublicKey(x, y *FieldVal) *PublicKey {
+ var pubKey PublicKey
+ pubKey.x.Set(x)
+ pubKey.y.Set(y)
+ return &pubKey
+}
+
+// ParsePubKey parses a secp256k1 public key encoded according to the format
+// specified by ANSI X9.62-1998, which means it is also compatible with the
+// SEC (Standards for Efficient Cryptography) specification which is a subset of
+// the former. In other words, it supports the uncompressed, compressed, and
+// hybrid formats as follows:
+//
+// Compressed:
+//
+// <32-byte X coordinate>
+//
+// Uncompressed:
+//
+// <32-byte X coordinate><32-byte Y coordinate>
+//
+// Hybrid:
+//
+// <32-byte X coordinate><32-byte Y coordinate>
+//
+// NOTE: The hybrid format makes little sense in practice an therefore this
+// package will not produce public keys serialized in this format. However,
+// this function will properly parse them since they exist in the wild.
+func ParsePubKey(serialized []byte) (key *PublicKey, err error) {
+ var x, y FieldVal
+ switch len(serialized) {
+ case PubKeyBytesLenUncompressed:
+ // Reject unsupported public key formats for the given length.
+ format := serialized[0]
+ switch format {
+ case PubKeyFormatUncompressed:
+ case PubKeyFormatHybridEven, PubKeyFormatHybridOdd:
+ default:
+ str := fmt.Sprintf("invalid public key: unsupported format: %x",
+ format)
+ return nil, makeError(ErrPubKeyInvalidFormat, str)
+ }
+
+ // Parse the x and y coordinates while ensuring that they are in the
+ // allowed range.
+ if overflow := x.SetByteSlice(serialized[1:33]); overflow {
+ str := "invalid public key: x >= field prime"
+ return nil, makeError(ErrPubKeyXTooBig, str)
+ }
+ if overflow := y.SetByteSlice(serialized[33:]); overflow {
+ str := "invalid public key: y >= field prime"
+ return nil, makeError(ErrPubKeyYTooBig, str)
+ }
+
+ // Ensure the oddness of the y coordinate matches the specified format
+ // for hybrid public keys.
+ if format == PubKeyFormatHybridEven || format == PubKeyFormatHybridOdd {
+ wantOddY := format == PubKeyFormatHybridOdd
+ if y.IsOdd() != wantOddY {
+ str := fmt.Sprintf("invalid public key: y oddness does not "+
+ "match specified value of %v", wantOddY)
+ return nil, makeError(ErrPubKeyMismatchedOddness, str)
+ }
+ }
+
+ // Reject public keys that are not on the secp256k1 curve.
+ if !isOnCurve(&x, &y) {
+ str := fmt.Sprintf("invalid public key: [%v,%v] not on secp256k1 "+
+ "curve", x, y)
+ return nil, makeError(ErrPubKeyNotOnCurve, str)
+ }
+
+ case PubKeyBytesLenCompressed:
+ // Reject unsupported public key formats for the given length.
+ format := serialized[0]
+ switch format {
+ case PubKeyFormatCompressedEven, PubKeyFormatCompressedOdd:
+ default:
+ str := fmt.Sprintf("invalid public key: unsupported format: %x",
+ format)
+ return nil, makeError(ErrPubKeyInvalidFormat, str)
+ }
+
+ // Parse the x coordinate while ensuring that it is in the allowed
+ // range.
+ if overflow := x.SetByteSlice(serialized[1:33]); overflow {
+ str := "invalid public key: x >= field prime"
+ return nil, makeError(ErrPubKeyXTooBig, str)
+ }
+
+ // Attempt to calculate the y coordinate for the given x coordinate such
+ // that the result pair is a point on the secp256k1 curve and the
+ // solution with desired oddness is chosen.
+ wantOddY := format == PubKeyFormatCompressedOdd
+ if !DecompressY(&x, wantOddY, &y) {
+ str := fmt.Sprintf("invalid public key: x coordinate %v is not on "+
+ "the secp256k1 curve", x)
+ return nil, makeError(ErrPubKeyNotOnCurve, str)
+ }
+ y.Normalize()
+
+ default:
+ str := fmt.Sprintf("malformed public key: invalid length: %d",
+ len(serialized))
+ return nil, makeError(ErrPubKeyInvalidLen, str)
+ }
+
+ return NewPublicKey(&x, &y), nil
+}
+
+// SerializeUncompressed serializes a public key in the 65-byte uncompressed
+// format.
+func (p PublicKey) SerializeUncompressed() []byte {
+ // 0x04 || 32-byte x coordinate || 32-byte y coordinate
+ var b [PubKeyBytesLenUncompressed]byte
+ b[0] = PubKeyFormatUncompressed
+ p.x.PutBytesUnchecked(b[1:33])
+ p.y.PutBytesUnchecked(b[33:65])
+ return b[:]
+}
+
+// SerializeCompressed serializes a public key in the 33-byte compressed format.
+func (p PublicKey) SerializeCompressed() []byte {
+ // Choose the format byte depending on the oddness of the Y coordinate.
+ format := PubKeyFormatCompressedEven
+ if p.y.IsOdd() {
+ format = PubKeyFormatCompressedOdd
+ }
+
+ // 0x02 or 0x03 || 32-byte x coordinate
+ var b [PubKeyBytesLenCompressed]byte
+ b[0] = format
+ p.x.PutBytesUnchecked(b[1:33])
+ return b[:]
+}
+
+// IsEqual compares this public key instance to the one passed, returning true
+// if both public keys are equivalent. A public key is equivalent to another,
+// if they both have the same X and Y coordinates.
+func (p *PublicKey) IsEqual(otherPubKey *PublicKey) bool {
+ return p.x.Equals(&otherPubKey.x) && p.y.Equals(&otherPubKey.y)
+}
+
+// AsJacobian converts the public key into a Jacobian point with Z=1 and stores
+// the result in the provided result param. This allows the public key to be
+// treated a Jacobian point in the secp256k1 group in calculations.
+func (p *PublicKey) AsJacobian(result *JacobianPoint) {
+ result.X.Set(&p.x)
+ result.Y.Set(&p.y)
+ result.Z.SetInt(1)
+}
+
+// IsOnCurve returns whether or not the public key represents a point on the
+// secp256k1 curve.
+func (p *PublicKey) IsOnCurve() bool {
+ return isOnCurve(&p.x, &p.y)
+}
diff --git a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/schnorr/README.md b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/schnorr/README.md
new file mode 100644
index 0000000..78fc1ae
--- /dev/null
+++ b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/schnorr/README.md
@@ -0,0 +1,334 @@
+schnorr
+=======
+
+[![Build Status](https://github.com/decred/dcrd/workflows/Build%20and%20Test/badge.svg)](https://github.com/decred/dcrd/actions)
+[![ISC License](https://img.shields.io/badge/license-ISC-blue.svg)](http://copyfree.org)
+[![GoDoc](https://img.shields.io/badge/godoc-reference-blue.svg)](https://pkg.go.dev/github.com/decred/dcrd/dcrec/secp256k1/v4/schnorr)
+
+Package schnorr provides custom Schnorr signing and verification via secp256k1.
+
+This package provides data structures and functions necessary to produce and
+verify deterministic canonical Schnorr signatures using a custom scheme named
+`EC-Schnorr-DCRv0` that is described herein. The signatures and implementation
+are optimized specifically for the secp256k1 curve. See
+https://www.secg.org/sec2-v2.pdf for details on the secp256k1 standard.
+
+It also provides functions to parse and serialize the Schnorr signatures
+according to the specification described herein.
+
+A comprehensive suite of tests is provided to ensure proper functionality.
+
+## Overview
+
+A Schnorr signature is a digital signature scheme that is known for its
+simplicity, provable security and efficient generation of short signatures.
+
+It provides many advantages over ECDSA signatures that make them ideal for use
+with the only real downside being that they are not well standardized at the
+time of this writing.
+
+Some of the advantages over ECDSA include:
+
+* They are linear which makes them easier to aggregate and use in protocols that
+ build on them such as multi-party signatures, threshold signatures, adaptor
+ signatures, and blind signatures
+* They are provably secure with weaker assumptions than the best known security
+ proofs for ECDSA
+ * Specifically Schnorr signatures are provably secure under SUF-CMA (Strong
+ Existential Unforgeability under Chosen Message Attack) in the ROM (Random
+ Oracle Model) which guarantees that as long as the hash function behaves
+ ideally, the only way to break Schnorr signatures is by solving the ECDLP
+ (Elliptic Curve Discrete Logarithm Problem).
+* Their relatively straightforward and efficient aggregation properties make
+ them excellent for scalability and allow them to provide some nice privacy
+ characteristics
+* They support faster batch verification unlike the standardized version of
+ ECDSA signatures
+
+## Custom Schnorr-based Signature Scheme
+
+As mentioned in the overview, the primary downside of Schnorr signatures for
+elliptic curves is that they are not standardized as well as ECDSA signatures
+which means there are a number of variations that are not compatible with each
+other.
+
+In addition, many of the standardization attempts have various disadvantages
+that make them unsuitable for use in Decred. Some of these details will be
+discussed further in the Design section along with providing some insight into
+the design decisions made.
+
+Consequently, this package implements a custom Schnorr-based signature scheme
+named `EC-Schnorr-DCRv0` suitable for use in Decred.
+
+The following provides a high-level overview of the key design features of the
+scheme:
+
+* Uses signatures of the form `(R, s)`
+* Produces 64-byte signatures by only encoding the `x` coordinate of `R`
+* Enforces even `y` coordinates for `R` to support efficient verification by
+ disambiguating the two possible `y` coordinates
+* Canonically encodes by both components of the signature with 32-bytes each
+* Uses BLAKE-256 with 14 rounds for the hash function to calculate challenge `e`
+* Uses RFC6979 to obviate the need for an entropy source at signing time
+* Produces deterministic signatures for a given message and private key pair
+
+## Design Details And Rationale
+
+As previously mentioned, unfortunately, Schnorr signatures for elliptic curves
+are not standardized as well as ECDSA signatures which means there are a number
+of variations that are not compatible with each other. For example, different
+schemes can be found in ISO/IEC 14888-3:2016 (`EC-SDSA`, `EC-SDSA-opt`, and
+`EC-FSDSA`), BSI TR-03111, Versions 2.0 (`EC-Schnorr-v2.0`) and 2.10
+(`EC-Schnorr-v2.10`), and published by Clause Schnorr himself in Efficient
+Signature Generation by Smart Cards in the Journal of Cryptology, Vol.4,
+pp.161-174, 1991 (`Sc91`). There are other variants not covered here as well.
+
+Further, each of these schemes have various disadvantages that are discussed
+more in the following sections which make them unsuitable for use with Decred.
+Consequently, Decred makes use of a custom scheme named `EC-Schnorr-DCRv0`.
+
+That said, the various schemes are all fairly simple variations which involve
+using an agreed upon elliptic curve with generator `G`, and hash function `hash`
+where the signer, with public key `Q` and signing message `m`, picks a _unique_
+random point `R` and two integers `s` and `e` such that the following equations
+hold:
+
+* `e = hash(R || m)`
+* `s*G = R + e*Q`
+
+The signature itself then consists of two components with two major variants
+that depend on which of `e` or `R` the signer wishes to reveal and further minor
+variants which depend on the data that is hashed as well as the sign used in the
+calculation of `s`, which in a sense, can be thought of as the sign applied to
+the public key.
+
+For reference, the following is a high-level breakdown of some of the key
+differences between the aforementioned schemes, where `d` is the signers
+private key and `k` is the secret nonce used to generate the random point
+`R = k*G` (note that `R.x` and `R.y` indicate the x and y coordinates of the
+point `R`, respectively):
+
+| Scheme | Pubkey | Challenge (e) | 1st part | 2nd part (mod N) |
+|------------------|--------|---------------------|-----------|------------------|
+| Sc91 | -d*G | hash(R ∥ m) | e | k + d*e |
+| EC-SDSA | -d*G | hash(R.x ∥ R.y ∥ m) | e | k + d*e |
+| EC-SDSA-opt | -d*G | hash(R.x ∥ m) | e | k + d*e |
+| EC-FSDSA | d*G | hash(R.x ∥ R.y ∥ m) | R.x ∥ R.y | k - d*e |
+| EC-Schnorr-v2.0 | d*G | hash(m ∥ R.x) | e | k - d*e |
+| EC-Schnorr-v2.10 | -d*G | hash(R.x ∥ R.y ∥ m) | e | k + d*e |
+| EC-Schnorr-DCRv0 | d*G | hash(R.x ∥ m) | R.x | k - d*e |
+
+Notice the main differences are:
+
+* The signature pair is either `(e, s)` or `(R, s)`
+* The `y` coordinate of `R` is either explicit or implicit leaving it up to the
+ verifier to calculate from the `x` coordinate
+* The exact serialization of the data used to create the challenge `e` varies, but
+ they all commit to the random point `R` and the message `m`
+* The calculation of `s` either uses addition or subtraction meaning the
+ verifier must use the opposite operation which essentially changes the sign of
+ the public key in the addition case
+
+### Revealing `e` vs `R`
+
+The first main difference is whether or not `e` or `R` is revealed, meaning the
+signature is either the pair `(e, s)` or the pair `(R, s)`, respectively.
+
+In the case `e` is revealed, the verifier must calculate `R = s*G - e*Q` and
+thus implies the pair must satisfy `e = hash(s*G - e*Q || m)`. On the other
+hand, when `R` is revealed, the verifier must calculate
+`s*G = R + hash(R || m)*Q`.
+
+This is an important distinction because, while the first approach of revealing
+`e` does have the theoretical potential for smaller signatures, since it is the
+result of a hash function as opposed to encoding `R`, it also has a couple of
+important disadvantages that the second approach does not:
+
+* It makes the implementation of secure joint multi-party and threshold
+ signatures more difficult
+* It does not support fast batch verification due to the fact the necessary
+ elliptic curve operations are performed inside the hash function which
+ prevents the ability to take advantage of their homomorphic properties
+
+Further, when the size of the field elements for the elliptic curve is the same
+size as the hash function, as is the case in Decred, techniques which are
+discussed in the next section can be used to make `(R, s)` signatures the same
+size as `(e, s)` signatures.
+
+Therefore, the second approach of `(R, s)` signatures is chosen.
+
+### Explicit Versus Implicit `y` Coordinate for `R`
+
+The second main difference is whether or not the full `R` point is explicitly or
+implicitly specified. Explicitly specifying it refers to committing directly to
+and/or revealing both the `x` and `y` coordinates of the point while the
+implicit option only makes use of the `x` coordinate.
+
+Using the implicit option provides for smaller signatures of the `(R, s)` form
+since it means the `R` component requires less bytes to encode.
+
+However, even though all that is required for single signature validations in
+some implicit schemes is the `x` coordinate of `R`, in order to support batch
+validation the verifiers must know the full point, which includes the `y`
+coordinate.
+
+Since there are two possible `y` coordinates corresponding to the `x`
+coordinate, in cases where the full point `R` must be known to verifiers, some
+additional semantics are required to correctly identify which one is the correct
+one.
+
+While there are various methods, the choice made for `EC-Schnorr-DCRv0` is to
+enforce the `y` coordinate to be even which can be efficiently accomplished at
+signing time by negating the nonce in the case it is odd and it does not involve
+adding an additional byte in the signature to specify the oddness. This is
+possible because all valid points on the secp256k1 curve always have
+corresponding `y` coordinates where one is even and the other is odd due to them
+being the negation of each other modulo the underlying field prime, which an odd
+number.
+
+### Challenge (`e`) Calculation
+
+The third main difference is the specific format of the data that is used to
+create the challenge via the hash function. Some variants include both the `x`
+and `y` coordinates of the point `R` while others only include the `x`
+coordinate. See the previous section about explicit versus implicit `y`
+coordinates since this choice also ties into that. Also, one of the variants
+reverses the order of the concatenation of the message `m` and the point `R`.
+
+Combining these details with the following additional information specific to
+Decred results in the choice of `e = BLAKE-256(R.x || m)` for the challenge with
+additional restrictions on `R` to ensure verifiers can reconstruct the full
+point:
+
+* The order of the committed information for the challenge is not important and
+ the more common formulation consists of `R` followed by `m`
+* Compact signatures are more desirable since they end up in the public ledger
+* The BLAKE-256 hash function with 14 rounds is already in widespread use and
+ satisfies all requirements needed for the hash function
+
+### Sign For `s` Calculation
+
+The final main difference is whether or not `s` is calculated as `s = k - d*e`
+or `s = k + d*e`. The verification equation naturally changes depending on
+which variant is used: `R = s*G + e*Q` for the first and `R = s*G - e*Q` for
+the second. For this reason, it is perhaps easier to think of it terms of the
+the signature scheme choosing whether or not to flip the sign on the public key
+`Q` depending on which `s` calculation is used.
+
+The only option among the covered standardization attempts that returns
+signatures pairs in the `(R, s)` form uses the `s = k - d*e` variant, so that
+variant is chosen for `EC-Schnorr-DCRv0` as well.
+
+## Future Design Considerations
+
+It is worth noting that there are some additional optimizations and
+modifications that have been identified since the introduction of
+`EC-Schnorr-DCRv0` that can be made to further harden security for multi-party
+and threshold signature use cases as well provide the opportunity for faster
+signature verification with a sufficiently optimized implementation.
+
+However, the v0 scheme is used in the existing consensus rules and any changes
+to the signature scheme would invalidate existing uses. Therefore changes in
+this regard will need to come in the form of a v1 signature scheme and be
+accompanied by the necessary consensus updates.
+
+## EC-Schnorr-DCRv0 Specification
+
+### EC-Schnorr-DCRv0 Signing Algorithm
+
+The algorithm for producing an EC-Schnorr-DCRv0 signature is as follows:
+
+G = curve generator
+n = curve order
+d = private key
+m = message
+r, s = signature
+
+1. Fail if m is not 32 bytes
+2. Fail if d = 0 or d >= n
+3. Use RFC6979 to generate a deterministic nonce k in [1, n-1] parameterized by
+ the private key, message being signed, extra data that identifies the scheme
+ (`0x0b75f97b60e8a5762876c004829ee9b926fa6f0d2eeaec3a4fd1446a768331cb`), and
+ an iteration count
+4. R = kG
+5. Negate nonce k if R.y is odd (R.y is the y coordinate of the point R)
+6. r = R.x (R.x is the x coordinate of the point R)
+7. e = BLAKE-256(r || m) (Ensure r is padded to 32 bytes)
+8. Repeat from step 3 (with iteration + 1) if e >= n
+9. s = k - e*d mod n
+10. Return (r, s)
+
+### EC-Schnorr-DCRv0 Verification Algorithm
+
+The algorithm for verifying an EC-Schnorr-DCRv0 signature is as follows:
+
+G = curve generator
+n = curve order
+p = field size
+Q = public key
+m = message
+r, s = signature
+
+1. Fail if m is not 32 bytes
+2. Fail if Q is not a point on the curve
+3. Fail if r >= p
+4. Fail if s >= n
+5. e = BLAKE-256(r || m) (Ensure r is padded to 32 bytes)
+6. Fail if e >= n
+7. R = s*G + e*Q
+8. Fail if R is the point at infinity
+9. Fail if R.y is odd
+10. Verified if R.x == r
+
+### EC-Schnorr-DCRv0 Signature Serialization Format
+
+The serialization format consists of the two components of the signature, `R.x`
+(the `x` coordinate of the point `R`) and `s`, each serialized as a padded
+big-endian uint256 (32-bytes with the most significant byte first) and
+concatenated together to form a 64-byte signature.
+
+See the file `signature_test.go` for test vectors.
+
+## Schnorr use in Decred
+
+At the time of this writing, Schnorr signatures are not yet in widespread use on
+the Decred network, largely due to the current lack of support in wallets and
+infrastructure for secure multi-party and threshold signatures.
+
+However, the consensus rules and scripting engine supports the necessary
+primitives and given many of the beneficial properties of Schnorr signatures, a
+good goal is to work towards providing the additional infrastructure to increase
+their usage.
+
+## Acknowledgements
+
+The EC-Schnorr-DCRv0 scheme is partly based on work that was ongoing in the
+Bitcoin community at the time it was implemented along with the following
+standardization attempts:
+
+* `EC-SDSA`, `EC-SDSA-opt`, and `EC-FSDSA` specified in ISO/IEC 14888-3:2016
+* `EC-Schnorr-v2.0` and `EC-Schnorr-v2.10` specified in BSI TR-03111, Versions 2.0
+ and v2.10, respectively
+* `Sc91` specified in Efficient Signature Generation by Smart Cards in the
+ Journal of Cryptology, Vol.4, pp.161-174, 1991
+
+## Installation and Updating
+
+This package is part of the `github.com/decred/dcrd/dcrec/secp256k1/v4` module.
+Use the standard go tooling for working with modules to incorporate it.
+
+## Examples
+
+* [Sign Message](https://pkg.go.dev/github.com/decred/dcrd/dcrec/secp256k1/v4/schnorr#example-package-SignMessage)
+ Demonstrates signing a message with the EC-Schnorr-DCRv0 scheme using a
+ secp256k1 private key that is first parsed from raw bytes and serializing the
+ generated signature.
+
+* [Verify Signature](https://pkg.go.dev/github.com/decred/dcrd/dcrec/secp256k1/v4/schnorr#example-Signature.Verify)
+ Demonstrates verifying an EC-Schnorr-DCRv0 signature against a public key that
+ is first parsed from raw bytes. The signature is also parsed from raw bytes.
+
+## License
+
+Package schnorr is licensed under the [copyfree](http://copyfree.org) ISC
+License.
diff --git a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/schnorr/doc.go b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/schnorr/doc.go
new file mode 100644
index 0000000..a3bd724
--- /dev/null
+++ b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/schnorr/doc.go
@@ -0,0 +1,102 @@
+// Copyright (c) 2020-2022 The Decred developers
+// Use of this source code is governed by an ISC
+// license that can be found in the LICENSE file.
+
+/*
+Package schnorr provides custom Schnorr signing and verification via secp256k1.
+
+This package provides data structures and functions necessary to produce and
+verify deterministic canonical Schnorr signatures using a custom scheme named
+EC-Schnorr-DCRv0 that is described herein. The signatures and implementation
+are optimized specifically for the secp256k1 curve. See
+https://www.secg.org/sec2-v2.pdf for details on the secp256k1 standard.
+
+It also provides functions to parse and serialize the Schnorr signatures
+according to the specification described herein.
+
+A comprehensive suite of tests is provided to ensure proper functionality.
+
+# Overview
+
+A Schnorr signature is a digital signature scheme that is known for its
+simplicity, provable security and efficient generation of short signatures.
+
+It provides many advantages over ECDSA signatures that make them ideal for use
+with the only real downside being that they are not well standardized at the
+time of this writing.
+
+Some of the advantages over ECDSA include:
+
+ - They are linear which makes them easier to aggregate and use in protocols that
+ build on them such as multi-party signatures, threshold signatures, adaptor
+ signatures, and blind signatures
+ - They are provably secure with weaker assumptions than the best known security
+ proofs for ECDSA
+ - Specifically Schnorr signatures are provably secure under SUF-CMA (Strong
+ Existential Unforgeability under Chosen Message Attack) in the ROM (Random
+ Oracle Model) which guarantees that as long as the hash function behaves
+ ideally, the only way to break Schnorr signatures is by solving the ECDLP
+ (Elliptic Curve Discrete Logarithm Problem).
+ - Their relatively straightforward and efficient aggregation properties make
+ them excellent for scalability and allow them to provide some nice privacy
+ characteristics
+ - They support faster batch verification unlike the standardized version of
+ ECDSA signatures
+
+# Custom Schnorr-based Signature Scheme
+
+As mentioned in the overview, the primary downside of Schnorr signatures for
+elliptic curves is that they are not standardized as well as ECDSA signatures
+which means there are a number of variations that are not compatible with each
+other.
+
+In addition, many of the standardization attempts have various disadvantages
+that make them unsuitable for use in Decred. Some of these details and some
+insight into the design decisions made are discussed further in the README.md
+file.
+
+Consequently, this package implements a custom Schnorr-based signature scheme
+named EC-Schnorr-DCRv0 suitable for use in Decred.
+
+The following provides a high-level overview of the key design features of the
+scheme:
+
+ - Uses signatures of the form (R, s)
+ - Produces 64-byte signatures by only encoding the x coordinate of R
+ - Enforces even y coordinates for R to support efficient verification by
+ disambiguating the two possible y coordinates
+ - Canonically encodes by both components of the signature with 32-bytes each
+ - Uses BLAKE-256 with 14 rounds for the hash function to calculate challenge e
+ - Uses RFC6979 to obviate the need for an entropy source at signing time
+ - Produces deterministic signatures for a given message and private key pair
+
+# EC-Schnorr-DCRv0 Specification
+
+See the README.md file for the specific details of the signing and verification
+algorithm as well as the signature serialization format.
+
+# Future Design Considerations
+
+It is worth noting that there are some additional optimizations and
+modifications that have been identified since the introduction of
+EC-Schnorr-DCRv0 that can be made to further harden security for multi-party and
+threshold signature use cases as well provide the opportunity for faster
+signature verification with a sufficiently optimized implementation.
+
+However, the v0 scheme is used in the existing consensus rules and any changes
+to the signature scheme would invalidate existing uses. Therefore changes in
+this regard will need to come in the form of a v1 signature scheme and be
+accompanied by the necessary consensus updates.
+
+# Schnorr use in Decred
+
+At the time of this writing, Schnorr signatures are not yet in widespread use on
+the Decred network, largely due to the current lack of support in wallets and
+infrastructure for secure multi-party and threshold signatures.
+
+However, the consensus rules and scripting engine supports the necessary
+primitives and given many of the beneficial properties of Schnorr signatures, a
+good goal is to work towards providing the additional infrastructure to increase
+their usage.
+*/
+package schnorr
diff --git a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/schnorr/error.go b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/schnorr/error.go
new file mode 100644
index 0000000..2b41c07
--- /dev/null
+++ b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/schnorr/error.go
@@ -0,0 +1,85 @@
+// Copyright (c) 2014 Conformal Systems LLC.
+// Copyright (c) 2015-2020 The Decred developers
+// Use of this source code is governed by an ISC
+// license that can be found in the LICENSE file.
+
+package schnorr
+
+// ErrorKind identifies a kind of error. It has full support for errors.Is
+// and errors.As, so the caller can directly check against an error kind
+// when determining the reason for an error.
+type ErrorKind string
+
+// These constants are used to identify a specific RuleError.
+const (
+ // ErrInvalidHashLen indicates that the input hash to sign or verify is not
+ // the required length.
+ ErrInvalidHashLen = ErrorKind("ErrInvalidHashLen")
+
+ // ErrPrivateKeyIsZero indicates an attempt was made to sign a message with
+ // a private key that is equal to zero.
+ ErrPrivateKeyIsZero = ErrorKind("ErrPrivateKeyIsZero")
+
+ // ErrSchnorrHashValue indicates that the hash of (R || m) was too large and
+ // so a new nonce should be used.
+ ErrSchnorrHashValue = ErrorKind("ErrSchnorrHashValue")
+
+ // ErrPubKeyNotOnCurve indicates that a point was not on the given elliptic
+ // curve.
+ ErrPubKeyNotOnCurve = ErrorKind("ErrPubKeyNotOnCurve")
+
+ // ErrSigRYIsOdd indicates that the calculated Y value of R was odd.
+ ErrSigRYIsOdd = ErrorKind("ErrSigRYIsOdd")
+
+ // ErrSigRNotOnCurve indicates that the calculated or given point R for some
+ // signature was not on the curve.
+ ErrSigRNotOnCurve = ErrorKind("ErrSigRNotOnCurve")
+
+ // ErrUnequalRValues indicates that the calculated point R for some
+ // signature was not the same as the given R value for the signature.
+ ErrUnequalRValues = ErrorKind("ErrUnequalRValues")
+
+ // ErrSigTooShort is returned when a signature that should be a Schnorr
+ // signature is too short.
+ ErrSigTooShort = ErrorKind("ErrSigTooShort")
+
+ // ErrSigTooLong is returned when a signature that should be a Schnorr
+ // signature is too long.
+ ErrSigTooLong = ErrorKind("ErrSigTooLong")
+
+ // ErrSigRTooBig is returned when a signature has r with a value that is
+ // greater than or equal to the prime of the field underlying the group.
+ ErrSigRTooBig = ErrorKind("ErrSigRTooBig")
+
+ // ErrSigSTooBig is returned when a signature has s with a value that is
+ // greater than or equal to the group order.
+ ErrSigSTooBig = ErrorKind("ErrSigSTooBig")
+)
+
+// Error satisfies the error interface and prints human-readable errors.
+func (e ErrorKind) Error() string {
+ return string(e)
+}
+
+// Error identifies an error related to a schnorr signature. It has full
+// support for errors.Is and errors.As, so the caller can ascertain the
+// specific reason for the error by checking the underlying error.
+type Error struct {
+ Err error
+ Description string
+}
+
+// Error satisfies the error interface and prints human-readable errors.
+func (e Error) Error() string {
+ return e.Description
+}
+
+// Unwrap returns the underlying wrapped error.
+func (e Error) Unwrap() error {
+ return e.Err
+}
+
+// signatureError creates an Error given a set of arguments.
+func signatureError(kind ErrorKind, desc string) Error {
+ return Error{Err: kind, Description: desc}
+}
diff --git a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/schnorr/pubkey.go b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/schnorr/pubkey.go
new file mode 100644
index 0000000..1c9174e
--- /dev/null
+++ b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/schnorr/pubkey.go
@@ -0,0 +1,45 @@
+// Copyright (c) 2013-2014 The btcsuite developers
+// Copyright (c) 2015-2020 The Decred developers
+// Use of this source code is governed by an ISC
+// license that can be found in the LICENSE file.
+
+package schnorr
+
+import (
+ "fmt"
+
+ "github.com/decred/dcrd/dcrec/secp256k1/v4"
+)
+
+// These constants define the lengths of serialized public keys.
+const (
+ PubKeyBytesLen = 33
+)
+
+const (
+ // pubkeyCompressed is the header byte for a compressed secp256k1 pubkey.
+ pubkeyCompressed byte = 0x2 // y_bit + x coord
+)
+
+// ParsePubKey parses a public key for a koblitz curve from a bytestring into a
+// ecdsa.Publickey, verifying that it is valid. It supports compressed signature
+// formats only.
+func ParsePubKey(pubKeyStr []byte) (key *secp256k1.PublicKey, err error) {
+ if pubKeyStr == nil {
+ err = fmt.Errorf("nil pubkey byte string")
+ return
+ }
+ if len(pubKeyStr) != PubKeyBytesLen {
+ err = fmt.Errorf("bad pubkey byte string size (want %v, have %v)",
+ PubKeyBytesLen, len(pubKeyStr))
+ return
+ }
+ format := pubKeyStr[0]
+ format &= ^byte(0x1)
+ if format != pubkeyCompressed {
+ err = fmt.Errorf("wrong pubkey type (not compressed)")
+ return
+ }
+
+ return secp256k1.ParsePubKey(pubKeyStr)
+}
diff --git a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/schnorr/signature.go b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/schnorr/signature.go
new file mode 100644
index 0000000..53d5525
--- /dev/null
+++ b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/schnorr/signature.go
@@ -0,0 +1,394 @@
+// Copyright (c) 2013-2014 The btcsuite developers
+// Copyright (c) 2015-2022 The Decred developers
+// Use of this source code is governed by an ISC
+// license that can be found in the LICENSE file.
+
+package schnorr
+
+import (
+ "fmt"
+
+ "github.com/decred/dcrd/crypto/blake256"
+ "github.com/decred/dcrd/dcrec/secp256k1/v4"
+)
+
+const (
+ // SignatureSize is the size of an encoded Schnorr signature.
+ SignatureSize = 64
+
+ // scalarSize is the size of an encoded big endian scalar.
+ scalarSize = 32
+)
+
+var (
+ // rfc6979ExtraDataV0 is the extra data to feed to RFC6979 when generating
+ // the deterministic nonce for the EC-Schnorr-DCRv0 scheme. This ensures
+ // the same nonce is not generated for the same message and key as for other
+ // signing algorithms such as ECDSA.
+ //
+ // It is equal to BLAKE-256([]byte("EC-Schnorr-DCRv0")).
+ rfc6979ExtraDataV0 = [32]byte{
+ 0x0b, 0x75, 0xf9, 0x7b, 0x60, 0xe8, 0xa5, 0x76,
+ 0x28, 0x76, 0xc0, 0x04, 0x82, 0x9e, 0xe9, 0xb9,
+ 0x26, 0xfa, 0x6f, 0x0d, 0x2e, 0xea, 0xec, 0x3a,
+ 0x4f, 0xd1, 0x44, 0x6a, 0x76, 0x83, 0x31, 0xcb,
+ }
+)
+
+// Signature is a type representing a Schnorr signature.
+type Signature struct {
+ r secp256k1.FieldVal
+ s secp256k1.ModNScalar
+}
+
+// NewSignature instantiates a new signature given some r and s values.
+func NewSignature(r *secp256k1.FieldVal, s *secp256k1.ModNScalar) *Signature {
+ var sig Signature
+ sig.r.Set(r).Normalize()
+ sig.s.Set(s)
+ return &sig
+}
+
+// Serialize returns the Schnorr signature in the more strict format.
+//
+// The signatures are encoded as:
+//
+// sig[0:32] x coordinate of the point R, encoded as a big-endian uint256
+// sig[32:64] s, encoded also as big-endian uint256
+func (sig Signature) Serialize() []byte {
+ // Total length of returned signature is the length of r and s.
+ var b [SignatureSize]byte
+ sig.r.PutBytesUnchecked(b[0:32])
+ sig.s.PutBytesUnchecked(b[32:64])
+ return b[:]
+}
+
+// ParseSignature parses a signature according to the EC-Schnorr-DCRv0
+// specification and enforces the following additional restrictions specific to
+// secp256k1:
+//
+// - The r component must be in the valid range for secp256k1 field elements
+// - The s component must be in the valid range for secp256k1 scalars
+func ParseSignature(sig []byte) (*Signature, error) {
+ // The signature must be the correct length.
+ sigLen := len(sig)
+ if sigLen < SignatureSize {
+ str := fmt.Sprintf("malformed signature: too short: %d < %d", sigLen,
+ SignatureSize)
+ return nil, signatureError(ErrSigTooShort, str)
+ }
+ if sigLen > SignatureSize {
+ str := fmt.Sprintf("malformed signature: too long: %d > %d", sigLen,
+ SignatureSize)
+ return nil, signatureError(ErrSigTooLong, str)
+ }
+
+ // The signature is validly encoded at this point, however, enforce
+ // additional restrictions to ensure r is in the range [0, p-1], and s is in
+ // the range [0, n-1] since valid Schnorr signatures are required to be in
+ // that range per spec.
+ var r secp256k1.FieldVal
+ if overflow := r.SetByteSlice(sig[0:32]); overflow {
+ str := "invalid signature: r >= field prime"
+ return nil, signatureError(ErrSigRTooBig, str)
+ }
+ var s secp256k1.ModNScalar
+ if overflow := s.SetByteSlice(sig[32:64]); overflow {
+ str := "invalid signature: s >= group order"
+ return nil, signatureError(ErrSigSTooBig, str)
+ }
+
+ // Return the signature.
+ return NewSignature(&r, &s), nil
+}
+
+// IsEqual compares this Signature instance to the one passed, returning true
+// if both Signatures are equivalent. A signature is equivalent to another, if
+// they both have the same scalar value for R and S.
+func (sig Signature) IsEqual(otherSig *Signature) bool {
+ return sig.r.Equals(&otherSig.r) && sig.s.Equals(&otherSig.s)
+}
+
+// schnorrVerify attempt to verify the signature for the provided hash and
+// secp256k1 public key and either returns nil if successful or a specific error
+// indicating why it failed if not successful.
+//
+// This differs from the exported Verify method in that it returns a specific
+// error to support better testing while the exported method simply returns a
+// bool indicating success or failure.
+func schnorrVerify(sig *Signature, hash []byte, pubKey *secp256k1.PublicKey) error {
+ // The algorithm for producing a EC-Schnorr-DCRv0 signature is described in
+ // README.md and is reproduced here for reference:
+ //
+ //
+ // 1. Fail if m is not 32 bytes
+ // 2. Fail if Q is not a point on the curve
+ // 3. Fail if r >= p
+ // 4. Fail if s >= n
+ // 5. e = BLAKE-256(r || m) (Ensure r is padded to 32 bytes)
+ // 6. Fail if e >= n
+ // 7. R = s*G + e*Q
+ // 8. Fail if R is the point at infinity
+ // 9. Fail if R.y is odd
+ // 10. Verified if R.x == r
+
+ // Step 1.
+ //
+ // Fail if m is not 32 bytes
+ if len(hash) != scalarSize {
+ str := fmt.Sprintf("wrong size for message (got %v, want %v)",
+ len(hash), scalarSize)
+ return signatureError(ErrInvalidHashLen, str)
+ }
+
+ // Step 2.
+ //
+ // Fail if Q is not a point on the curve
+ if !pubKey.IsOnCurve() {
+ str := "pubkey point is not on curve"
+ return signatureError(ErrPubKeyNotOnCurve, str)
+ }
+
+ // Step 3.
+ //
+ // Fail if r >= p
+ //
+ // Note this is already handled by the fact r is a field element.
+
+ // Step 4.
+ //
+ // Fail if s >= n
+ //
+ // Note this is already handled by the fact s is a mod n scalar.
+
+ // Step 5.
+ //
+ // e = BLAKE-256(r || m) (Ensure r is padded to 32 bytes)
+ var commitmentInput [scalarSize * 2]byte
+ sig.r.PutBytesUnchecked(commitmentInput[0:scalarSize])
+ copy(commitmentInput[scalarSize:], hash[:])
+ commitment := blake256.Sum256(commitmentInput[:])
+
+ // Step 6.
+ //
+ // Fail if e >= n
+ var e secp256k1.ModNScalar
+ if overflow := e.SetBytes(&commitment); overflow != 0 {
+ str := "hash of (R || m) too big"
+ return signatureError(ErrSchnorrHashValue, str)
+ }
+
+ // Step 7.
+ //
+ // R = s*G + e*Q
+ var Q, R, sG, eQ secp256k1.JacobianPoint
+ pubKey.AsJacobian(&Q)
+ secp256k1.ScalarBaseMultNonConst(&sig.s, &sG)
+ secp256k1.ScalarMultNonConst(&e, &Q, &eQ)
+ secp256k1.AddNonConst(&sG, &eQ, &R)
+
+ // Step 8.
+ //
+ // Fail if R is the point at infinity
+ if (R.X.IsZero() && R.Y.IsZero()) || R.Z.IsZero() {
+ str := "calculated R point is the point at infinity"
+ return signatureError(ErrSigRNotOnCurve, str)
+ }
+
+ // Step 9.
+ //
+ // Fail if R.y is odd
+ //
+ // Note that R must be in affine coordinates for this check.
+ R.ToAffine()
+ if R.Y.IsOdd() {
+ str := "calculated R y-value is odd"
+ return signatureError(ErrSigRYIsOdd, str)
+ }
+
+ // Step 10.
+ //
+ // Verified if R.x == r
+ //
+ // Note that R must be in affine coordinates for this check.
+ if !sig.r.Equals(&R.X) {
+ str := "calculated R point was not given R"
+ return signatureError(ErrUnequalRValues, str)
+ }
+
+ return nil
+}
+
+// Verify returns whether or not the signature is valid for the provided hash
+// and secp256k1 public key.
+func (sig *Signature) Verify(hash []byte, pubKey *secp256k1.PublicKey) bool {
+ return schnorrVerify(sig, hash, pubKey) == nil
+}
+
+// zeroArray zeroes the memory of a scalar array.
+func zeroArray(a *[scalarSize]byte) {
+ for i := 0; i < scalarSize; i++ {
+ a[i] = 0x00
+ }
+}
+
+// schnorrSign generates an EC-Schnorr-DCRv0 signature over the secp256k1 curve
+// for the provided hash (which should be the result of hashing a larger
+// message) using the given nonce and private key. The produced signature is
+// deterministic (same message, nonce, and key yield the same signature) and
+// canonical.
+//
+// WARNING: The hash MUST be 32 bytes and both the nonce and private keys must
+// NOT be 0. Since this is an internal use function, these preconditions MUST
+// be satisified by the caller.
+func schnorrSign(privKey, nonce *secp256k1.ModNScalar, hash []byte) (*Signature, error) {
+ // The algorithm for producing a EC-Schnorr-DCRv0 signature is described in
+ // README.md and is reproduced here for reference:
+ //
+ // G = curve generator
+ // n = curve order
+ // d = private key
+ // m = message
+ // r, s = signature
+ //
+ // 1. Fail if m is not 32 bytes
+ // 2. Fail if d = 0 or d >= n
+ // 3. Use RFC6979 to generate a deterministic nonce k in [1, n-1]
+ // parameterized by the private key, message being signed, extra data
+ // that identifies the scheme, and an iteration count
+ // 4. R = kG
+ // 5. Negate nonce k if R.y is odd (R.y is the y coordinate of the point R)
+ // 6. r = R.x (R.x is the x coordinate of the point R)
+ // 7. e = BLAKE-256(r || m) (Ensure r is padded to 32 bytes)
+ // 8. Repeat from step 3 (with iteration + 1) if e >= n
+ // 9. s = k - e*d mod n
+ // 10. Return (r, s)
+
+ // NOTE: Steps 1-3 are performed by the caller.
+ //
+ // Step 4.
+ //
+ // R = kG
+ var R secp256k1.JacobianPoint
+ k := *nonce
+ secp256k1.ScalarBaseMultNonConst(&k, &R)
+
+ // Step 5.
+ //
+ // Negate nonce k if R.y is odd (R.y is the y coordinate of the point R)
+ //
+ // Note that R must be in affine coordinates for this check.
+ R.ToAffine()
+ if R.Y.IsOdd() {
+ k.Negate()
+ }
+
+ // Step 6.
+ //
+ // r = R.x (R.x is the x coordinate of the point R)
+ r := &R.X
+
+ // Step 7.
+ //
+ // e = BLAKE-256(r || m) (Ensure r is padded to 32 bytes)
+ var commitmentInput [scalarSize * 2]byte
+ r.PutBytesUnchecked(commitmentInput[0:scalarSize])
+ copy(commitmentInput[scalarSize:], hash[:])
+ commitment := blake256.Sum256(commitmentInput[:])
+
+ // Step 8.
+ //
+ // Repeat from step 1 (with iteration + 1) if e >= N
+ var e secp256k1.ModNScalar
+ if overflow := e.SetBytes(&commitment); overflow != 0 {
+ k.Zero()
+ str := "hash of (R || m) too big"
+ return nil, signatureError(ErrSchnorrHashValue, str)
+ }
+
+ // Step 9.
+ //
+ // s = k - e*d mod n
+ s := new(secp256k1.ModNScalar).Mul2(&e, privKey).Negate().Add(&k)
+ k.Zero()
+
+ // Step 10.
+ //
+ // Return (r, s)
+ return NewSignature(r, s), nil
+}
+
+// Sign generates an EC-Schnorr-DCRv0 signature over the secp256k1 curve for the
+// provided hash (which should be the result of hashing a larger message) using
+// the given private key. The produced signature is deterministic (same message
+// and same key yield the same signature) and canonical.
+//
+// Note that the current signing implementation has a few remaining variable
+// time aspects which make use of the private key and the generated nonce, which
+// can expose the signer to constant time attacks. As a result, this function
+// should not be used in situations where there is the possibility of someone
+// having EM field/cache/etc access.
+func Sign(privKey *secp256k1.PrivateKey, hash []byte) (*Signature, error) {
+ // The algorithm for producing a EC-Schnorr-DCRv0 signature is described in
+ // README.md and is reproduced here for reference:
+ //
+ // G = curve generator
+ // n = curve order
+ // d = private key
+ // m = message
+ // r, s = signature
+ //
+ // 1. Fail if m is not 32 bytes
+ // 2. Fail if d = 0 or d >= n
+ // 3. Use RFC6979 to generate a deterministic nonce k in [1, n-1]
+ // parameterized by the private key, message being signed, extra data
+ // that identifies the scheme, and an iteration count
+ // 4. R = kG
+ // 5. Negate nonce k if R.y is odd (R.y is the y coordinate of the point R)
+ // 6. r = R.x (R.x is the x coordinate of the point R)
+ // 7. e = BLAKE-256(r || m) (Ensure r is padded to 32 bytes)
+ // 8. Repeat from step 3 (with iteration + 1) if e >= n
+ // 9. s = k - e*d mod n
+ // 10. Return (r, s)
+
+ // Step 1.
+ //
+ // Fail if m is not 32 bytes
+ if len(hash) != scalarSize {
+ str := fmt.Sprintf("wrong size for message hash (got %v, want %v)",
+ len(hash), scalarSize)
+ return nil, signatureError(ErrInvalidHashLen, str)
+ }
+
+ // Step 2.
+ //
+ // Fail if d = 0 or d >= n
+ privKeyScalar := &privKey.Key
+ if privKeyScalar.IsZero() {
+ str := "private key is zero"
+ return nil, signatureError(ErrPrivateKeyIsZero, str)
+ }
+
+ var privKeyBytes [scalarSize]byte
+ privKeyScalar.PutBytes(&privKeyBytes)
+ defer zeroArray(&privKeyBytes)
+ for iteration := uint32(0); ; iteration++ {
+ // Step 3.
+ //
+ // Use RFC6979 to generate a deterministic nonce k in [1, n-1]
+ // parameterized by the private key, message being signed, extra data
+ // that identifies the scheme, and an iteration count
+ k := secp256k1.NonceRFC6979(privKeyBytes[:], hash, rfc6979ExtraDataV0[:],
+ nil, iteration)
+
+ // Steps 4-10.
+ sig, err := schnorrSign(privKeyScalar, k, hash)
+ k.Zero()
+ if err != nil {
+ // Try again with a new nonce.
+ continue
+ }
+
+ return sig, nil
+ }
+}
diff --git a/vendor/github.com/fasthttp/websocket/.editorconfig b/vendor/github.com/fasthttp/websocket/.editorconfig
new file mode 100644
index 0000000..2940ec9
--- /dev/null
+++ b/vendor/github.com/fasthttp/websocket/.editorconfig
@@ -0,0 +1,20 @@
+; https://editorconfig.org/
+
+root = true
+
+[*]
+insert_final_newline = true
+charset = utf-8
+trim_trailing_whitespace = true
+indent_style = space
+indent_size = 2
+
+[{Makefile,go.mod,go.sum,*.go,.gitmodules}]
+indent_style = tab
+indent_size = 4
+
+[*.md]
+indent_size = 4
+trim_trailing_whitespace = false
+
+eclint_indent_style = unset
diff --git a/vendor/github.com/fasthttp/websocket/.gitignore b/vendor/github.com/fasthttp/websocket/.gitignore
new file mode 100644
index 0000000..f23fd01
--- /dev/null
+++ b/vendor/github.com/fasthttp/websocket/.gitignore
@@ -0,0 +1,30 @@
+# Compiled Object files, Static and Dynamic libs (Shared Objects)
+*.o
+*.a
+*.so
+
+# Folders
+_obj
+_test
+
+# Architecture specific extensions/prefixes
+*.[568vq]
+[568vq].out
+
+*.cgo1.go
+*.cgo2.c
+_cgo_defun.c
+_cgo_gotypes.go
+_cgo_export.*
+
+_testmain.go
+
+*.exe
+
+.idea/
+*.iml
+.vscode/
+
+vendor/
+
+**/*.gz
diff --git a/vendor/github.com/fasthttp/websocket/.golangci.yml b/vendor/github.com/fasthttp/websocket/.golangci.yml
new file mode 100644
index 0000000..3488213
--- /dev/null
+++ b/vendor/github.com/fasthttp/websocket/.golangci.yml
@@ -0,0 +1,3 @@
+run:
+ skip-dirs:
+ - examples/*.go
diff --git a/vendor/github.com/fasthttp/websocket/LICENSE b/vendor/github.com/fasthttp/websocket/LICENSE
new file mode 100644
index 0000000..bb9d80b
--- /dev/null
+++ b/vendor/github.com/fasthttp/websocket/LICENSE
@@ -0,0 +1,27 @@
+Copyright (c) 2023 The Gorilla Authors. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+ * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/vendor/github.com/fasthttp/websocket/Makefile b/vendor/github.com/fasthttp/websocket/Makefile
new file mode 100644
index 0000000..603a63f
--- /dev/null
+++ b/vendor/github.com/fasthttp/websocket/Makefile
@@ -0,0 +1,34 @@
+GO_LINT=$(shell which golangci-lint 2> /dev/null || echo '')
+GO_LINT_URI=github.com/golangci/golangci-lint/cmd/golangci-lint@latest
+
+GO_SEC=$(shell which gosec 2> /dev/null || echo '')
+GO_SEC_URI=github.com/securego/gosec/v2/cmd/gosec@latest
+
+GO_VULNCHECK=$(shell which govulncheck 2> /dev/null || echo '')
+GO_VULNCHECK_URI=golang.org/x/vuln/cmd/govulncheck@latest
+
+.PHONY: golangci-lint
+golangci-lint:
+ $(if $(GO_LINT), ,go install $(GO_LINT_URI))
+ @echo "##### Running golangci-lint"
+ golangci-lint run -v
+
+.PHONY: gosec
+gosec:
+ $(if $(GO_SEC), ,go install $(GO_SEC_URI))
+ @echo "##### Running gosec"
+ gosec -exclude-dir examples ./...
+
+.PHONY: govulncheck
+govulncheck:
+ $(if $(GO_VULNCHECK), ,go install $(GO_VULNCHECK_URI))
+ @echo "##### Running govulncheck"
+ govulncheck ./...
+
+.PHONY: verify
+verify: golangci-lint gosec govulncheck
+
+.PHONY: test
+test:
+ @echo "##### Running tests"
+ go test -race -cover -coverprofile=coverage.coverprofile -covermode=atomic -v ./...
diff --git a/vendor/github.com/fasthttp/websocket/README.md b/vendor/github.com/fasthttp/websocket/README.md
new file mode 100644
index 0000000..89c7ab1
--- /dev/null
+++ b/vendor/github.com/fasthttp/websocket/README.md
@@ -0,0 +1,40 @@
+# Fasthttp WebSocket
+
+[![Test status](https://github.com/fasthttp/websocket/actions/workflows/test.yml/badge.svg?branch=master)](https://github.com/fasthttp/websocket/actions?workflow=test)
+[![Go Report Card](https://goreportcard.com/badge/github.com/fasthttp/websocket)](https://goreportcard.com/report/github.com/fasthttp/websocket)
+[![GoDev](https://img.shields.io/badge/go.dev-reference-007d9c?logo=go&logoColor=white)](https://pkg.go.dev/github.com/fasthttp/websocket)
+[![GitHub release](https://img.shields.io/github/release/fasthttp/websocket.svg)](https://github.com/fasthttp/websocket/releases)
+
+WebSocket is a [Go](http://golang.org/) implementation of the [WebSocket](http://www.rfc-editor.org/rfc/rfc6455.txt) for [fasthttp](https://github.com/valyala/fasthttp).
+
+![Gorilla Logo](https://github.com/gorilla/.github/assets/53367916/d92caabf-98e0-473e-bfbf-ab554ba435e5)
+
+_This project is a fork of the latest version of [gorilla/websocket](https://github.com/gorilla/websocket) that continues its development independently._
+
+### Documentation
+
+* [API Reference](https://pkg.go.dev/github.com/fasthttp/websocket?tab=doc)
+* [Chat example](_examples/chat)
+* [Command example](_examples/command)
+* [Client and server example](_examples/echo)
+* [File watch example](_examples/filewatch)
+* [Write buffer pool example](_examples/bufferpool)
+
+### Status
+
+The WebSocket package provides a complete and tested implementation of
+the [WebSocket](http://www.rfc-editor.org/rfc/rfc6455.txt) protocol. The
+package API is stable.
+
+### Installation
+
+```
+go get github.com/fasthttp/websocket
+```
+But beware that this will fetch the **latest commit of the master branch** which is never purposely broken, but usually not considered stable anyway.
+
+### Protocol Compliance
+
+The WebSocket package passes the server tests in the [Autobahn Test
+Suite](https://github.com/crossbario/autobahn-testsuite) using the application in the [_examples/autobahn
+subdirectory](_examples/autobahn).
diff --git a/vendor/github.com/fasthttp/websocket/SECURITY.md b/vendor/github.com/fasthttp/websocket/SECURITY.md
new file mode 100644
index 0000000..2beab17
--- /dev/null
+++ b/vendor/github.com/fasthttp/websocket/SECURITY.md
@@ -0,0 +1,115 @@
+### TL;DR
+
+We use a simplified version of [Golang Security Policy](https://golang.org/security).
+For example, for now we skip CVE assignment.
+
+### Reporting a Security Bug
+
+Please report to us any issues you find. This document explains how to do that and what to expect in return.
+
+All security bugs in our releases should be reported by email to oss-security@highload.solutions.
+This mail is delivered to a small security team.
+Your email will be acknowledged within 24 hours, and you'll receive a more detailed response
+to your email within 72 hours indicating the next steps in handling your report.
+For critical problems, you can encrypt your report using our PGP key (listed below).
+
+Please use a descriptive subject line for your report email.
+After the initial reply to your report, the security team will
+endeavor to keep you informed of the progress being made towards a fix and full announcement.
+These updates will be sent at least every five days.
+In reality, this is more likely to be every 24-48 hours.
+
+If you have not received a reply to your email within 48 hours or you have not heard from the security
+team for the past five days please contact us by email to developers@highload.solutions or by Telegram message
+to [our support](https://t.me/highload_support).
+Please note that developers@highload.solutions list includes all developers, who may be outside our opensource security team.
+When escalating on this list, please do not disclose the details of the issue.
+Simply state that you're trying to reach a member of the security team.
+
+### Flagging Existing Issues as Security-related
+
+If you believe that an existing issue is security-related, we ask that you send an email to oss-security@highload.solutions.
+The email should include the issue ID and a short description of why it should be handled according to this security policy.
+
+### Disclosure Process
+
+Our project uses the following disclosure process:
+
+- Once the security report is received it is assigned a primary handler. This person coordinates the fix and release process.
+- The issue is confirmed and a list of affected software is determined.
+- Code is audited to find any potential similar problems.
+- Fixes are prepared for the two most recent major releases and the head/master revision. These fixes are not yet committed to the public repository.
+- To notify users, a new issue without security details is submitted to our GitHub repository.
+- Three working days following this notification, the fixes are applied to the public repository and a new release is issued.
+- On the date that the fixes are applied, announcement is published in the issue.
+
+This process can take some time, especially when coordination is required with maintainers of other projects.
+Every effort will be made to handle the bug in as timely a manner as possible, however it's important that we follow
+the process described above to ensure that disclosures are handled consistently.
+
+### Receiving Security Updates
+The best way to receive security announcements is to subscribe ("Watch") to our repository.
+Any GitHub issues pertaining to a security issue will be prefixed with [security].
+
+### Comments on This Policy
+If you have any suggestions to improve this policy, please send an email to oss-security@highload.solutions for discussion.
+
+### PGP Key for oss-security@highload.solutions
+
+We accept PGP-encrypted email, but the majority of the security team are not regular PGP users
+so it's somewhat inconvenient. Please only use PGP for critical security reports.
+
+```
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+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
+=lnt2
+-----END PGP PUBLIC KEY BLOCK-----
+```
diff --git a/vendor/github.com/fasthttp/websocket/client.go b/vendor/github.com/fasthttp/websocket/client.go
new file mode 100644
index 0000000..c55bcb2
--- /dev/null
+++ b/vendor/github.com/fasthttp/websocket/client.go
@@ -0,0 +1,443 @@
+// Copyright 2013 The Gorilla WebSocket 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 websocket
+
+import (
+ "bytes"
+ "context"
+ "crypto/tls"
+ "errors"
+ "fmt"
+ "io"
+ "log"
+ "net"
+ "net/http"
+ "net/http/httptrace"
+ "net/url"
+ "strings"
+ "time"
+
+ "golang.org/x/net/proxy"
+)
+
+// ErrBadHandshake is returned when the server response to opening handshake is
+// invalid.
+var ErrBadHandshake = errors.New("websocket: bad handshake")
+
+var errInvalidCompression = errors.New("websocket: invalid compression negotiation")
+
+// NewClient creates a new client connection using the given net connection.
+// The URL u specifies the host and request URI. Use requestHeader to specify
+// the origin (Origin), subprotocols (Sec-WebSocket-Protocol) and cookies
+// (Cookie). Use the response.Header to get the selected subprotocol
+// (Sec-WebSocket-Protocol) and cookies (Set-Cookie).
+//
+// If the WebSocket handshake fails, ErrBadHandshake is returned along with a
+// non-nil *http.Response so that callers can handle redirects, authentication,
+// etc.
+//
+// Deprecated: Use Dialer instead.
+func NewClient(netConn net.Conn, u *url.URL, requestHeader http.Header, readBufSize, writeBufSize int) (c *Conn, response *http.Response, err error) {
+ d := Dialer{
+ ReadBufferSize: readBufSize,
+ WriteBufferSize: writeBufSize,
+ NetDial: func(net, addr string) (net.Conn, error) {
+ return netConn, nil
+ },
+ }
+ return d.Dial(u.String(), requestHeader)
+}
+
+// A Dialer contains options for connecting to WebSocket server.
+//
+// It is safe to call Dialer's methods concurrently.
+type Dialer struct {
+ // NetDial specifies the dial function for creating TCP connections. If
+ // NetDial is nil, net.Dial is used.
+ NetDial func(network, addr string) (net.Conn, error)
+
+ // NetDialContext specifies the dial function for creating TCP connections. If
+ // NetDialContext is nil, NetDial is used.
+ NetDialContext func(ctx context.Context, network, addr string) (net.Conn, error)
+
+ // NetDialTLSContext specifies the dial function for creating TLS/TCP connections. If
+ // NetDialTLSContext is nil, NetDialContext is used.
+ // If NetDialTLSContext is set, Dial assumes the TLS handshake is done there and
+ // TLSClientConfig is ignored.
+ NetDialTLSContext func(ctx context.Context, network, addr string) (net.Conn, error)
+
+ // Proxy specifies a function to return a proxy for a given
+ // Request. If the function returns a non-nil error, the
+ // request is aborted with the provided error.
+ // If Proxy is nil or returns a nil *URL, no proxy is used.
+ Proxy func(*http.Request) (*url.URL, error)
+
+ // TLSClientConfig specifies the TLS configuration to use with tls.Client.
+ // If nil, the default configuration is used.
+ // If either NetDialTLS or NetDialTLSContext are set, Dial assumes the TLS handshake
+ // is done there and TLSClientConfig is ignored.
+ TLSClientConfig *tls.Config
+
+ // HandshakeTimeout specifies the duration for the handshake to complete.
+ HandshakeTimeout time.Duration
+
+ // ReadBufferSize and WriteBufferSize specify I/O buffer sizes in bytes. If a buffer
+ // size is zero, then a useful default size is used. The I/O buffer sizes
+ // do not limit the size of the messages that can be sent or received.
+ ReadBufferSize, WriteBufferSize int
+
+ // WriteBufferPool is a pool of buffers for write operations. If the value
+ // is not set, then write buffers are allocated to the connection for the
+ // lifetime of the connection.
+ //
+ // A pool is most useful when the application has a modest volume of writes
+ // across a large number of connections.
+ //
+ // Applications should use a single pool for each unique value of
+ // WriteBufferSize.
+ WriteBufferPool BufferPool
+
+ // Subprotocols specifies the client's requested subprotocols.
+ Subprotocols []string
+
+ // EnableCompression specifies if the client should attempt to negotiate
+ // per message compression (RFC 7692). Setting this value to true does not
+ // guarantee that compression will be supported. Currently only "no context
+ // takeover" modes are supported.
+ EnableCompression bool
+
+ // Jar specifies the cookie jar.
+ // If Jar is nil, cookies are not sent in requests and ignored
+ // in responses.
+ Jar http.CookieJar
+}
+
+// Dial creates a new client connection by calling DialContext with a background context.
+func (d *Dialer) Dial(urlStr string, requestHeader http.Header) (*Conn, *http.Response, error) {
+ return d.DialContext(context.Background(), urlStr, requestHeader)
+}
+
+var errMalformedURL = errors.New("malformed ws or wss URL")
+
+func hostPortNoPort(u *url.URL) (hostPort, hostNoPort string) {
+ hostPort = u.Host
+ hostNoPort = u.Host
+ if i := strings.LastIndex(u.Host, ":"); i > strings.LastIndex(u.Host, "]") {
+ hostNoPort = hostNoPort[:i]
+ } else {
+ switch u.Scheme {
+ case "wss":
+ hostPort += ":443"
+ case "https":
+ hostPort += ":443"
+ default:
+ hostPort += ":80"
+ }
+ }
+ return hostPort, hostNoPort
+}
+
+// DefaultDialer is a dialer with all fields set to the default values.
+var DefaultDialer = &Dialer{
+ Proxy: http.ProxyFromEnvironment,
+ HandshakeTimeout: 45 * time.Second,
+}
+
+// nilDialer is dialer to use when receiver is nil.
+var nilDialer = *DefaultDialer
+
+// DialContext creates a new client connection. Use requestHeader to specify the
+// origin (Origin), subprotocols (Sec-WebSocket-Protocol) and cookies (Cookie).
+// Use the response.Header to get the selected subprotocol
+// (Sec-WebSocket-Protocol) and cookies (Set-Cookie).
+//
+// The context will be used in the request and in the Dialer.
+//
+// If the WebSocket handshake fails, ErrBadHandshake is returned along with a
+// non-nil *http.Response so that callers can handle redirects, authentication,
+// etcetera. The response body may not contain the entire response and does not
+// need to be closed by the application.
+func (d *Dialer) DialContext(ctx context.Context, urlStr string, requestHeader http.Header) (*Conn, *http.Response, error) {
+ if d == nil {
+ d = &nilDialer
+ }
+
+ challengeKey, err := generateChallengeKey()
+ if err != nil {
+ return nil, nil, err
+ }
+
+ u, err := url.Parse(urlStr)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ switch u.Scheme {
+ case "ws":
+ u.Scheme = "http"
+ case "wss":
+ u.Scheme = "https"
+ default:
+ return nil, nil, errMalformedURL
+ }
+
+ if u.User != nil {
+ // User name and password are not allowed in websocket URIs.
+ return nil, nil, errMalformedURL
+ }
+
+ req := &http.Request{
+ Method: http.MethodGet,
+ URL: u,
+ Proto: "HTTP/1.1",
+ ProtoMajor: 1,
+ ProtoMinor: 1,
+ Header: make(http.Header),
+ Host: u.Host,
+ }
+ req = req.WithContext(ctx)
+
+ // Set the cookies present in the cookie jar of the dialer
+ if d.Jar != nil {
+ for _, cookie := range d.Jar.Cookies(u) {
+ req.AddCookie(cookie)
+ }
+ }
+
+ // Set the request headers using the capitalization for names and values in
+ // RFC examples. Although the capitalization shouldn't matter, there are
+ // servers that depend on it. The Header.Set method is not used because the
+ // method canonicalizes the header names.
+ req.Header["Upgrade"] = []string{"websocket"}
+ req.Header["Connection"] = []string{"Upgrade"}
+ req.Header["Sec-WebSocket-Key"] = []string{challengeKey}
+ req.Header["Sec-WebSocket-Version"] = []string{"13"}
+ if len(d.Subprotocols) > 0 {
+ req.Header["Sec-WebSocket-Protocol"] = []string{strings.Join(d.Subprotocols, ", ")}
+ }
+ for k, vs := range requestHeader {
+ switch {
+ case k == "Host":
+ if len(vs) > 0 {
+ req.Host = vs[0]
+ }
+ case k == "Upgrade" ||
+ k == "Connection" ||
+ k == "Sec-Websocket-Key" ||
+ k == "Sec-Websocket-Version" ||
+ //#nosec G101 (CWE-798): Potential HTTP request smuggling via parameter pollution
+ k == "Sec-Websocket-Extensions" ||
+ (k == "Sec-Websocket-Protocol" && len(d.Subprotocols) > 0):
+ return nil, nil, errors.New("websocket: duplicate header not allowed: " + k)
+ case k == "Sec-Websocket-Protocol":
+ req.Header["Sec-WebSocket-Protocol"] = vs
+ default:
+ req.Header[k] = vs
+ }
+ }
+
+ if d.EnableCompression {
+ req.Header["Sec-WebSocket-Extensions"] = []string{"permessage-deflate; server_no_context_takeover; client_no_context_takeover"}
+ }
+
+ if d.HandshakeTimeout != 0 {
+ var cancel func()
+ ctx, cancel = context.WithTimeout(ctx, d.HandshakeTimeout)
+ defer cancel()
+ }
+
+ // Get network dial function.
+ var netDial func(network, add string) (net.Conn, error)
+
+ switch u.Scheme {
+ case "http":
+ if d.NetDialContext != nil {
+ netDial = func(network, addr string) (net.Conn, error) {
+ return d.NetDialContext(ctx, network, addr)
+ }
+ } else if d.NetDial != nil {
+ netDial = d.NetDial
+ }
+ case "https":
+ if d.NetDialTLSContext != nil {
+ netDial = func(network, addr string) (net.Conn, error) {
+ return d.NetDialTLSContext(ctx, network, addr)
+ }
+ } else if d.NetDialContext != nil {
+ netDial = func(network, addr string) (net.Conn, error) {
+ return d.NetDialContext(ctx, network, addr)
+ }
+ } else if d.NetDial != nil {
+ netDial = d.NetDial
+ }
+ default:
+ return nil, nil, errMalformedURL
+ }
+
+ if netDial == nil {
+ netDialer := &net.Dialer{}
+ netDial = func(network, addr string) (net.Conn, error) {
+ return netDialer.DialContext(ctx, network, addr)
+ }
+ }
+
+ // If needed, wrap the dial function to set the connection deadline.
+ if deadline, ok := ctx.Deadline(); ok {
+ forwardDial := netDial
+ netDial = func(network, addr string) (net.Conn, error) {
+ c, err := forwardDial(network, addr)
+ if err != nil {
+ return nil, err
+ }
+ err = c.SetDeadline(deadline)
+ if err != nil {
+ if err := c.Close(); err != nil {
+ log.Printf("websocket: failed to close network connection: %v", err)
+ }
+ return nil, err
+ }
+ return c, nil
+ }
+ }
+
+ // If needed, wrap the dial function to connect through a proxy.
+ if d.Proxy != nil {
+ proxyURL, err := d.Proxy(req)
+ if err != nil {
+ return nil, nil, err
+ }
+ if proxyURL != nil {
+ dialer, err := proxy.FromURL(proxyURL, netDialerFunc(netDial))
+ if err != nil {
+ return nil, nil, err
+ }
+ netDial = dialer.Dial
+ }
+ }
+
+ hostPort, hostNoPort := hostPortNoPort(u)
+ trace := httptrace.ContextClientTrace(ctx)
+ if trace != nil && trace.GetConn != nil {
+ trace.GetConn(hostPort)
+ }
+
+ netConn, err := netDial("tcp", hostPort)
+ if err != nil {
+ return nil, nil, err
+ }
+ if trace != nil && trace.GotConn != nil {
+ trace.GotConn(httptrace.GotConnInfo{
+ Conn: netConn,
+ })
+ }
+
+ defer func() {
+ if netConn != nil {
+ if err := netConn.Close(); err != nil {
+ log.Printf("websocket: failed to close network connection: %v", err)
+ }
+ }
+ }()
+
+ if u.Scheme == "https" && d.NetDialTLSContext == nil {
+ // If NetDialTLSContext is set, assume that the TLS handshake has already been done
+
+ cfg := cloneTLSConfig(d.TLSClientConfig)
+ if cfg.ServerName == "" {
+ cfg.ServerName = hostNoPort
+ }
+ tlsConn := tls.Client(netConn, cfg)
+ netConn = tlsConn
+
+ if trace != nil && trace.TLSHandshakeStart != nil {
+ trace.TLSHandshakeStart()
+ }
+ err := doHandshake(ctx, tlsConn, cfg)
+ if trace != nil && trace.TLSHandshakeDone != nil {
+ trace.TLSHandshakeDone(tlsConn.ConnectionState(), err)
+ }
+
+ if err != nil {
+ return nil, nil, err
+ }
+ }
+
+ conn := newConn(netConn, false, d.ReadBufferSize, d.WriteBufferSize, d.WriteBufferPool, nil, nil)
+
+ if err := req.Write(netConn); err != nil {
+ return nil, nil, err
+ }
+
+ if trace != nil && trace.GotFirstResponseByte != nil {
+ if peek, err := conn.br.Peek(1); err == nil && len(peek) == 1 {
+ trace.GotFirstResponseByte()
+ }
+ }
+
+ resp, err := http.ReadResponse(conn.br, req)
+ if err != nil {
+ if d.TLSClientConfig != nil {
+ for _, proto := range d.TLSClientConfig.NextProtos {
+ if proto != "http/1.1" {
+ return nil, nil, fmt.Errorf(
+ "websocket: protocol %q was given but is not supported;"+
+ "sharing tls.Config with net/http Transport can cause this error: %w",
+ proto, err,
+ )
+ }
+ }
+ }
+ return nil, nil, err
+ }
+
+ if d.Jar != nil {
+ if rc := resp.Cookies(); len(rc) > 0 {
+ d.Jar.SetCookies(u, rc)
+ }
+ }
+
+ if resp.StatusCode != http.StatusSwitchingProtocols ||
+ !tokenListContainsValue(resp.Header, "Upgrade", "websocket") ||
+ !tokenListContainsValue(resp.Header, "Connection", "upgrade") ||
+ resp.Header.Get("Sec-Websocket-Accept") != computeAcceptKey(challengeKey) {
+ // Before closing the network connection on return from this
+ // function, slurp up some of the response to aid application
+ // debugging.
+ buf := make([]byte, 1024)
+ n, _ := io.ReadFull(resp.Body, buf)
+ resp.Body = io.NopCloser(bytes.NewReader(buf[:n]))
+ return nil, resp, ErrBadHandshake
+ }
+
+ for _, ext := range parseExtensions(resp.Header) {
+ if ext[""] != "permessage-deflate" {
+ continue
+ }
+ _, snct := ext["server_no_context_takeover"]
+ _, cnct := ext["client_no_context_takeover"]
+ if !snct || !cnct {
+ return nil, resp, errInvalidCompression
+ }
+ conn.newCompressionWriter = compressNoContextTakeover
+ conn.newDecompressionReader = decompressNoContextTakeover
+ break
+ }
+
+ resp.Body = io.NopCloser(bytes.NewReader([]byte{}))
+ conn.subprotocol = resp.Header.Get("Sec-Websocket-Protocol")
+
+ if err := netConn.SetDeadline(time.Time{}); err != nil {
+ return nil, nil, err
+ }
+ netConn = nil // to avoid close in defer.
+ return conn, resp, nil
+}
+
+func cloneTLSConfig(cfg *tls.Config) *tls.Config {
+ if cfg == nil {
+ return &tls.Config{MinVersion: tls.VersionTLS12}
+ }
+ return cfg.Clone()
+}
diff --git a/vendor/github.com/fasthttp/websocket/compression.go b/vendor/github.com/fasthttp/websocket/compression.go
new file mode 100644
index 0000000..f42aa74
--- /dev/null
+++ b/vendor/github.com/fasthttp/websocket/compression.go
@@ -0,0 +1,154 @@
+// Copyright 2017 The Gorilla WebSocket 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 websocket
+
+import (
+ "errors"
+ "io"
+ "log"
+ "strings"
+ "sync"
+
+ "github.com/klauspost/compress/flate"
+)
+
+const (
+ minCompressionLevel = -2 // flate.HuffmanOnly not defined in Go < 1.6
+ maxCompressionLevel = flate.BestCompression
+ defaultCompressionLevel = 1
+)
+
+var (
+ flateWriterPools [maxCompressionLevel - minCompressionLevel + 1]sync.Pool
+ flateReaderPool = sync.Pool{New: func() interface{} {
+ return flate.NewReader(nil)
+ }}
+)
+
+func decompressNoContextTakeover(r io.Reader) io.ReadCloser {
+ const tail =
+ // Add four bytes as specified in RFC
+ "\x00\x00\xff\xff" +
+ // Add final block to squelch unexpected EOF error from flate reader.
+ "\x01\x00\x00\xff\xff"
+
+ fr, _ := flateReaderPool.Get().(io.ReadCloser)
+ if err := fr.(flate.Resetter).Reset(io.MultiReader(r, strings.NewReader(tail)), nil); err != nil {
+ panic(err)
+ }
+ return &flateReadWrapper{fr}
+}
+
+func isValidCompressionLevel(level int) bool {
+ return minCompressionLevel <= level && level <= maxCompressionLevel
+}
+
+func compressNoContextTakeover(w io.WriteCloser, level int) io.WriteCloser {
+ p := &flateWriterPools[level-minCompressionLevel]
+ tw := &truncWriter{w: w}
+ fw, _ := p.Get().(*flate.Writer)
+ if fw == nil {
+ fw, _ = flate.NewWriter(tw, level)
+ } else {
+ fw.Reset(tw)
+ }
+ return &flateWriteWrapper{fw: fw, tw: tw, p: p}
+}
+
+// truncWriter is an io.Writer that writes all but the last four bytes of the
+// stream to another io.Writer.
+type truncWriter struct {
+ w io.WriteCloser
+ n int
+ p [4]byte
+}
+
+func (w *truncWriter) Write(p []byte) (int, error) {
+ n := 0
+
+ // fill buffer first for simplicity.
+ if w.n < len(w.p) {
+ n = copy(w.p[w.n:], p)
+ p = p[n:]
+ w.n += n
+ if len(p) == 0 {
+ return n, nil
+ }
+ }
+
+ m := len(p)
+ if m > len(w.p) {
+ m = len(w.p)
+ }
+
+ if nn, err := w.w.Write(w.p[:m]); err != nil {
+ return n + nn, err
+ }
+
+ copy(w.p[:], w.p[m:])
+ copy(w.p[len(w.p)-m:], p[len(p)-m:])
+ nn, err := w.w.Write(p[:len(p)-m])
+ return n + nn, err
+}
+
+type flateWriteWrapper struct {
+ fw *flate.Writer
+ tw *truncWriter
+ p *sync.Pool
+}
+
+func (w *flateWriteWrapper) Write(p []byte) (int, error) {
+ if w.fw == nil {
+ return 0, errWriteClosed
+ }
+ return w.fw.Write(p)
+}
+
+func (w *flateWriteWrapper) Close() error {
+ if w.fw == nil {
+ return errWriteClosed
+ }
+ err1 := w.fw.Flush()
+ w.p.Put(w.fw)
+ w.fw = nil
+ if w.tw.p != [4]byte{0, 0, 0xff, 0xff} {
+ return errors.New("websocket: internal error, unexpected bytes at end of flate stream")
+ }
+ err2 := w.tw.w.Close()
+ if err1 != nil {
+ return err1
+ }
+ return err2
+}
+
+type flateReadWrapper struct {
+ fr io.ReadCloser
+}
+
+func (r *flateReadWrapper) Read(p []byte) (int, error) {
+ if r.fr == nil {
+ return 0, io.ErrClosedPipe
+ }
+ n, err := r.fr.Read(p)
+ if err == io.EOF {
+ // Preemptively place the reader back in the pool. This helps with
+ // scenarios where the application does not call NextReader() soon after
+ // this final read.
+ if err := r.Close(); err != nil {
+ log.Printf("websocket: flateReadWrapper.Close() returned error: %v", err)
+ }
+ }
+ return n, err
+}
+
+func (r *flateReadWrapper) Close() error {
+ if r.fr == nil {
+ return io.ErrClosedPipe
+ }
+ err := r.fr.Close()
+ flateReaderPool.Put(r.fr)
+ r.fr = nil
+ return err
+}
diff --git a/vendor/github.com/fasthttp/websocket/conn.go b/vendor/github.com/fasthttp/websocket/conn.go
new file mode 100644
index 0000000..3fcbd57
--- /dev/null
+++ b/vendor/github.com/fasthttp/websocket/conn.go
@@ -0,0 +1,1367 @@
+// Copyright 2013 The Gorilla WebSocket 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 websocket
+
+import (
+ "bufio"
+ "crypto/rand"
+ "encoding/binary"
+ "errors"
+ "io"
+ "log"
+ "net"
+ "strconv"
+ "strings"
+ "sync"
+ "time"
+ "unicode/utf8"
+)
+
+const (
+ // Frame header byte 0 bits from Section 5.2 of RFC 6455
+ finalBit = 1 << 7
+ rsv1Bit = 1 << 6
+ rsv2Bit = 1 << 5
+ rsv3Bit = 1 << 4
+
+ // Frame header byte 1 bits from Section 5.2 of RFC 6455
+ maskBit = 1 << 7
+
+ maxFrameHeaderSize = 2 + 8 + 4 // Fixed header + length + mask
+ maxControlFramePayloadSize = 125
+
+ writeWait = time.Second
+
+ defaultReadBufferSize = 4096
+ defaultWriteBufferSize = 4096
+
+ continuationFrame = 0
+ noFrame = -1
+)
+
+// Close codes defined in RFC 6455, section 11.7.
+const (
+ CloseNormalClosure = 1000
+ CloseGoingAway = 1001
+ CloseProtocolError = 1002
+ CloseUnsupportedData = 1003
+ CloseNoStatusReceived = 1005
+ CloseAbnormalClosure = 1006
+ CloseInvalidFramePayloadData = 1007
+ ClosePolicyViolation = 1008
+ CloseMessageTooBig = 1009
+ CloseMandatoryExtension = 1010
+ CloseInternalServerErr = 1011
+ CloseServiceRestart = 1012
+ CloseTryAgainLater = 1013
+ CloseTLSHandshake = 1015
+)
+
+// The message types are defined in RFC 6455, section 11.8.
+const (
+ // TextMessage denotes a text data message. The text message payload is
+ // interpreted as UTF-8 encoded text data.
+ TextMessage = 1
+
+ // BinaryMessage denotes a binary data message.
+ BinaryMessage = 2
+
+ // CloseMessage denotes a close control message. The optional message
+ // payload contains a numeric code and text. Use the FormatCloseMessage
+ // function to format a close message payload.
+ CloseMessage = 8
+
+ // PingMessage denotes a ping control message. The optional message payload
+ // is UTF-8 encoded text.
+ PingMessage = 9
+
+ // PongMessage denotes a pong control message. The optional message payload
+ // is UTF-8 encoded text.
+ PongMessage = 10
+)
+
+// ErrCloseSent is returned when the application writes a message to the
+// connection after sending a close message.
+var ErrCloseSent = errors.New("websocket: close sent")
+
+// ErrReadLimit is returned when reading a message that is larger than the
+// read limit set for the connection.
+var ErrReadLimit = errors.New("websocket: read limit exceeded")
+
+// netError satisfies the net Error interface.
+type netError struct {
+ msg string
+ temporary bool
+ timeout bool
+}
+
+func (e *netError) Error() string { return e.msg }
+func (e *netError) Temporary() bool { return e.temporary }
+func (e *netError) Timeout() bool { return e.timeout }
+
+// CloseError represents a close message.
+type CloseError struct {
+ // Code is defined in RFC 6455, section 11.7.
+ Code int
+
+ // Text is the optional text payload.
+ Text string
+}
+
+func (e *CloseError) Error() string {
+ s := []byte("websocket: close ")
+ s = strconv.AppendInt(s, int64(e.Code), 10)
+ switch e.Code {
+ case CloseNormalClosure:
+ s = append(s, " (normal)"...)
+ case CloseGoingAway:
+ s = append(s, " (going away)"...)
+ case CloseProtocolError:
+ s = append(s, " (protocol error)"...)
+ case CloseUnsupportedData:
+ s = append(s, " (unsupported data)"...)
+ case CloseNoStatusReceived:
+ s = append(s, " (no status)"...)
+ case CloseAbnormalClosure:
+ s = append(s, " (abnormal closure)"...)
+ case CloseInvalidFramePayloadData:
+ s = append(s, " (invalid payload data)"...)
+ case ClosePolicyViolation:
+ s = append(s, " (policy violation)"...)
+ case CloseMessageTooBig:
+ s = append(s, " (message too big)"...)
+ case CloseMandatoryExtension:
+ s = append(s, " (mandatory extension missing)"...)
+ case CloseInternalServerErr:
+ s = append(s, " (internal server error)"...)
+ case CloseTLSHandshake:
+ s = append(s, " (TLS handshake error)"...)
+ }
+ if e.Text != "" {
+ s = append(s, ": "...)
+ s = append(s, e.Text...)
+ }
+ return string(s)
+}
+
+// IsCloseError returns boolean indicating whether the error is a *CloseError
+// with one of the specified codes.
+func IsCloseError(err error, codes ...int) bool {
+ if e, ok := err.(*CloseError); ok {
+ for _, code := range codes {
+ if e.Code == code {
+ return true
+ }
+ }
+ }
+ return false
+}
+
+// IsUnexpectedCloseError returns boolean indicating whether the error is a
+// *CloseError with a code not in the list of expected codes.
+func IsUnexpectedCloseError(err error, expectedCodes ...int) bool {
+ if e, ok := err.(*CloseError); ok {
+ for _, code := range expectedCodes {
+ if e.Code == code {
+ return false
+ }
+ }
+ return true
+ }
+ return false
+}
+
+var (
+ errWriteTimeout = &netError{msg: "websocket: write timeout", timeout: true, temporary: true}
+ errUnexpectedEOF = &CloseError{Code: CloseAbnormalClosure, Text: io.ErrUnexpectedEOF.Error()}
+ errBadWriteOpCode = errors.New("websocket: bad write message type")
+ errWriteClosed = errors.New("websocket: write closed")
+ errInvalidControlFrame = errors.New("websocket: invalid control frame")
+)
+
+// maskRand is an io.Reader for generating mask bytes. The reader is initialized
+// to crypto/rand Reader. Tests swap the reader to a math/rand reader for
+// reproducible results.
+var maskRand = rand.Reader
+
+// newMaskKey returns a new 32 bit value for masking client frames.
+func newMaskKey() [4]byte {
+ var k [4]byte
+ _, _ = io.ReadFull(maskRand, k[:])
+ return k
+}
+
+func hideTempErr(err error) error {
+ if e, ok := err.(net.Error); ok {
+ err = &netError{msg: e.Error(), timeout: e.Timeout()}
+ }
+ return err
+}
+
+func isControl(frameType int) bool {
+ return frameType == CloseMessage || frameType == PingMessage || frameType == PongMessage
+}
+
+func isData(frameType int) bool {
+ return frameType == TextMessage || frameType == BinaryMessage
+}
+
+var validReceivedCloseCodes = map[int]bool{
+ // see http://www.iana.org/assignments/websocket/websocket.xhtml#close-code-number
+
+ CloseNormalClosure: true,
+ CloseGoingAway: true,
+ CloseProtocolError: true,
+ CloseUnsupportedData: true,
+ CloseNoStatusReceived: false,
+ CloseAbnormalClosure: false,
+ CloseInvalidFramePayloadData: true,
+ ClosePolicyViolation: true,
+ CloseMessageTooBig: true,
+ CloseMandatoryExtension: true,
+ CloseInternalServerErr: true,
+ CloseServiceRestart: true,
+ CloseTryAgainLater: true,
+ CloseTLSHandshake: false,
+}
+
+func isValidReceivedCloseCode(code int) bool {
+ return validReceivedCloseCodes[code] || (code >= 3000 && code <= 4999)
+}
+
+// BufferPool represents a pool of buffers. The *sync.Pool type satisfies this
+// interface. The type of the value stored in a pool is not specified.
+type BufferPool interface {
+ // Get gets a value from the pool or returns nil if the pool is empty.
+ Get() interface{}
+ // Put adds a value to the pool.
+ Put(interface{})
+}
+
+// writePoolData is the type added to the write buffer pool. This wrapper is
+// used to prevent applications from peeking at and depending on the values
+// added to the pool.
+type writePoolData struct{ buf []byte }
+
+// The Conn type represents a WebSocket connection.
+type Conn struct {
+ conn net.Conn
+ isServer bool
+ subprotocol string
+
+ // Write fields
+ mu chan struct{} // used as mutex to protect write to conn
+ writeBuf []byte // frame is constructed in this buffer.
+ writePool BufferPool
+ writeBufSize int
+ writeDeadline time.Time
+ writer io.WriteCloser // the current writer returned to the application
+ isWriting bool // for best-effort concurrent write detection
+
+ writeErrMu sync.Mutex
+ writeErr error
+
+ enableWriteCompression bool
+ compressionLevel int
+ newCompressionWriter func(io.WriteCloser, int) io.WriteCloser
+
+ // Read fields
+ reader io.ReadCloser // the current reader returned to the application
+ readErr error
+ br *bufio.Reader
+ // bytes remaining in current frame.
+ // set setReadRemaining to safely update this value and prevent overflow
+ readRemaining int64
+ readFinal bool // true the current message has more frames.
+ readLength int64 // Message size.
+ readLimit int64 // Maximum message size.
+ readMaskPos int
+ readMaskKey [4]byte
+ handlePong func(string) error
+ handlePing func(string) error
+ handleClose func(int, string) error
+ readErrCount int
+ messageReader *messageReader // the current low-level reader
+
+ readDecompress bool // whether last read frame had RSV1 set
+ newDecompressionReader func(io.Reader) io.ReadCloser
+}
+
+func newConn(conn net.Conn, isServer bool, readBufferSize, writeBufferSize int, writeBufferPool BufferPool, br *bufio.Reader, writeBuf []byte) *Conn {
+
+ if br == nil {
+ if readBufferSize == 0 {
+ readBufferSize = defaultReadBufferSize
+ } else if readBufferSize < maxControlFramePayloadSize {
+ // must be large enough for control frame
+ readBufferSize = maxControlFramePayloadSize
+ }
+ br = bufio.NewReaderSize(conn, readBufferSize)
+ }
+
+ if writeBufferSize <= 0 {
+ writeBufferSize = defaultWriteBufferSize
+ }
+ writeBufferSize += maxFrameHeaderSize
+
+ if writeBuf == nil && writeBufferPool == nil {
+ writeBuf = make([]byte, writeBufferSize)
+ }
+
+ mu := make(chan struct{}, 1)
+ mu <- struct{}{}
+ c := &Conn{
+ isServer: isServer,
+ br: br,
+ conn: conn,
+ mu: mu,
+ readFinal: true,
+ writeBuf: writeBuf,
+ writePool: writeBufferPool,
+ writeBufSize: writeBufferSize,
+ enableWriteCompression: true,
+ compressionLevel: defaultCompressionLevel,
+ }
+ c.SetCloseHandler(nil)
+ c.SetPingHandler(nil)
+ c.SetPongHandler(nil)
+ return c
+}
+
+// setReadRemaining tracks the number of bytes remaining on the connection. If n
+// overflows, an ErrReadLimit is returned.
+func (c *Conn) setReadRemaining(n int64) error {
+ if n < 0 {
+ return ErrReadLimit
+ }
+
+ c.readRemaining = n
+ return nil
+}
+
+// Subprotocol returns the negotiated protocol for the connection.
+func (c *Conn) Subprotocol() string {
+ if c == nil {
+ return ""
+ }
+ return c.subprotocol
+}
+
+// Close closes the underlying network connection without sending or waiting
+// for a close message.
+func (c *Conn) Close() error {
+ if c == nil {
+ return ErrNilConn
+ }
+ if c.conn == nil {
+ return ErrNilNetConn
+ }
+ return c.conn.Close()
+}
+
+// LocalAddr returns the local network address.
+func (c *Conn) LocalAddr() net.Addr {
+ if c == nil || c.conn == nil {
+ return nil
+ }
+ return c.conn.LocalAddr()
+}
+
+// RemoteAddr returns the remote network address.
+func (c *Conn) RemoteAddr() net.Addr {
+ if c == nil || c.conn == nil {
+ return nil
+ }
+ return c.conn.RemoteAddr()
+}
+
+// Write methods
+
+func (c *Conn) writeFatal(err error) error {
+ if c == nil {
+ return ErrNilConn
+ }
+ err = hideTempErr(err)
+ c.writeErrMu.Lock()
+ if c.writeErr == nil {
+ c.writeErr = err
+ }
+ c.writeErrMu.Unlock()
+ return err
+}
+
+func (c *Conn) read(n int) ([]byte, error) {
+ if c == nil {
+ return nil, ErrNilConn
+ }
+ p, err := c.br.Peek(n)
+ if err == io.EOF {
+ err = errUnexpectedEOF
+ }
+ if _, err := c.br.Discard(len(p)); err != nil {
+ return p, err
+ }
+ return p, err
+}
+
+func (c *Conn) write(frameType int, deadline time.Time, buf0, buf1 []byte) error {
+ if c == nil {
+ return ErrNilConn
+ }
+ <-c.mu
+ defer func() { c.mu <- struct{}{} }()
+
+ c.writeErrMu.Lock()
+ err := c.writeErr
+ c.writeErrMu.Unlock()
+ if err != nil {
+ return err
+ }
+ if c.conn == nil {
+ return ErrNilNetConn
+ }
+ if err := c.conn.SetWriteDeadline(deadline); err != nil {
+ return c.writeFatal(err)
+ }
+ if len(buf1) == 0 {
+ _, err = c.conn.Write(buf0)
+ } else {
+ err = c.writeBufs(buf0, buf1)
+ }
+ if err != nil {
+ return c.writeFatal(err)
+ }
+ if frameType == CloseMessage {
+ _ = c.writeFatal(ErrCloseSent)
+ }
+ return nil
+}
+
+func (c *Conn) writeBufs(bufs ...[]byte) error {
+ b := net.Buffers(bufs)
+ _, err := b.WriteTo(c.conn)
+ return err
+}
+
+// WriteControl writes a control message with the given deadline. The allowed
+// message types are CloseMessage, PingMessage and PongMessage.
+func (c *Conn) WriteControl(messageType int, data []byte, deadline time.Time) error {
+ if c == nil {
+ return ErrNilConn
+ }
+ if !isControl(messageType) {
+ return errBadWriteOpCode
+ }
+ if len(data) > maxControlFramePayloadSize {
+ return errInvalidControlFrame
+ }
+
+ b0 := byte(messageType) | finalBit
+ b1 := byte(len(data))
+ if !c.isServer {
+ b1 |= maskBit
+ }
+
+ buf := make([]byte, 0, maxFrameHeaderSize+maxControlFramePayloadSize)
+ buf = append(buf, b0, b1)
+
+ if c.isServer {
+ buf = append(buf, data...)
+ } else {
+ key := newMaskKey()
+ buf = append(buf, key[:]...)
+ buf = append(buf, data...)
+ maskBytes(key, 0, buf[6:])
+ }
+
+ d := 1000 * time.Hour
+ if !deadline.IsZero() {
+ d = time.Until(deadline)
+ if d < 0 {
+ return errWriteTimeout
+ }
+ }
+
+ timer := time.NewTimer(d)
+ select {
+ case <-c.mu:
+ timer.Stop()
+ case <-timer.C:
+ return errWriteTimeout
+ }
+ defer func() { c.mu <- struct{}{} }()
+
+ c.writeErrMu.Lock()
+ err := c.writeErr
+ c.writeErrMu.Unlock()
+ if err != nil {
+ return err
+ }
+ if c.conn == nil {
+ return ErrNilNetConn
+ }
+ if err := c.conn.SetWriteDeadline(deadline); err != nil {
+ return c.writeFatal(err)
+ }
+ _, err = c.conn.Write(buf)
+ if err != nil {
+ return c.writeFatal(err)
+ }
+ if messageType == CloseMessage {
+ _ = c.writeFatal(ErrCloseSent)
+ }
+ return err
+}
+
+// beginMessage prepares a connection and message writer for a new message.
+func (c *Conn) beginMessage(mw *messageWriter, messageType int) error {
+ if c == nil {
+ return ErrNilConn
+ }
+ // Close previous writer if not already closed by the application. It's
+ // probably better to return an error in this situation, but we cannot
+ // change this without breaking existing applications.
+ if c.writer != nil {
+ if err := c.writer.Close(); err != nil {
+ log.Printf("websocket: discarding writer close error: %v", err)
+ }
+ c.writer = nil
+ }
+
+ if !isControl(messageType) && !isData(messageType) {
+ return errBadWriteOpCode
+ }
+
+ c.writeErrMu.Lock()
+ err := c.writeErr
+ c.writeErrMu.Unlock()
+ if err != nil {
+ return err
+ }
+
+ mw.c = c
+ mw.frameType = messageType
+ mw.pos = maxFrameHeaderSize
+
+ if c.writeBuf == nil {
+ wpd, ok := c.writePool.Get().(writePoolData)
+ if ok {
+ c.writeBuf = wpd.buf
+ } else {
+ c.writeBuf = make([]byte, c.writeBufSize)
+ }
+ }
+ return nil
+}
+
+// NextWriter returns a writer for the next message to send. The writer's Close
+// method flushes the complete message to the network.
+//
+// There can be at most one open writer on a connection. NextWriter closes the
+// previous writer if the application has not already done so.
+//
+// All message types (TextMessage, BinaryMessage, CloseMessage, PingMessage and
+// PongMessage) are supported.
+func (c *Conn) NextWriter(messageType int) (io.WriteCloser, error) {
+ if c == nil {
+ return nil, ErrNilConn
+ }
+ var mw messageWriter
+ if err := c.beginMessage(&mw, messageType); err != nil {
+ return nil, err
+ }
+ c.writer = &mw
+ if c.newCompressionWriter != nil && c.enableWriteCompression && isData(messageType) {
+ w := c.newCompressionWriter(c.writer, c.compressionLevel)
+ mw.compress = true
+ c.writer = w
+ }
+ return c.writer, nil
+}
+
+type messageWriter struct {
+ c *Conn
+ compress bool // whether next call to flushFrame should set RSV1
+ pos int // end of data in writeBuf.
+ frameType int // type of the current frame.
+ err error
+}
+
+func (w *messageWriter) endMessage(err error) error {
+ if w.err != nil {
+ return err
+ }
+ c := w.c
+ w.err = err
+ c.writer = nil
+ if c.writePool != nil {
+ c.writePool.Put(writePoolData{buf: c.writeBuf})
+ c.writeBuf = nil
+ }
+ return err
+}
+
+// flushFrame writes buffered data and extra as a frame to the network. The
+// final argument indicates that this is the last frame in the message.
+func (w *messageWriter) flushFrame(final bool, extra []byte) error {
+ c := w.c
+ if c == nil {
+ return ErrNilConn
+ }
+ length := w.pos - maxFrameHeaderSize + len(extra)
+
+ // Check for invalid control frames.
+ if isControl(w.frameType) &&
+ (!final || length > maxControlFramePayloadSize) {
+ return w.endMessage(errInvalidControlFrame)
+ }
+
+ b0 := byte(w.frameType)
+ if final {
+ b0 |= finalBit
+ }
+ if w.compress {
+ b0 |= rsv1Bit
+ }
+ w.compress = false
+
+ b1 := byte(0)
+ if !c.isServer {
+ b1 |= maskBit
+ }
+
+ // Assume that the frame starts at beginning of c.writeBuf.
+ framePos := 0
+ if c.isServer {
+ // Adjust up if mask not included in the header.
+ framePos = 4
+ }
+
+ switch {
+ case length >= 65536:
+ c.writeBuf[framePos] = b0
+ c.writeBuf[framePos+1] = b1 | 127
+ binary.BigEndian.PutUint64(c.writeBuf[framePos+2:], uint64(length))
+ case length > 125:
+ framePos += 6
+ c.writeBuf[framePos] = b0
+ c.writeBuf[framePos+1] = b1 | 126
+ binary.BigEndian.PutUint16(c.writeBuf[framePos+2:], uint16(length))
+ default:
+ framePos += 8
+ c.writeBuf[framePos] = b0
+ c.writeBuf[framePos+1] = b1 | byte(length)
+ }
+
+ if !c.isServer {
+ key := newMaskKey()
+ copy(c.writeBuf[maxFrameHeaderSize-4:], key[:])
+ maskBytes(key, 0, c.writeBuf[maxFrameHeaderSize:w.pos])
+ if len(extra) > 0 {
+ return w.endMessage(c.writeFatal(errors.New("websocket: internal error, extra used in client mode")))
+ }
+ }
+
+ // Write the buffers to the connection with best-effort detection of
+ // concurrent writes. See the concurrency section in the package
+ // documentation for more info.
+
+ if c.isWriting {
+ panic("concurrent write to websocket connection")
+ }
+ c.isWriting = true
+
+ err := c.write(w.frameType, c.writeDeadline, c.writeBuf[framePos:w.pos], extra)
+
+ if !c.isWriting {
+ panic("concurrent write to websocket connection")
+ }
+ c.isWriting = false
+
+ if err != nil {
+ return w.endMessage(err)
+ }
+
+ if final {
+ _ = w.endMessage(errWriteClosed)
+ return nil
+ }
+
+ // Setup for next frame.
+ w.pos = maxFrameHeaderSize
+ w.frameType = continuationFrame
+ return nil
+}
+
+func (w *messageWriter) ncopy(max int) (int, error) {
+ n := len(w.c.writeBuf) - w.pos
+ if n <= 0 {
+ if err := w.flushFrame(false, nil); err != nil {
+ return 0, err
+ }
+ n = len(w.c.writeBuf) - w.pos
+ }
+ if n > max {
+ n = max
+ }
+ return n, nil
+}
+
+func (w *messageWriter) Write(p []byte) (int, error) {
+ if w.err != nil {
+ return 0, w.err
+ }
+
+ if len(p) > 2*len(w.c.writeBuf) && w.c.isServer {
+ // Don't buffer large messages.
+ err := w.flushFrame(false, p)
+ if err != nil {
+ return 0, err
+ }
+ return len(p), nil
+ }
+
+ nn := len(p)
+ for len(p) > 0 {
+ n, err := w.ncopy(len(p))
+ if err != nil {
+ return 0, err
+ }
+ copy(w.c.writeBuf[w.pos:], p[:n])
+ w.pos += n
+ p = p[n:]
+ }
+ return nn, nil
+}
+
+func (w *messageWriter) WriteString(p string) (int, error) {
+ if w.err != nil {
+ return 0, w.err
+ }
+
+ nn := len(p)
+ for len(p) > 0 {
+ n, err := w.ncopy(len(p))
+ if err != nil {
+ return 0, err
+ }
+ copy(w.c.writeBuf[w.pos:], p[:n])
+ w.pos += n
+ p = p[n:]
+ }
+ return nn, nil
+}
+
+func (w *messageWriter) ReadFrom(r io.Reader) (nn int64, err error) {
+ if w.err != nil {
+ return 0, w.err
+ }
+ for {
+ if w.pos == len(w.c.writeBuf) {
+ err = w.flushFrame(false, nil)
+ if err != nil {
+ break
+ }
+ }
+ var n int
+ n, err = r.Read(w.c.writeBuf[w.pos:])
+ w.pos += n
+ nn += int64(n)
+ if err != nil {
+ if err == io.EOF {
+ err = nil
+ }
+ break
+ }
+ }
+ return nn, err
+}
+
+func (w *messageWriter) Close() error {
+ if w.err != nil {
+ return w.err
+ }
+ return w.flushFrame(true, nil)
+}
+
+// WritePreparedMessage writes prepared message into connection.
+func (c *Conn) WritePreparedMessage(pm *PreparedMessage) error {
+ if c == nil {
+ return ErrNilConn
+ }
+ frameType, frameData, err := pm.frame(prepareKey{
+ isServer: c.isServer,
+ compress: c.newCompressionWriter != nil && c.enableWriteCompression && isData(pm.messageType),
+ compressionLevel: c.compressionLevel,
+ })
+ if err != nil {
+ return err
+ }
+ if c.isWriting {
+ panic("concurrent write to websocket connection")
+ }
+ c.isWriting = true
+ err = c.write(frameType, c.writeDeadline, frameData, nil)
+ if !c.isWriting {
+ panic("concurrent write to websocket connection")
+ }
+ c.isWriting = false
+ return err
+}
+
+// WriteMessage is a helper method for getting a writer using NextWriter,
+// writing the message and closing the writer.
+func (c *Conn) WriteMessage(messageType int, data []byte) error {
+ if c == nil {
+ return ErrNilConn
+ }
+ if c.isServer && (c.newCompressionWriter == nil || !c.enableWriteCompression) {
+ // Fast path with no allocations and single frame.
+
+ var mw messageWriter
+ if err := c.beginMessage(&mw, messageType); err != nil {
+ return err
+ }
+ n := copy(c.writeBuf[mw.pos:], data)
+ mw.pos += n
+ data = data[n:]
+ return mw.flushFrame(true, data)
+ }
+
+ w, err := c.NextWriter(messageType)
+ if err != nil {
+ return err
+ }
+ if _, err = w.Write(data); err != nil {
+ return err
+ }
+ return w.Close()
+}
+
+// SetWriteDeadline sets the write deadline on the underlying network
+// connection. After a write has timed out, the websocket state is corrupt and
+// all future writes will return an error. A zero value for t means writes will
+// not time out.
+func (c *Conn) SetWriteDeadline(t time.Time) error {
+ if c == nil {
+ return ErrNilConn
+ }
+ c.writeDeadline = t
+ return nil
+}
+
+// Read methods
+
+func (c *Conn) advanceFrame() (int, error) {
+ // 1. Skip remainder of previous frame.
+
+ if c.readRemaining > 0 {
+ if _, err := io.CopyN(io.Discard, c.br, c.readRemaining); err != nil {
+ return noFrame, err
+ }
+ }
+
+ // 2. Read and parse first two bytes of frame header.
+ // To aid debugging, collect and report all errors in the first two bytes
+ // of the header.
+
+ var errors []string
+
+ p, err := c.read(2)
+ if err != nil {
+ return noFrame, err
+ }
+
+ frameType := int(p[0] & 0xf)
+ final := p[0]&finalBit != 0
+ rsv1 := p[0]&rsv1Bit != 0
+ rsv2 := p[0]&rsv2Bit != 0
+ rsv3 := p[0]&rsv3Bit != 0
+ mask := p[1]&maskBit != 0
+ if err := c.setReadRemaining(int64(p[1] & 0x7f)); err != nil {
+ return noFrame, err
+ }
+
+ c.readDecompress = false
+ if rsv1 {
+ if c.newDecompressionReader != nil {
+ c.readDecompress = true
+ } else {
+ errors = append(errors, "RSV1 set")
+ }
+ }
+
+ if rsv2 {
+ errors = append(errors, "RSV2 set")
+ }
+
+ if rsv3 {
+ errors = append(errors, "RSV3 set")
+ }
+
+ switch frameType {
+ case CloseMessage, PingMessage, PongMessage:
+ if c.readRemaining > maxControlFramePayloadSize {
+ errors = append(errors, "len > 125 for control")
+ }
+ if !final {
+ errors = append(errors, "FIN not set on control")
+ }
+ case TextMessage, BinaryMessage:
+ if !c.readFinal {
+ errors = append(errors, "data before FIN")
+ }
+ c.readFinal = final
+ case continuationFrame:
+ if c.readFinal {
+ errors = append(errors, "continuation after FIN")
+ }
+ c.readFinal = final
+ default:
+ errors = append(errors, "bad opcode "+strconv.Itoa(frameType))
+ }
+
+ if mask != c.isServer {
+ errors = append(errors, "bad MASK")
+ }
+
+ if len(errors) > 0 {
+ return noFrame, c.handleProtocolError(strings.Join(errors, ", "))
+ }
+
+ // 3. Read and parse frame length as per
+ // https://tools.ietf.org/html/rfc6455#section-5.2
+ //
+ // The length of the "Payload data", in bytes: if 0-125, that is the payload
+ // length.
+ // - If 126, the following 2 bytes interpreted as a 16-bit unsigned
+ // integer are the payload length.
+ // - If 127, the following 8 bytes interpreted as
+ // a 64-bit unsigned integer (the most significant bit MUST be 0) are the
+ // payload length. Multibyte length quantities are expressed in network byte
+ // order.
+
+ switch c.readRemaining {
+ case 126:
+ p, err := c.read(2)
+ if err != nil {
+ return noFrame, err
+ }
+
+ if err := c.setReadRemaining(int64(binary.BigEndian.Uint16(p))); err != nil {
+ return noFrame, err
+ }
+ case 127:
+ p, err := c.read(8)
+ if err != nil {
+ return noFrame, err
+ }
+
+ if err := c.setReadRemaining(int64(binary.BigEndian.Uint64(p))); err != nil {
+ return noFrame, err
+ }
+ }
+
+ // 4. Handle frame masking.
+
+ if mask {
+ c.readMaskPos = 0
+ p, err := c.read(len(c.readMaskKey))
+ if err != nil {
+ return noFrame, err
+ }
+ copy(c.readMaskKey[:], p)
+ }
+
+ // 5. For text and binary messages, enforce read limit and return.
+
+ if frameType == continuationFrame || frameType == TextMessage || frameType == BinaryMessage {
+
+ c.readLength += c.readRemaining
+ // Don't allow readLength to overflow in the presence of a large readRemaining
+ // counter.
+ if c.readLength < 0 {
+ return noFrame, ErrReadLimit
+ }
+
+ if c.readLimit > 0 && c.readLength > c.readLimit {
+ if err := c.WriteControl(CloseMessage, FormatCloseMessage(CloseMessageTooBig, ""), time.Now().Add(writeWait)); err != nil {
+ return noFrame, err
+ }
+ return noFrame, ErrReadLimit
+ }
+
+ return frameType, nil
+ }
+
+ // 6. Read control frame payload.
+
+ var payload []byte
+ if c.readRemaining > 0 {
+ payload, err = c.read(int(c.readRemaining))
+ if err := c.setReadRemaining(0); err != nil {
+ return noFrame, err
+ }
+ if err != nil {
+ return noFrame, err
+ }
+ if c.isServer {
+ maskBytes(c.readMaskKey, 0, payload)
+ }
+ }
+
+ // 7. Process control frame payload.
+
+ switch frameType {
+ case PongMessage:
+ if err := c.handlePong(string(payload)); err != nil {
+ return noFrame, err
+ }
+ case PingMessage:
+ if err := c.handlePing(string(payload)); err != nil {
+ return noFrame, err
+ }
+ case CloseMessage:
+ closeCode := CloseNoStatusReceived
+ closeText := ""
+ if len(payload) >= 2 {
+ closeCode = int(binary.BigEndian.Uint16(payload))
+ if !isValidReceivedCloseCode(closeCode) {
+ return noFrame, c.handleProtocolError("bad close code " + strconv.Itoa(closeCode))
+ }
+ closeText = string(payload[2:])
+ if !utf8.ValidString(closeText) {
+ return noFrame, c.handleProtocolError("invalid utf8 payload in close frame")
+ }
+ }
+ if err := c.handleClose(closeCode, closeText); err != nil {
+ return noFrame, err
+ }
+ return noFrame, &CloseError{Code: closeCode, Text: closeText}
+ }
+
+ return frameType, nil
+}
+
+func (c *Conn) handleProtocolError(message string) error {
+ if c == nil {
+ return ErrNilConn
+ }
+ data := FormatCloseMessage(CloseProtocolError, message)
+ if len(data) > maxControlFramePayloadSize {
+ data = data[:maxControlFramePayloadSize]
+ }
+ if err := c.WriteControl(CloseMessage, data, time.Now().Add(writeWait)); err != nil {
+ return err
+ }
+ return errors.New("websocket: " + message)
+}
+
+// NextReader returns the next data message received from the peer. The
+// returned messageType is either TextMessage or BinaryMessage.
+//
+// There can be at most one open reader on a connection. NextReader discards
+// the previous message if the application has not already consumed it.
+//
+// Applications must break out of the application's read loop when this method
+// returns a non-nil error value. Errors returned from this method are
+// permanent. Once this method returns a non-nil error, all subsequent calls to
+// this method return the same error.
+func (c *Conn) NextReader() (messageType int, r io.Reader, err error) {
+ if c == nil {
+ return 0, nil, ErrNilConn
+ }
+ // Close previous reader, only relevant for decompression.
+ if c.reader != nil {
+ if err := c.reader.Close(); err != nil {
+ log.Printf("websocket: discarding reader close error: %v", err)
+ }
+ c.reader = nil
+ }
+
+ c.messageReader = nil
+ c.readLength = 0
+
+ for c.readErr == nil {
+ frameType, err := c.advanceFrame()
+ if err != nil {
+ c.readErr = hideTempErr(err)
+ break
+ }
+
+ if frameType == TextMessage || frameType == BinaryMessage {
+ c.messageReader = &messageReader{c}
+ c.reader = c.messageReader
+ if c.readDecompress {
+ c.reader = c.newDecompressionReader(c.reader)
+ }
+ return frameType, c.reader, nil
+ }
+ }
+
+ // Applications that do handle the error returned from this method spin in
+ // tight loop on connection failure. To help application developers detect
+ // this error, panic on repeated reads to the failed connection.
+ c.readErrCount++
+ if c.readErrCount >= 1000 {
+ panic("repeated read on failed websocket connection")
+ }
+
+ return noFrame, nil, c.readErr
+}
+
+type messageReader struct{ c *Conn }
+
+func (r *messageReader) Read(b []byte) (int, error) {
+ c := r.c
+ if c == nil {
+ return 0, ErrNilConn
+ }
+ if c.messageReader != r {
+ return 0, io.EOF
+ }
+
+ for c.readErr == nil {
+
+ if c.readRemaining > 0 {
+ if int64(len(b)) > c.readRemaining {
+ b = b[:c.readRemaining]
+ }
+ n, err := c.br.Read(b)
+ c.readErr = hideTempErr(err)
+ if c.isServer {
+ c.readMaskPos = maskBytes(c.readMaskKey, c.readMaskPos, b[:n])
+ }
+ rem := c.readRemaining
+ rem -= int64(n)
+ if err := c.setReadRemaining(rem); err != nil {
+ return 0, err
+ }
+ if c.readRemaining > 0 && c.readErr == io.EOF {
+ c.readErr = errUnexpectedEOF
+ }
+ return n, c.readErr
+ }
+
+ if c.readFinal {
+ c.messageReader = nil
+ return 0, io.EOF
+ }
+
+ frameType, err := c.advanceFrame()
+ switch {
+ case err != nil:
+ c.readErr = hideTempErr(err)
+ case frameType == TextMessage || frameType == BinaryMessage:
+ c.readErr = errors.New("websocket: internal error, unexpected text or binary in Reader")
+ }
+ }
+
+ err := c.readErr
+ if err == io.EOF && c.messageReader == r {
+ err = errUnexpectedEOF
+ }
+ return 0, err
+}
+
+func (r *messageReader) Close() error {
+ return nil
+}
+
+// ReadMessage is a helper method for getting a reader using NextReader and
+// reading from that reader to a buffer.
+func (c *Conn) ReadMessage() (messageType int, p []byte, err error) {
+ if c == nil {
+ return 0, nil, ErrNilConn
+ }
+ var r io.Reader
+ messageType, r, err = c.NextReader()
+ if err != nil {
+ return messageType, nil, err
+ }
+ p, err = io.ReadAll(r)
+ return messageType, p, err
+}
+
+// SetReadDeadline sets the read deadline on the underlying network connection.
+// After a read has timed out, the websocket connection state is corrupt and
+// all future reads will return an error. A zero value for t means reads will
+// not time out.
+func (c *Conn) SetReadDeadline(t time.Time) error {
+ if c == nil {
+ return ErrNilConn
+ }
+ if c.conn == nil {
+ return ErrNilNetConn
+ }
+ return c.conn.SetReadDeadline(t)
+}
+
+// SetReadLimit sets the maximum size in bytes for a message read from the peer. If a
+// message exceeds the limit, the connection sends a close message to the peer
+// and returns ErrReadLimit to the application.
+func (c *Conn) SetReadLimit(limit int64) {
+ if c == nil {
+ return
+ }
+ c.readLimit = limit
+}
+
+// CloseHandler returns the current close handler
+func (c *Conn) CloseHandler() func(code int, text string) error {
+ if c == nil {
+ return nil
+ }
+ return c.handleClose
+}
+
+// SetCloseHandler sets the handler for close messages received from the peer.
+// The code argument to h is the received close code or CloseNoStatusReceived
+// if the close message is empty. The default close handler sends a close
+// message back to the peer.
+//
+// The handler function is called from the NextReader, ReadMessage and message
+// reader Read methods. The application must read the connection to process
+// close messages as described in the section on Control Messages above.
+//
+// The connection read methods return a CloseError when a close message is
+// received. Most applications should handle close messages as part of their
+// normal error handling. Applications should only set a close handler when the
+// application must perform some action before sending a close message back to
+// the peer.
+func (c *Conn) SetCloseHandler(h func(code int, text string) error) {
+ if c == nil {
+ return
+ }
+ if h == nil {
+ h = func(code int, text string) error {
+ message := FormatCloseMessage(code, "")
+ err := c.WriteControl(CloseMessage, message, time.Now().Add(writeWait))
+ if err != nil && err != ErrCloseSent {
+ return err
+ }
+ return nil
+ }
+ }
+ c.handleClose = h
+}
+
+// PingHandler returns the current ping handler
+func (c *Conn) PingHandler() func(appData string) error {
+ if c == nil {
+ return nil
+ }
+ return c.handlePing
+}
+
+// SetPingHandler sets the handler for ping messages received from the peer.
+// The appData argument to h is the PING message application data. The default
+// ping handler sends a pong to the peer.
+//
+// The handler function is called from the NextReader, ReadMessage and message
+// reader Read methods. The application must read the connection to process
+// ping messages as described in the section on Control Messages above.
+func (c *Conn) SetPingHandler(h func(appData string) error) {
+ if c == nil {
+ return
+ }
+ if h == nil {
+ h = func(message string) error {
+ err := c.WriteControl(PongMessage, []byte(message), time.Now().Add(writeWait))
+ if err == ErrCloseSent {
+ return nil
+ } else if _, ok := err.(net.Error); ok {
+ return nil
+ }
+ return err
+ }
+ }
+ c.handlePing = h
+}
+
+// PongHandler returns the current pong handler
+func (c *Conn) PongHandler() func(appData string) error {
+ if c == nil {
+ return nil
+ }
+ return c.handlePong
+}
+
+// SetPongHandler sets the handler for pong messages received from the peer.
+// The appData argument to h is the PONG message application data. The default
+// pong handler does nothing.
+//
+// The handler function is called from the NextReader, ReadMessage and message
+// reader Read methods. The application must read the connection to process
+// pong messages as described in the section on Control Messages above.
+func (c *Conn) SetPongHandler(h func(appData string) error) {
+ if c == nil {
+ return
+ }
+ if h == nil {
+ h = func(string) error { return nil }
+ }
+ c.handlePong = h
+}
+
+// NetConn returns the underlying connection that is wrapped by c.
+// Note that writing to or reading from this connection directly will corrupt the
+// WebSocket connection.
+func (c *Conn) NetConn() net.Conn {
+ if c == nil {
+ return nil
+ }
+ return c.conn
+}
+
+// UnderlyingConn returns the internal net.Conn. This can be used to further
+// modifications to connection specific flags.
+// Deprecated: Use the NetConn method.
+func (c *Conn) UnderlyingConn() net.Conn {
+ if c == nil {
+ return nil
+ }
+ return c.conn
+}
+
+// EnableWriteCompression enables and disables write compression of
+// subsequent text and binary messages. This function is a noop if
+// compression was not negotiated with the peer.
+func (c *Conn) EnableWriteCompression(enable bool) {
+ if c == nil {
+ return
+ }
+ c.enableWriteCompression = enable
+}
+
+// SetCompressionLevel sets the flate compression level for subsequent text and
+// binary messages. This function is a noop if compression was not negotiated
+// with the peer. See the github.com/klauspost/compress/flate package for a description of
+// compression levels.
+func (c *Conn) SetCompressionLevel(level int) error {
+ if c == nil {
+ return ErrNilConn
+ }
+ if !isValidCompressionLevel(level) {
+ return errors.New("websocket: invalid compression level")
+ }
+ c.compressionLevel = level
+ return nil
+}
+
+// FormatCloseMessage formats closeCode and text as a WebSocket close message.
+// An empty message is returned for code CloseNoStatusReceived.
+func FormatCloseMessage(closeCode int, text string) []byte {
+ if closeCode == CloseNoStatusReceived {
+ // Return empty message because it's illegal to send
+ // CloseNoStatusReceived. Return non-nil value in case application
+ // checks for nil.
+ return []byte{}
+ }
+ buf := make([]byte, 2+len(text))
+ binary.BigEndian.PutUint16(buf, uint16(closeCode))
+ copy(buf[2:], text)
+ return buf
+}
diff --git a/vendor/github.com/fasthttp/websocket/doc.go b/vendor/github.com/fasthttp/websocket/doc.go
new file mode 100644
index 0000000..4471dd2
--- /dev/null
+++ b/vendor/github.com/fasthttp/websocket/doc.go
@@ -0,0 +1,246 @@
+// Copyright 2013 The Gorilla WebSocket 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 websocket implements the WebSocket protocol defined in RFC 6455.
+//
+// Overview
+//
+// The Conn type represents a WebSocket connection. A server application calls
+// the Upgrader.Upgrade method from an HTTP request handler to get a *Conn:
+//
+// net/http
+//
+// var upgrader = websocket.Upgrader{
+// ReadBufferSize: 1024,
+// WriteBufferSize: 1024,
+// }
+//
+// func handler(w http.ResponseWriter, r *http.Request) {
+// conn, err := upgrader.Upgrade(w, r, nil)
+// if err != nil {
+// log.Println(err)
+// return
+// }
+// ... Use conn to send and receive messages.
+// }
+//
+// valyala/fasthttp
+//
+// var upgrader = websocket.FastHTTPUpgrader{
+// ReadBufferSize: 1024,
+// WriteBufferSize: 1024,
+// }
+//
+// func handler(ctx *fasthttp.RequestCtx) {
+// err := upgrader.Upgrade(ctx, func(conn *websocket.Conn) {
+// ... Use conn to send and receive messages.
+// })
+// if err != nil {
+// log.Println(err)
+// return
+// }
+// }
+//
+// Call the connection's WriteMessage and ReadMessage methods to send and
+// receive messages as a slice of bytes. This snippet of code shows how to echo
+// messages using these methods:
+//
+// for {
+// messageType, p, err := conn.ReadMessage()
+// if err != nil {
+// log.Println(err)
+// return
+// }
+// if err := conn.WriteMessage(messageType, p); err != nil {
+// log.Println(err)
+// return
+// }
+// }
+//
+// In above snippet of code, p is a []byte and messageType is an int with value
+// websocket.BinaryMessage or websocket.TextMessage.
+//
+// An application can also send and receive messages using the io.WriteCloser
+// and io.Reader interfaces. To send a message, call the connection NextWriter
+// method to get an io.WriteCloser, write the message to the writer and close
+// the writer when done. To receive a message, call the connection NextReader
+// method to get an io.Reader and read until io.EOF is returned. This snippet
+// shows how to echo messages using the NextWriter and NextReader methods:
+//
+// for {
+// messageType, r, err := conn.NextReader()
+// if err != nil {
+// return
+// }
+// w, err := conn.NextWriter(messageType)
+// if err != nil {
+// return err
+// }
+// if _, err := io.Copy(w, r); err != nil {
+// return err
+// }
+// if err := w.Close(); err != nil {
+// return err
+// }
+// }
+//
+// Data Messages
+//
+// The WebSocket protocol distinguishes between text and binary data messages.
+// Text messages are interpreted as UTF-8 encoded text. The interpretation of
+// binary messages is left to the application.
+//
+// This package uses the TextMessage and BinaryMessage integer constants to
+// identify the two data message types. The ReadMessage and NextReader methods
+// return the type of the received message. The messageType argument to the
+// WriteMessage and NextWriter methods specifies the type of a sent message.
+//
+// It is the application's responsibility to ensure that text messages are
+// valid UTF-8 encoded text.
+//
+// Control Messages
+//
+// The WebSocket protocol defines three types of control messages: close, ping
+// and pong. Call the connection WriteControl, WriteMessage or NextWriter
+// methods to send a control message to the peer.
+//
+// Connections handle received close messages by calling the handler function
+// set with the SetCloseHandler method and by returning a *CloseError from the
+// NextReader, ReadMessage or the message Read method. The default close
+// handler sends a close message to the peer.
+//
+// Connections handle received ping messages by calling the handler function
+// set with the SetPingHandler method. The default ping handler sends a pong
+// message to the peer.
+//
+// Connections handle received pong messages by calling the handler function
+// set with the SetPongHandler method. The default pong handler does nothing.
+// If an application sends ping messages, then the application should set a
+// pong handler to receive the corresponding pong.
+//
+// The control message handler functions are called from the NextReader,
+// ReadMessage and message reader Read methods. The default close and ping
+// handlers can block these methods for a short time when the handler writes to
+// the connection.
+//
+// The application must read the connection to process close, ping and pong
+// messages sent from the peer. If the application is not otherwise interested
+// in messages from the peer, then the application should start a goroutine to
+// read and discard messages from the peer. A simple example is:
+//
+// func readLoop(c *websocket.Conn) {
+// for {
+// if _, _, err := c.NextReader(); err != nil {
+// c.Close()
+// break
+// }
+// }
+// }
+//
+// Concurrency
+//
+// Connections support one concurrent reader and one concurrent writer.
+//
+// Applications are responsible for ensuring that no more than one goroutine
+// calls the write methods (NextWriter, SetWriteDeadline, WriteMessage,
+// WriteJSON, EnableWriteCompression, SetCompressionLevel) concurrently and
+// that no more than one goroutine calls the read methods (NextReader,
+// SetReadDeadline, ReadMessage, ReadJSON, SetPongHandler, SetPingHandler)
+// concurrently.
+//
+// The Close and WriteControl methods can be called concurrently with all other
+// methods.
+//
+// Origin Considerations
+//
+// Web browsers allow Javascript applications to open a WebSocket connection to
+// any host. It's up to the server to enforce an origin policy using the Origin
+// request header sent by the browser.
+//
+// The Upgrader calls the function specified in the CheckOrigin field to check
+// the origin. If the CheckOrigin function returns false, then the Upgrade
+// method fails the WebSocket handshake with HTTP status 403.
+//
+// If the CheckOrigin field is nil, then the Upgrader uses a safe default: fail
+// the handshake if the Origin request header is present and the Origin host is
+// not equal to the Host request header.
+//
+// The deprecated package-level Upgrade function does not perform origin
+// checking. The application is responsible for checking the Origin header
+// before calling the Upgrade function.
+//
+// Buffers
+//
+// Connections buffer network input and output to reduce the number
+// of system calls when reading or writing messages.
+//
+// Write buffers are also used for constructing WebSocket frames. See RFC 6455,
+// Section 5 for a discussion of message framing. A WebSocket frame header is
+// written to the network each time a write buffer is flushed to the network.
+// Decreasing the size of the write buffer can increase the amount of framing
+// overhead on the connection.
+//
+// The buffer sizes in bytes are specified by the ReadBufferSize and
+// WriteBufferSize fields in the Dialer and Upgrader. The Dialer uses a default
+// size of 4096 when a buffer size field is set to zero. The Upgrader reuses
+// buffers created by the HTTP server when a buffer size field is set to zero.
+// The HTTP server buffers have a size of 4096 at the time of this writing.
+//
+// The buffer sizes do not limit the size of a message that can be read or
+// written by a connection.
+//
+// Buffers are held for the lifetime of the connection by default. If the
+// Dialer or Upgrader WriteBufferPool field is set, then a connection holds the
+// write buffer only when writing a message.
+//
+// Applications should tune the buffer sizes to balance memory use and
+// performance. Increasing the buffer size uses more memory, but can reduce the
+// number of system calls to read or write the network. In the case of writing,
+// increasing the buffer size can reduce the number of frame headers written to
+// the network.
+//
+// Some guidelines for setting buffer parameters are:
+//
+// Limit the buffer sizes to the maximum expected message size. Buffers larger
+// than the largest message do not provide any benefit.
+//
+// Depending on the distribution of message sizes, setting the buffer size to
+// a value less than the maximum expected message size can greatly reduce memory
+// use with a small impact on performance. Here's an example: If 99% of the
+// messages are smaller than 256 bytes and the maximum message size is 512
+// bytes, then a buffer size of 256 bytes will result in 1.01 more system calls
+// than a buffer size of 512 bytes. The memory savings is 50%.
+//
+// A write buffer pool is useful when the application has a modest number
+// writes over a large number of connections. when buffers are pooled, a larger
+// buffer size has a reduced impact on total memory use and has the benefit of
+// reducing system calls and frame overhead.
+//
+// Compression EXPERIMENTAL
+//
+// Per message compression extensions (RFC 7692) are experimentally supported
+// by this package in a limited capacity. Setting the EnableCompression option
+// to true in Dialer or Upgrader will attempt to negotiate per message deflate
+// support.
+//
+// var upgrader = websocket.Upgrader{
+// EnableCompression: true,
+// }
+//
+// If compression was successfully negotiated with the connection's peer, any
+// message received in compressed form will be automatically decompressed.
+// All Read methods will return uncompressed bytes.
+//
+// Per message compression of messages written to a connection can be enabled
+// or disabled by calling the corresponding Conn method:
+//
+// conn.EnableWriteCompression(false)
+//
+// Currently this package does not support compression with "context takeover".
+// This means that messages must be compressed and decompressed in isolation,
+// without retaining sliding window or dictionary state across messages. For
+// more details refer to RFC 7692.
+//
+// Use of compression is experimental and may result in decreased performance.
+package websocket
diff --git a/vendor/github.com/fasthttp/websocket/errors.go b/vendor/github.com/fasthttp/websocket/errors.go
new file mode 100644
index 0000000..865a843
--- /dev/null
+++ b/vendor/github.com/fasthttp/websocket/errors.go
@@ -0,0 +1,8 @@
+package websocket
+
+import "errors"
+
+var (
+ ErrNilConn = errors.New("nil *Conn")
+ ErrNilNetConn = errors.New("nil net.Conn")
+)
diff --git a/vendor/github.com/fasthttp/websocket/join.go b/vendor/github.com/fasthttp/websocket/join.go
new file mode 100644
index 0000000..c64f8c8
--- /dev/null
+++ b/vendor/github.com/fasthttp/websocket/join.go
@@ -0,0 +1,42 @@
+// Copyright 2019 The Gorilla WebSocket 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 websocket
+
+import (
+ "io"
+ "strings"
+)
+
+// JoinMessages concatenates received messages to create a single io.Reader.
+// The string term is appended to each message. The returned reader does not
+// support concurrent calls to the Read method.
+func JoinMessages(c *Conn, term string) io.Reader {
+ return &joinReader{c: c, term: term}
+}
+
+type joinReader struct {
+ c *Conn
+ term string
+ r io.Reader
+}
+
+func (r *joinReader) Read(p []byte) (int, error) {
+ if r.r == nil {
+ var err error
+ _, r.r, err = r.c.NextReader()
+ if err != nil {
+ return 0, err
+ }
+ if r.term != "" {
+ r.r = io.MultiReader(r.r, strings.NewReader(r.term))
+ }
+ }
+ n, err := r.r.Read(p)
+ if err == io.EOF {
+ err = nil
+ r.r = nil
+ }
+ return n, err
+}
diff --git a/vendor/github.com/fasthttp/websocket/json.go b/vendor/github.com/fasthttp/websocket/json.go
new file mode 100644
index 0000000..dc2c1f6
--- /dev/null
+++ b/vendor/github.com/fasthttp/websocket/json.go
@@ -0,0 +1,60 @@
+// Copyright 2013 The Gorilla WebSocket 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 websocket
+
+import (
+ "encoding/json"
+ "io"
+)
+
+// WriteJSON writes the JSON encoding of v as a message.
+//
+// Deprecated: Use c.WriteJSON instead.
+func WriteJSON(c *Conn, v interface{}) error {
+ return c.WriteJSON(v)
+}
+
+// WriteJSON writes the JSON encoding of v as a message.
+//
+// See the documentation for encoding/json Marshal for details about the
+// conversion of Go values to JSON.
+func (c *Conn) WriteJSON(v interface{}) error {
+ w, err := c.NextWriter(TextMessage)
+ if err != nil {
+ return err
+ }
+ err1 := json.NewEncoder(w).Encode(v)
+ err2 := w.Close()
+ if err1 != nil {
+ return err1
+ }
+ return err2
+}
+
+// ReadJSON reads the next JSON-encoded message from the connection and stores
+// it in the value pointed to by v.
+//
+// Deprecated: Use c.ReadJSON instead.
+func ReadJSON(c *Conn, v interface{}) error {
+ return c.ReadJSON(v)
+}
+
+// ReadJSON reads the next JSON-encoded message from the connection and stores
+// it in the value pointed to by v.
+//
+// See the documentation for the encoding/json Unmarshal function for details
+// about the conversion of JSON to a Go value.
+func (c *Conn) ReadJSON(v interface{}) error {
+ _, r, err := c.NextReader()
+ if err != nil {
+ return err
+ }
+ err = json.NewDecoder(r).Decode(v)
+ if err == io.EOF {
+ // One value is expected in the message.
+ err = io.ErrUnexpectedEOF
+ }
+ return err
+}
diff --git a/vendor/github.com/fasthttp/websocket/mask.go b/vendor/github.com/fasthttp/websocket/mask.go
new file mode 100644
index 0000000..0b0223d
--- /dev/null
+++ b/vendor/github.com/fasthttp/websocket/mask.go
@@ -0,0 +1,60 @@
+// Copyright 2016 The Gorilla WebSocket Authors. All rights reserved. Use of
+// this source code is governed by a BSD-style license that can be found in the
+// LICENSE file.
+
+//go:build !appengine
+// +build !appengine
+
+package websocket
+
+import "unsafe"
+
+// #nosec G103 -- (CWE-242) Has been audited
+const wordSize = int(unsafe.Sizeof(uintptr(0)))
+
+func maskBytes(key [4]byte, pos int, b []byte) int {
+ // Mask one byte at a time for small buffers.
+ if len(b) < 2*wordSize {
+ for i := range b {
+ b[i] ^= key[pos&3]
+ pos++
+ }
+ return pos & 3
+ }
+
+ // Mask one byte at a time to word boundary.
+ // #nosec G103 -- (CWE-242) Has been audited
+ n := int(uintptr(unsafe.Pointer(&b[0]))) % wordSize
+ if n != 0 {
+ n = wordSize - n
+ for i := range b[:n] {
+ b[i] ^= key[pos&3]
+ pos++
+ }
+ b = b[n:]
+ }
+
+ // Create aligned word size key.
+ var k [wordSize]byte
+ for i := range k {
+ k[i] = key[(pos+i)&3]
+ }
+ //#nosec G103 -- (CWE-242) Has been audited
+ kw := *(*uintptr)(unsafe.Pointer(&k))
+
+ // Mask one word at a time.
+ n = (len(b) / wordSize) * wordSize
+ for i := 0; i < n; i += wordSize {
+ //#nosec G103 -- (CWE-242) Has been audited
+ *(*uintptr)(unsafe.Pointer(uintptr(unsafe.Pointer(&b[0])) + uintptr(i))) ^= kw
+ }
+
+ // Mask one byte at a time for remaining bytes.
+ b = b[n:]
+ for i := range b {
+ b[i] ^= key[pos&3]
+ pos++
+ }
+
+ return pos & 3
+}
diff --git a/vendor/github.com/fasthttp/websocket/mask_safe.go b/vendor/github.com/fasthttp/websocket/mask_safe.go
new file mode 100644
index 0000000..36250ca
--- /dev/null
+++ b/vendor/github.com/fasthttp/websocket/mask_safe.go
@@ -0,0 +1,16 @@
+// Copyright 2016 The Gorilla WebSocket Authors. All rights reserved. Use of
+// this source code is governed by a BSD-style license that can be found in the
+// LICENSE file.
+
+//go:build appengine
+// +build appengine
+
+package websocket
+
+func maskBytes(key [4]byte, pos int, b []byte) int {
+ for i := range b {
+ b[i] ^= key[pos&3]
+ pos++
+ }
+ return pos & 3
+}
diff --git a/vendor/github.com/fasthttp/websocket/prepared.go b/vendor/github.com/fasthttp/websocket/prepared.go
new file mode 100644
index 0000000..c854225
--- /dev/null
+++ b/vendor/github.com/fasthttp/websocket/prepared.go
@@ -0,0 +1,102 @@
+// Copyright 2017 The Gorilla WebSocket 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 websocket
+
+import (
+ "bytes"
+ "net"
+ "sync"
+ "time"
+)
+
+// PreparedMessage caches on the wire representations of a message payload.
+// Use PreparedMessage to efficiently send a message payload to multiple
+// connections. PreparedMessage is especially useful when compression is used
+// because the CPU and memory expensive compression operation can be executed
+// once for a given set of compression options.
+type PreparedMessage struct {
+ messageType int
+ data []byte
+ mu sync.Mutex
+ frames map[prepareKey]*preparedFrame
+}
+
+// prepareKey defines a unique set of options to cache prepared frames in PreparedMessage.
+type prepareKey struct {
+ isServer bool
+ compress bool
+ compressionLevel int
+}
+
+// preparedFrame contains data in wire representation.
+type preparedFrame struct {
+ once sync.Once
+ data []byte
+}
+
+// NewPreparedMessage returns an initialized PreparedMessage. You can then send
+// it to connection using WritePreparedMessage method. Valid wire
+// representation will be calculated lazily only once for a set of current
+// connection options.
+func NewPreparedMessage(messageType int, data []byte) (*PreparedMessage, error) {
+ pm := &PreparedMessage{
+ messageType: messageType,
+ frames: make(map[prepareKey]*preparedFrame),
+ data: data,
+ }
+
+ // Prepare a plain server frame.
+ _, frameData, err := pm.frame(prepareKey{isServer: true, compress: false})
+ if err != nil {
+ return nil, err
+ }
+
+ // To protect against caller modifying the data argument, remember the data
+ // copied to the plain server frame.
+ pm.data = frameData[len(frameData)-len(data):]
+ return pm, nil
+}
+
+func (pm *PreparedMessage) frame(key prepareKey) (int, []byte, error) {
+ pm.mu.Lock()
+ frame, ok := pm.frames[key]
+ if !ok {
+ frame = &preparedFrame{}
+ pm.frames[key] = frame
+ }
+ pm.mu.Unlock()
+
+ var err error
+ frame.once.Do(func() {
+ // Prepare a frame using a 'fake' connection.
+ // TODO: Refactor code in conn.go to allow more direct construction of
+ // the frame.
+ mu := make(chan struct{}, 1)
+ mu <- struct{}{}
+ var nc prepareConn
+ c := &Conn{
+ conn: &nc,
+ mu: mu,
+ isServer: key.isServer,
+ compressionLevel: key.compressionLevel,
+ enableWriteCompression: true,
+ writeBuf: make([]byte, defaultWriteBufferSize+maxFrameHeaderSize),
+ }
+ if key.compress {
+ c.newCompressionWriter = compressNoContextTakeover
+ }
+ err = c.WriteMessage(pm.messageType, pm.data)
+ frame.data = nc.buf.Bytes()
+ })
+ return pm.messageType, frame.data, err
+}
+
+type prepareConn struct {
+ buf bytes.Buffer
+ net.Conn
+}
+
+func (pc *prepareConn) Write(p []byte) (int, error) { return pc.buf.Write(p) }
+func (pc *prepareConn) SetWriteDeadline(t time.Time) error { return nil }
diff --git a/vendor/github.com/fasthttp/websocket/proxy.go b/vendor/github.com/fasthttp/websocket/proxy.go
new file mode 100644
index 0000000..65ef3ee
--- /dev/null
+++ b/vendor/github.com/fasthttp/websocket/proxy.go
@@ -0,0 +1,86 @@
+// Copyright 2017 The Gorilla WebSocket 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 websocket
+
+import (
+ "bufio"
+ "encoding/base64"
+ "errors"
+ "log"
+ "net"
+ "net/http"
+ "net/url"
+ "strings"
+
+ "golang.org/x/net/proxy"
+)
+
+type netDialerFunc func(network, addr string) (net.Conn, error)
+
+func (fn netDialerFunc) Dial(network, addr string) (net.Conn, error) {
+ return fn(network, addr)
+}
+
+func init() {
+ proxy.RegisterDialerType("http", func(proxyURL *url.URL, forwardDialer proxy.Dialer) (proxy.Dialer, error) {
+ return &httpProxyDialer{proxyURL: proxyURL, forwardDial: forwardDialer.Dial}, nil
+ })
+}
+
+type httpProxyDialer struct {
+ proxyURL *url.URL
+ forwardDial func(network, addr string) (net.Conn, error)
+}
+
+func (hpd *httpProxyDialer) Dial(network string, addr string) (net.Conn, error) {
+ hostPort, _ := hostPortNoPort(hpd.proxyURL)
+ conn, err := hpd.forwardDial(network, hostPort)
+ if err != nil {
+ return nil, err
+ }
+
+ connectHeader := make(http.Header)
+ if user := hpd.proxyURL.User; user != nil {
+ proxyUser := user.Username()
+ if proxyPassword, passwordSet := user.Password(); passwordSet {
+ credential := base64.StdEncoding.EncodeToString([]byte(proxyUser + ":" + proxyPassword))
+ connectHeader.Set("Proxy-Authorization", "Basic "+credential)
+ }
+ }
+
+ connectReq := &http.Request{
+ Method: http.MethodConnect,
+ URL: &url.URL{Opaque: addr},
+ Host: addr,
+ Header: connectHeader,
+ }
+
+ if err := connectReq.Write(conn); err != nil {
+ if err := conn.Close(); err != nil {
+ log.Printf("httpProxyDialer: failed to close connection: %v", err)
+ }
+ return nil, err
+ }
+
+ // Read response. It's OK to use and discard buffered reader here because
+ // the remote server does not speak until spoken to.
+ br := bufio.NewReader(conn)
+ resp, err := http.ReadResponse(br, connectReq)
+ if err != nil {
+ if err := conn.Close(); err != nil {
+ log.Printf("httpProxyDialer: failed to close connection: %v", err)
+ }
+ return nil, err
+ }
+
+ if resp.StatusCode != http.StatusOK {
+ if err := conn.Close(); err != nil {
+ log.Printf("httpProxyDialer: failed to close connection: %v", err)
+ }
+ f := strings.SplitN(resp.Status, " ", 2)
+ return nil, errors.New(f[1])
+ }
+ return conn, nil
+}
diff --git a/vendor/github.com/fasthttp/websocket/server.go b/vendor/github.com/fasthttp/websocket/server.go
new file mode 100644
index 0000000..cb75263
--- /dev/null
+++ b/vendor/github.com/fasthttp/websocket/server.go
@@ -0,0 +1,389 @@
+// Copyright 2013 The Gorilla WebSocket 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 websocket
+
+import (
+ "bufio"
+ "errors"
+ "io"
+ "log"
+ "net/http"
+ "net/url"
+ "strings"
+ "time"
+)
+
+const badHandshake = "websocket: the client is not using the websocket protocol: "
+
+// HandshakeError describes an error with the handshake from the peer.
+type HandshakeError struct {
+ message string
+}
+
+func (e HandshakeError) Error() string { return e.message }
+
+// Upgrader specifies parameters for upgrading an HTTP connection to a
+// WebSocket connection.
+//
+// It is safe to call Upgrader's methods concurrently.
+type Upgrader struct {
+ // HandshakeTimeout specifies the duration for the handshake to complete.
+ HandshakeTimeout time.Duration
+
+ // ReadBufferSize and WriteBufferSize specify I/O buffer sizes in bytes. If a buffer
+ // size is zero, then buffers allocated by the HTTP server are used. The
+ // I/O buffer sizes do not limit the size of the messages that can be sent
+ // or received.
+ ReadBufferSize, WriteBufferSize int
+
+ // WriteBufferPool is a pool of buffers for write operations. If the value
+ // is not set, then write buffers are allocated to the connection for the
+ // lifetime of the connection.
+ //
+ // A pool is most useful when the application has a modest volume of writes
+ // across a large number of connections.
+ //
+ // Applications should use a single pool for each unique value of
+ // WriteBufferSize.
+ WriteBufferPool BufferPool
+
+ // Subprotocols specifies the server's supported protocols in order of
+ // preference. If this field is not nil, then the Upgrade method negotiates a
+ // subprotocol by selecting the first match in this list with a protocol
+ // requested by the client. If there's no match, then no protocol is
+ // negotiated (the Sec-Websocket-Protocol header is not included in the
+ // handshake response).
+ Subprotocols []string
+
+ // Error specifies the function for generating HTTP error responses. If Error
+ // is nil, then http.Error is used to generate the HTTP response.
+ Error func(w http.ResponseWriter, r *http.Request, status int, reason error)
+
+ // CheckOrigin returns true if the request Origin header is acceptable. If
+ // CheckOrigin is nil, then a safe default is used: return false if the
+ // Origin request header is present and the origin host is not equal to
+ // request Host header.
+ //
+ // A CheckOrigin function should carefully validate the request origin to
+ // prevent cross-site request forgery.
+ CheckOrigin func(r *http.Request) bool
+
+ // EnableCompression specify if the server should attempt to negotiate per
+ // message compression (RFC 7692). Setting this value to true does not
+ // guarantee that compression will be supported. Currently only "no context
+ // takeover" modes are supported.
+ EnableCompression bool
+}
+
+func (u *Upgrader) returnError(w http.ResponseWriter, r *http.Request, status int, reason string) (*Conn, error) {
+ err := HandshakeError{reason}
+ if u.Error != nil {
+ u.Error(w, r, status, err)
+ } else {
+ w.Header().Set("Sec-Websocket-Version", "13")
+ http.Error(w, http.StatusText(status), status)
+ }
+ return nil, err
+}
+
+// checkSameOrigin returns true if the origin is not set or is equal to the request host.
+func checkSameOrigin(r *http.Request) bool {
+ origin := r.Header["Origin"]
+ if len(origin) == 0 {
+ return true
+ }
+ u, err := url.Parse(origin[0])
+ if err != nil {
+ return false
+ }
+ return equalASCIIFold(u.Host, r.Host)
+}
+
+func (u *Upgrader) selectSubprotocol(r *http.Request, responseHeader http.Header) string {
+ if u.Subprotocols != nil {
+ clientProtocols := Subprotocols(r)
+ for _, clientProtocol := range clientProtocols {
+ for _, serverProtocol := range u.Subprotocols {
+ if clientProtocol == serverProtocol {
+ return clientProtocol
+ }
+ }
+ }
+ } else if responseHeader != nil {
+ return responseHeader.Get("Sec-Websocket-Protocol")
+ }
+ return ""
+}
+
+// Upgrade upgrades the HTTP server connection to the WebSocket protocol.
+//
+// The responseHeader is included in the response to the client's upgrade
+// request. Use the responseHeader to specify cookies (Set-Cookie). To specify
+// subprotocols supported by the server, set Upgrader.Subprotocols directly.
+//
+// If the upgrade fails, then Upgrade replies to the client with an HTTP error
+// response.
+func (u *Upgrader) Upgrade(w http.ResponseWriter, r *http.Request, responseHeader http.Header) (*Conn, error) {
+ if !tokenListContainsValue(r.Header, "Connection", "upgrade") {
+ return u.returnError(w, r, http.StatusBadRequest, badHandshake+"'upgrade' token not found in 'Connection' header")
+ }
+
+ if !tokenListContainsValue(r.Header, "Upgrade", "websocket") {
+ return u.returnError(w, r, http.StatusBadRequest, badHandshake+"'websocket' token not found in 'Upgrade' header")
+ }
+
+ if r.Method != http.MethodGet {
+ return u.returnError(w, r, http.StatusMethodNotAllowed, badHandshake+"request method is not GET")
+ }
+
+ if !tokenListContainsValue(r.Header, "Sec-Websocket-Version", "13") {
+ return u.returnError(w, r, http.StatusBadRequest, "websocket: unsupported version: 13 not found in 'Sec-Websocket-Version' header")
+ }
+
+ if _, ok := responseHeader["Sec-Websocket-Extensions"]; ok {
+ return u.returnError(w, r, http.StatusInternalServerError, "websocket: application specific 'Sec-WebSocket-Extensions' headers are unsupported")
+ }
+
+ checkOrigin := u.CheckOrigin
+ if checkOrigin == nil {
+ checkOrigin = checkSameOrigin
+ }
+ if !checkOrigin(r) {
+ return u.returnError(w, r, http.StatusForbidden, "websocket: request origin not allowed by Upgrader.CheckOrigin")
+ }
+
+ challengeKey := r.Header.Get("Sec-Websocket-Key")
+ if !isValidChallengeKey(challengeKey) {
+ return u.returnError(w, r, http.StatusBadRequest, "websocket: not a websocket handshake: 'Sec-WebSocket-Key' header must be Base64 encoded value of 16-byte in length")
+ }
+
+ subprotocol := u.selectSubprotocol(r, responseHeader)
+
+ // Negotiate PMCE
+ var compress bool
+ if u.EnableCompression {
+ for _, ext := range parseExtensions(r.Header) {
+ if ext[""] != "permessage-deflate" {
+ continue
+ }
+ compress = true
+ break
+ }
+ }
+
+ h, ok := w.(http.Hijacker)
+ if !ok {
+ return u.returnError(w, r, http.StatusInternalServerError, "websocket: response does not implement http.Hijacker")
+ }
+ var brw *bufio.ReadWriter
+ netConn, brw, err := h.Hijack()
+ if err != nil {
+ return u.returnError(w, r, http.StatusInternalServerError, err.Error())
+ }
+
+ if brw.Reader.Buffered() > 0 {
+ if err := netConn.Close(); err != nil {
+ log.Printf("websocket: failed to close network connection: %v", err)
+ }
+ return nil, errors.New("websocket: client sent data before handshake is complete")
+ }
+
+ var br *bufio.Reader
+ if u.ReadBufferSize == 0 && bufioReaderSize(netConn, brw.Reader) > 256 {
+ // Reuse hijacked buffered reader as connection reader.
+ br = brw.Reader
+ }
+
+ buf := bufioWriterBuffer(netConn, brw.Writer)
+
+ var writeBuf []byte
+ if u.WriteBufferPool == nil && u.WriteBufferSize == 0 && len(buf) >= maxFrameHeaderSize+256 {
+ // Reuse hijacked write buffer as connection buffer.
+ writeBuf = buf
+ }
+
+ c := newConn(netConn, true, u.ReadBufferSize, u.WriteBufferSize, u.WriteBufferPool, br, writeBuf)
+ c.subprotocol = subprotocol
+
+ if compress {
+ c.newCompressionWriter = compressNoContextTakeover
+ c.newDecompressionReader = decompressNoContextTakeover
+ }
+
+ // Use larger of hijacked buffer and connection write buffer for header.
+ p := buf
+ if len(c.writeBuf) > len(p) {
+ p = c.writeBuf
+ }
+ p = p[:0]
+
+ p = append(p, "HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: "...)
+ p = append(p, computeAcceptKey(challengeKey)...)
+ p = append(p, "\r\n"...)
+ if c.subprotocol != "" {
+ p = append(p, "Sec-WebSocket-Protocol: "...)
+ p = append(p, c.subprotocol...)
+ p = append(p, "\r\n"...)
+ }
+ if compress {
+ p = append(p, "Sec-WebSocket-Extensions: permessage-deflate; server_no_context_takeover; client_no_context_takeover\r\n"...)
+ }
+ for k, vs := range responseHeader {
+ if k == "Sec-Websocket-Protocol" {
+ continue
+ }
+ for _, v := range vs {
+ p = append(p, k...)
+ p = append(p, ": "...)
+ for i := 0; i < len(v); i++ {
+ b := v[i]
+ if b <= 31 {
+ // prevent response splitting.
+ b = ' '
+ }
+ p = append(p, b)
+ }
+ p = append(p, "\r\n"...)
+ }
+ }
+ p = append(p, "\r\n"...)
+
+ // Clear deadlines set by HTTP server.
+ if err := netConn.SetDeadline(time.Time{}); err != nil {
+ if err := netConn.Close(); err != nil {
+ log.Printf("websocket: failed to close network connection: %v", err)
+ }
+ return nil, err
+ }
+
+ if u.HandshakeTimeout > 0 {
+ if err := netConn.SetWriteDeadline(time.Now().Add(u.HandshakeTimeout)); err != nil {
+ if err := netConn.Close(); err != nil {
+ log.Printf("websocket: failed to close network connection: %v", err)
+ }
+ return nil, err
+ }
+ }
+ if _, err = netConn.Write(p); err != nil {
+ if err := netConn.Close(); err != nil {
+ log.Printf("websocket: failed to close network connection: %v", err)
+ }
+ return nil, err
+ }
+ if u.HandshakeTimeout > 0 {
+ if err := netConn.SetWriteDeadline(time.Time{}); err != nil {
+ if err := netConn.Close(); err != nil {
+ log.Printf("websocket: failed to close network connection: %v", err)
+ }
+ return nil, err
+ }
+ }
+
+ return c, nil
+}
+
+// Upgrade upgrades the HTTP server connection to the WebSocket protocol.
+//
+// Deprecated: Use websocket.Upgrader instead.
+//
+// Upgrade does not perform origin checking. The application is responsible for
+// checking the Origin header before calling Upgrade. An example implementation
+// of the same origin policy check is:
+//
+// if req.Header.Get("Origin") != "http://"+req.Host {
+// http.Error(w, "Origin not allowed", http.StatusForbidden)
+// return
+// }
+//
+// If the endpoint supports subprotocols, then the application is responsible
+// for negotiating the protocol used on the connection. Use the Subprotocols()
+// function to get the subprotocols requested by the client. Use the
+// Sec-Websocket-Protocol response header to specify the subprotocol selected
+// by the application.
+//
+// The responseHeader is included in the response to the client's upgrade
+// request. Use the responseHeader to specify cookies (Set-Cookie) and the
+// negotiated subprotocol (Sec-Websocket-Protocol).
+//
+// The connection buffers IO to the underlying network connection. The
+// readBufSize and writeBufSize parameters specify the size of the buffers to
+// use. Messages can be larger than the buffers.
+//
+// If the request is not a valid WebSocket handshake, then Upgrade returns an
+// error of type HandshakeError. Applications should handle this error by
+// replying to the client with an HTTP error response.
+func Upgrade(w http.ResponseWriter, r *http.Request, responseHeader http.Header, readBufSize, writeBufSize int) (*Conn, error) {
+ u := Upgrader{ReadBufferSize: readBufSize, WriteBufferSize: writeBufSize}
+ u.Error = func(w http.ResponseWriter, r *http.Request, status int, reason error) {
+ // don't return errors to maintain backwards compatibility
+ }
+ u.CheckOrigin = func(r *http.Request) bool {
+ // allow all connections by default
+ return true
+ }
+ return u.Upgrade(w, r, responseHeader)
+}
+
+// Subprotocols returns the subprotocols requested by the client in the
+// Sec-Websocket-Protocol header.
+func Subprotocols(r *http.Request) []string {
+ h := strings.TrimSpace(r.Header.Get("Sec-Websocket-Protocol"))
+ if h == "" {
+ return nil
+ }
+ protocols := strings.Split(h, ",")
+ for i := range protocols {
+ protocols[i] = strings.TrimSpace(protocols[i])
+ }
+ return protocols
+}
+
+// IsWebSocketUpgrade returns true if the client requested upgrade to the
+// WebSocket protocol.
+func IsWebSocketUpgrade(r *http.Request) bool {
+ return tokenListContainsValue(r.Header, "Connection", "upgrade") &&
+ tokenListContainsValue(r.Header, "Upgrade", "websocket")
+}
+
+// bufioReaderSize size returns the size of a bufio.Reader.
+func bufioReaderSize(originalReader io.Reader, br *bufio.Reader) int {
+ // This code assumes that peek on a reset reader returns
+ // bufio.Reader.buf[:0].
+ // TODO: Use bufio.Reader.Size() after Go 1.10
+ br.Reset(originalReader)
+ if p, err := br.Peek(0); err == nil {
+ return cap(p)
+ }
+ return 0
+}
+
+// writeHook is an io.Writer that records the last slice passed to it vio
+// io.Writer.Write.
+type writeHook struct {
+ p []byte
+}
+
+func (wh *writeHook) Write(p []byte) (int, error) {
+ wh.p = p
+ return len(p), nil
+}
+
+// bufioWriterBuffer grabs the buffer from a bufio.Writer.
+func bufioWriterBuffer(originalWriter io.Writer, bw *bufio.Writer) []byte {
+ // This code assumes that bufio.Writer.buf[:1] is passed to the
+ // bufio.Writer's underlying writer.
+ var wh writeHook
+ bw.Reset(&wh)
+ if err := bw.WriteByte(0); err != nil {
+ panic(err)
+ }
+ if err := bw.Flush(); err != nil {
+ log.Printf("websocket: bufioWriterBuffer: Flush: %v", err)
+ }
+
+ bw.Reset(originalWriter)
+
+ return wh.p[:cap(wh.p)]
+}
diff --git a/vendor/github.com/fasthttp/websocket/server_fasthttp.go b/vendor/github.com/fasthttp/websocket/server_fasthttp.go
new file mode 100644
index 0000000..2266445
--- /dev/null
+++ b/vendor/github.com/fasthttp/websocket/server_fasthttp.go
@@ -0,0 +1,227 @@
+// Copyright 2013 The Gorilla WebSocket 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 websocket
+
+import (
+ "bytes"
+ "fmt"
+ "net"
+ "net/url"
+ "sync"
+ "time"
+
+ "github.com/savsgio/gotils/strconv"
+ "github.com/valyala/fasthttp"
+)
+
+var strPermessageDeflate = []byte("permessage-deflate")
+
+var poolWriteBuffer = sync.Pool{
+ New: func() interface{} {
+ return new(writePoolData)
+ },
+}
+
+// FastHTTPHandler receives a websocket connection after the handshake has been
+// completed. This must be provided.
+type FastHTTPHandler func(*Conn)
+
+// FastHTTPUpgrader specifies parameters for upgrading an HTTP connection to a
+// WebSocket connection.
+type FastHTTPUpgrader struct {
+ // HandshakeTimeout specifies the duration for the handshake to complete.
+ HandshakeTimeout time.Duration
+
+ // ReadBufferSize and WriteBufferSize specify I/O buffer sizes in bytes. If a buffer
+ // size is zero, then buffers allocated by the HTTP server are used. The
+ // I/O buffer sizes do not limit the size of the messages that can be sent
+ // or received.
+ ReadBufferSize, WriteBufferSize int
+
+ // WriteBufferPool is a pool of buffers for write operations. If the value
+ // is not set, then write buffers are allocated to the connection for the
+ // lifetime of the connection.
+ //
+ // A pool is most useful when the application has a modest volume of writes
+ // across a large number of connections.
+ //
+ // Applications should use a single pool for each unique value of
+ // WriteBufferSize.
+ WriteBufferPool BufferPool
+
+ // Subprotocols specifies the server's supported protocols in order of
+ // preference. If this field is not nil, then the Upgrade method negotiates a
+ // subprotocol by selecting the first match in this list with a protocol
+ // requested by the client. If there's no match, then no protocol is
+ // negotiated (the Sec-Websocket-Protocol header is not included in the
+ // handshake response).
+ Subprotocols []string
+
+ // Error specifies the function for generating HTTP error responses. If Error
+ // is nil, then http.Error is used to generate the HTTP response.
+ Error func(ctx *fasthttp.RequestCtx, status int, reason error)
+
+ // CheckOrigin returns true if the request Origin header is acceptable. If
+ // CheckOrigin is nil, then a safe default is used: return false if the
+ // Origin request header is present and the origin host is not equal to
+ // request Host header.
+ //
+ // A CheckOrigin function should carefully validate the request origin to
+ // prevent cross-site request forgery.
+ CheckOrigin func(ctx *fasthttp.RequestCtx) bool
+
+ // EnableCompression specify if the server should attempt to negotiate per
+ // message compression (RFC 7692). Setting this value to true does not
+ // guarantee that compression will be supported. Currently only "no context
+ // takeover" modes are supported.
+ EnableCompression bool
+}
+
+func (u *FastHTTPUpgrader) responseError(ctx *fasthttp.RequestCtx, status int, reason string) error {
+ err := HandshakeError{reason}
+ if u.Error != nil {
+ u.Error(ctx, status, err)
+ } else {
+ ctx.Response.Header.Set("Sec-Websocket-Version", "13")
+ ctx.Error(fasthttp.StatusMessage(status), status)
+ }
+
+ return err
+}
+
+func (u *FastHTTPUpgrader) selectSubprotocol(ctx *fasthttp.RequestCtx) []byte {
+ if u.Subprotocols != nil {
+ clientProtocols := parseDataHeader(ctx.Request.Header.Peek("Sec-Websocket-Protocol"))
+
+ for _, serverProtocol := range u.Subprotocols {
+ for _, clientProtocol := range clientProtocols {
+ if strconv.B2S(clientProtocol) == serverProtocol {
+ return clientProtocol
+ }
+ }
+ }
+ } else if ctx.Response.Header.Len() > 0 {
+ return ctx.Response.Header.Peek("Sec-Websocket-Protocol")
+ }
+
+ return nil
+}
+
+func (u *FastHTTPUpgrader) isCompressionEnable(ctx *fasthttp.RequestCtx) bool {
+ extensions := parseDataHeader(ctx.Request.Header.Peek("Sec-WebSocket-Extensions"))
+
+ // Negotiate PMCE
+ if u.EnableCompression {
+ for _, ext := range extensions {
+ if bytes.HasPrefix(ext, strPermessageDeflate) {
+ return true
+ }
+ }
+ }
+
+ return false
+}
+
+// Upgrade upgrades the HTTP server connection to the WebSocket protocol.
+//
+// The responseHeader is included in the response to the client's upgrade
+// request. Use the responseHeader to specify cookies (Set-Cookie) and the
+// application negotiated subprotocol (Sec-WebSocket-Protocol).
+//
+// If the upgrade fails, then Upgrade replies to the client with an HTTP error
+// response.
+func (u *FastHTTPUpgrader) Upgrade(ctx *fasthttp.RequestCtx, handler FastHTTPHandler) error {
+ if !ctx.IsGet() {
+ return u.responseError(ctx, fasthttp.StatusMethodNotAllowed, fmt.Sprintf("%s request method is not GET", badHandshake))
+ }
+
+ if !tokenContainsValue(strconv.B2S(ctx.Request.Header.Peek("Connection")), "Upgrade") {
+ return u.responseError(ctx, fasthttp.StatusBadRequest, fmt.Sprintf("%s 'upgrade' token not found in 'Connection' header", badHandshake))
+ }
+
+ if !tokenContainsValue(strconv.B2S(ctx.Request.Header.Peek("Upgrade")), "Websocket") {
+ return u.responseError(ctx, fasthttp.StatusBadRequest, fmt.Sprintf("%s 'websocket' token not found in 'Upgrade' header", badHandshake))
+ }
+
+ if !tokenContainsValue(strconv.B2S(ctx.Request.Header.Peek("Sec-Websocket-Version")), "13") {
+ return u.responseError(ctx, fasthttp.StatusBadRequest, "websocket: unsupported version: 13 not found in 'Sec-Websocket-Version' header")
+ }
+
+ if len(ctx.Response.Header.Peek("Sec-Websocket-Extensions")) > 0 {
+ return u.responseError(ctx, fasthttp.StatusInternalServerError, "websocket: application specific 'Sec-WebSocket-Extensions' headers are unsupported")
+ }
+
+ checkOrigin := u.CheckOrigin
+ if checkOrigin == nil {
+ checkOrigin = fastHTTPcheckSameOrigin
+ }
+ if !checkOrigin(ctx) {
+ return u.responseError(ctx, fasthttp.StatusForbidden, "websocket: request origin not allowed by FastHTTPUpgrader.CheckOrigin")
+ }
+
+ challengeKey := ctx.Request.Header.Peek("Sec-Websocket-Key")
+ if len(challengeKey) == 0 {
+ return u.responseError(ctx, fasthttp.StatusBadRequest, "websocket: not a websocket handshake: `Sec-WebSocket-Key' header is missing or blank")
+ }
+
+ subprotocol := u.selectSubprotocol(ctx)
+ compress := u.isCompressionEnable(ctx)
+
+ ctx.SetStatusCode(fasthttp.StatusSwitchingProtocols)
+ ctx.Response.Header.Set("Upgrade", "websocket")
+ ctx.Response.Header.Set("Connection", "Upgrade")
+ ctx.Response.Header.Set("Sec-WebSocket-Accept", computeAcceptKeyBytes(challengeKey))
+ if compress {
+ ctx.Response.Header.Set("Sec-WebSocket-Extensions", "permessage-deflate; server_no_context_takeover; client_no_context_takeover")
+ }
+ if subprotocol != nil {
+ ctx.Response.Header.SetBytesV("Sec-WebSocket-Protocol", subprotocol)
+ }
+
+ ctx.Hijack(func(netConn net.Conn) {
+ // var br *bufio.Reader // Always nil
+ writeBuf := poolWriteBuffer.Get().(*writePoolData)
+
+ c := newConn(netConn, true, u.ReadBufferSize, u.WriteBufferSize, u.WriteBufferPool, nil, writeBuf.buf)
+ if subprotocol != nil {
+ c.subprotocol = strconv.B2S(subprotocol)
+ }
+
+ if compress {
+ c.newCompressionWriter = compressNoContextTakeover
+ c.newDecompressionReader = decompressNoContextTakeover
+ }
+
+ // Clear deadlines set by HTTP server.
+ _ = netConn.SetDeadline(time.Time{})
+
+ handler(c)
+
+ writeBuf.buf = writeBuf.buf[0:0]
+ poolWriteBuffer.Put(writeBuf)
+ })
+
+ return nil
+}
+
+// fastHTTPcheckSameOrigin returns true if the origin is not set or is equal to the request host.
+func fastHTTPcheckSameOrigin(ctx *fasthttp.RequestCtx) bool {
+ origin := ctx.Request.Header.Peek("Origin")
+ if len(origin) == 0 {
+ return true
+ }
+ u, err := url.Parse(strconv.B2S(origin))
+ if err != nil {
+ return false
+ }
+ return equalASCIIFold(u.Host, strconv.B2S(ctx.Host()))
+}
+
+// FastHTTPIsWebSocketUpgrade returns true if the client requested upgrade to the
+// WebSocket protocol.
+func FastHTTPIsWebSocketUpgrade(ctx *fasthttp.RequestCtx) bool {
+ return tokenContainsValue(strconv.B2S(ctx.Request.Header.Peek("Connection")), "Upgrade") &&
+ tokenContainsValue(strconv.B2S(ctx.Request.Header.Peek("Upgrade")), "Websocket")
+}
diff --git a/vendor/github.com/fasthttp/websocket/tls_handshake.go b/vendor/github.com/fasthttp/websocket/tls_handshake.go
new file mode 100644
index 0000000..7f38645
--- /dev/null
+++ b/vendor/github.com/fasthttp/websocket/tls_handshake.go
@@ -0,0 +1,18 @@
+package websocket
+
+import (
+ "context"
+ "crypto/tls"
+)
+
+func doHandshake(ctx context.Context, tlsConn *tls.Conn, cfg *tls.Config) error {
+ if err := tlsConn.HandshakeContext(ctx); err != nil {
+ return err
+ }
+ if !cfg.InsecureSkipVerify {
+ if err := tlsConn.VerifyHostname(cfg.ServerName); err != nil {
+ return err
+ }
+ }
+ return nil
+}
diff --git a/vendor/github.com/fasthttp/websocket/util.go b/vendor/github.com/fasthttp/websocket/util.go
new file mode 100644
index 0000000..9e268d2
--- /dev/null
+++ b/vendor/github.com/fasthttp/websocket/util.go
@@ -0,0 +1,329 @@
+// Copyright 2013 The Gorilla WebSocket 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 websocket
+
+import (
+ "bytes"
+ "crypto/rand"
+ "crypto/sha1" //#nosec G505 -- (CWE-327) https://datatracker.ietf.org/doc/html/rfc6455#page-54
+ "encoding/base64"
+ "io"
+ "net/http"
+ "strings"
+ "unicode/utf8"
+)
+
+var keyGUID = []byte("258EAFA5-E914-47DA-95CA-C5AB0DC85B11")
+
+func computeAcceptKey(challengeKey string) string {
+ h := sha1.New() //#nosec G401 -- (CWE-326) https://datatracker.ietf.org/doc/html/rfc6455#page-54
+ h.Write([]byte(challengeKey))
+ h.Write(keyGUID)
+ return base64.StdEncoding.EncodeToString(h.Sum(nil))
+}
+
+func computeAcceptKeyBytes(challengeKey []byte) string {
+ h := sha1.New() //#nosec G401 -- (CWE-326) https://datatracker.ietf.org/doc/html/rfc6455#page-54
+ h.Write(challengeKey)
+ h.Write(keyGUID)
+ return base64.StdEncoding.EncodeToString(h.Sum(nil))
+}
+
+func generateChallengeKey() (string, error) {
+ p := make([]byte, 16)
+ if _, err := io.ReadFull(rand.Reader, p); err != nil {
+ return "", err
+ }
+ return base64.StdEncoding.EncodeToString(p), nil
+}
+
+// Token octets per RFC 2616.
+var isTokenOctet = [256]bool{
+ '!': true,
+ '#': true,
+ '$': true,
+ '%': true,
+ '&': true,
+ '\'': true,
+ '*': true,
+ '+': true,
+ '-': true,
+ '.': true,
+ '0': true,
+ '1': true,
+ '2': true,
+ '3': true,
+ '4': true,
+ '5': true,
+ '6': true,
+ '7': true,
+ '8': true,
+ '9': true,
+ 'A': true,
+ 'B': true,
+ 'C': true,
+ 'D': true,
+ 'E': true,
+ 'F': true,
+ 'G': true,
+ 'H': true,
+ 'I': true,
+ 'J': true,
+ 'K': true,
+ 'L': true,
+ 'M': true,
+ 'N': true,
+ 'O': true,
+ 'P': true,
+ 'Q': true,
+ 'R': true,
+ 'S': true,
+ 'T': true,
+ 'U': true,
+ 'W': true,
+ 'V': true,
+ 'X': true,
+ 'Y': true,
+ 'Z': true,
+ '^': true,
+ '_': true,
+ '`': true,
+ 'a': true,
+ 'b': true,
+ 'c': true,
+ 'd': true,
+ 'e': true,
+ 'f': true,
+ 'g': true,
+ 'h': true,
+ 'i': true,
+ 'j': true,
+ 'k': true,
+ 'l': true,
+ 'm': true,
+ 'n': true,
+ 'o': true,
+ 'p': true,
+ 'q': true,
+ 'r': true,
+ 's': true,
+ 't': true,
+ 'u': true,
+ 'v': true,
+ 'w': true,
+ 'x': true,
+ 'y': true,
+ 'z': true,
+ '|': true,
+ '~': true,
+}
+
+// skipSpace returns a slice of the string s with all leading RFC 2616 linear
+// whitespace removed.
+func skipSpace(s string) (rest string) {
+ i := 0
+ for ; i < len(s); i++ {
+ if b := s[i]; b != ' ' && b != '\t' {
+ break
+ }
+ }
+ return s[i:]
+}
+
+// nextToken returns the leading RFC 2616 token of s and the string following
+// the token.
+func nextToken(s string) (token, rest string) {
+ i := 0
+ for ; i < len(s); i++ {
+ if !isTokenOctet[s[i]] {
+ break
+ }
+ }
+ return s[:i], s[i:]
+}
+
+// nextTokenOrQuoted returns the leading token or quoted string per RFC 2616
+// and the string following the token or quoted string.
+func nextTokenOrQuoted(s string) (value string, rest string) {
+ if !strings.HasPrefix(s, "\"") {
+ token, rest := nextToken(s)
+ return token, rest
+ }
+ s = s[1:]
+ for i := 0; i < len(s); i++ {
+ switch s[i] {
+ case '"':
+ return s[:i], s[i+1:]
+ case '\\':
+ p := make([]byte, len(s)-1)
+ j := copy(p, s[:i])
+ escape := true
+ for i = i + 1; i < len(s); i++ {
+ b := s[i]
+ switch {
+ case escape:
+ escape = false
+ p[j] = b
+ j++
+ case b == '\\':
+ escape = true
+ case b == '"':
+ return string(p[:j]), s[i+1:]
+ default:
+ p[j] = b
+ j++
+ }
+ }
+ return "", ""
+ }
+ }
+ return "", ""
+}
+
+// equalASCIIFold returns true if s is equal to t with ASCII case folding as
+// defined in RFC 4790.
+func equalASCIIFold(s, t string) bool {
+ for s != "" && t != "" {
+ sr, size := utf8.DecodeRuneInString(s)
+ s = s[size:]
+ tr, size := utf8.DecodeRuneInString(t)
+ t = t[size:]
+ if sr == tr {
+ continue
+ }
+ if 'A' <= sr && sr <= 'Z' {
+ sr = sr + 'a' - 'A'
+ }
+ if 'A' <= tr && tr <= 'Z' {
+ tr = tr + 'a' - 'A'
+ }
+ if sr != tr {
+ return false
+ }
+ }
+ return s == t
+}
+
+// tokenListContainsValue returns true if the 1#token header with the given
+// name contains a token equal to value with ASCII case folding.
+func tokenContainsValue(s string, value string) bool {
+ for {
+ var t string
+ t, s = nextToken(skipSpace(s))
+ if t == "" {
+ return false
+ }
+ s = skipSpace(s)
+ if s != "" && s[0] != ',' {
+ return false
+ }
+ if equalASCIIFold(t, value) {
+ return true
+ }
+ if s == "" {
+ return false
+ }
+
+ s = s[1:]
+ }
+}
+
+// tokenListContainsValue returns true if the 1#token header with the given
+// name contains token.
+func tokenListContainsValue(header http.Header, name string, value string) bool {
+ for _, s := range header[name] {
+ if tokenContainsValue(s, value) {
+ return true
+ }
+ }
+ return false
+}
+
+// parseExtensions parses WebSocket extensions from a header.
+func parseExtensions(header http.Header) []map[string]string {
+ // From RFC 6455:
+ //
+ // Sec-WebSocket-Extensions = extension-list
+ // extension-list = 1#extension
+ // extension = extension-token *( ";" extension-param )
+ // extension-token = registered-token
+ // registered-token = token
+ // extension-param = token [ "=" (token | quoted-string) ]
+ // ;When using the quoted-string syntax variant, the value
+ // ;after quoted-string unescaping MUST conform to the
+ // ;'token' ABNF.
+
+ var result []map[string]string
+headers:
+ for _, s := range header["Sec-Websocket-Extensions"] {
+ for {
+ var t string
+ t, s = nextToken(skipSpace(s))
+ if t == "" {
+ continue headers
+ }
+ ext := map[string]string{"": t}
+ for {
+ s = skipSpace(s)
+ if !strings.HasPrefix(s, ";") {
+ break
+ }
+ var k string
+ k, s = nextToken(skipSpace(s[1:]))
+ if k == "" {
+ continue headers
+ }
+ s = skipSpace(s)
+ var v string
+ if strings.HasPrefix(s, "=") {
+ v, s = nextTokenOrQuoted(skipSpace(s[1:]))
+ s = skipSpace(s)
+ }
+ if s != "" && s[0] != ',' && s[0] != ';' {
+ continue headers
+ }
+ ext[k] = v
+ }
+ if s != "" && s[0] != ',' {
+ continue headers
+ }
+ result = append(result, ext)
+ if s == "" {
+ continue headers
+ }
+ s = s[1:]
+ }
+ }
+ return result
+}
+
+// isValidChallengeKey checks if the argument meets RFC6455 specification.
+func isValidChallengeKey(s string) bool {
+ // From RFC6455:
+ //
+ // A |Sec-WebSocket-Key| header field with a base64-encoded (see
+ // Section 4 of [RFC4648]) value that, when decoded, is 16 bytes in
+ // length.
+
+ if s == "" {
+ return false
+ }
+ decoded, err := base64.StdEncoding.DecodeString(s)
+ return err == nil && len(decoded) == 16
+}
+
+// parseDataHeader returns a list with values if header value is comma-separated
+func parseDataHeader(headerValue []byte) [][]byte {
+ h := bytes.TrimSpace(headerValue)
+ if bytes.Equal(h, []byte("")) {
+ return nil
+ }
+
+ values := bytes.Split(h, []byte(","))
+ for i := range values {
+ values[i] = bytes.TrimSpace(values[i])
+ }
+ return values
+}
diff --git a/vendor/github.com/fiatjaf/eventstore/.gitignore b/vendor/github.com/fiatjaf/eventstore/.gitignore
new file mode 100644
index 0000000..89f530b
--- /dev/null
+++ b/vendor/github.com/fiatjaf/eventstore/.gitignore
@@ -0,0 +1,2 @@
+cmd/eventstore/eventstore
+eventstore
diff --git a/vendor/github.com/fiatjaf/eventstore/LICENSE b/vendor/github.com/fiatjaf/eventstore/LICENSE
new file mode 100644
index 0000000..fdddb29
--- /dev/null
+++ b/vendor/github.com/fiatjaf/eventstore/LICENSE
@@ -0,0 +1,24 @@
+This is free and unencumbered software released into the public domain.
+
+Anyone is free to copy, modify, publish, use, compile, sell, or
+distribute this software, either in source code form or as a compiled
+binary, for any purpose, commercial or non-commercial, and by any
+means.
+
+In jurisdictions that recognize copyright laws, the author or authors
+of this software dedicate any and all copyright interest in the
+software to the public domain. We make this dedication for the benefit
+of the public at large and to the detriment of our heirs and
+successors. We intend this dedication to be an overt act of
+relinquishment in perpetuity of all present and future rights to this
+software under copyright law.
+
+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 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.
+
+For more information, please refer to
diff --git a/vendor/github.com/fiatjaf/eventstore/README.md b/vendor/github.com/fiatjaf/eventstore/README.md
new file mode 100644
index 0000000..842f48e
--- /dev/null
+++ b/vendor/github.com/fiatjaf/eventstore/README.md
@@ -0,0 +1,31 @@
+# eventstore
+
+A collection of reusable database connectors, wrappers and schemas that store Nostr events and expose a simple Go interface:
+
+```go
+type Store interface {
+ // Init is called at the very beginning by [Server.Start], after [Relay.Init],
+ // allowing a storage to initialize its internal resources.
+ Init() error
+
+ // Close must be called after you're done using the store, to free up resources and so on.
+ Close()
+
+ // QueryEvents is invoked upon a client's REQ as described in NIP-01.
+ // it should return a channel with the events as they're recovered from a database.
+ // the channel should be closed after the events are all delivered.
+ QueryEvents(context.Context, nostr.Filter) (chan *nostr.Event, error)
+
+ // DeleteEvent is used to handle deletion events, as per NIP-09.
+ DeleteEvent(context.Context, *nostr.Event) error
+
+ // SaveEvent is called once Relay.AcceptEvent reports true.
+ SaveEvent(context.Context, *nostr.Event) error
+}
+```
+
+[![Go Reference](https://pkg.go.dev/badge/github.com/fiatjaf/eventstore.svg)](https://pkg.go.dev/github.com/fiatjaf/eventstore) [![Run Tests](https://github.com/fiatjaf/eventstore/actions/workflows/test.yml/badge.svg)](https://github.com/fiatjaf/eventstore/actions/workflows/test.yml)
+
+## command-line tool
+
+There is an [`eventstore` command-line tool](cmd/eventstore) that can be used to query these databases directly.
diff --git a/vendor/github.com/fiatjaf/eventstore/errors.go b/vendor/github.com/fiatjaf/eventstore/errors.go
new file mode 100644
index 0000000..553ce65
--- /dev/null
+++ b/vendor/github.com/fiatjaf/eventstore/errors.go
@@ -0,0 +1,5 @@
+package eventstore
+
+import "errors"
+
+var ErrDupEvent = errors.New("duplicate: event already exists")
diff --git a/vendor/github.com/fiatjaf/eventstore/helpers.go b/vendor/github.com/fiatjaf/eventstore/helpers.go
new file mode 100644
index 0000000..98565e5
--- /dev/null
+++ b/vendor/github.com/fiatjaf/eventstore/helpers.go
@@ -0,0 +1,10 @@
+package eventstore
+
+import (
+ "github.com/nbd-wtf/go-nostr"
+)
+
+func isOlder(previous, next *nostr.Event) bool {
+ return previous.CreatedAt < next.CreatedAt ||
+ (previous.CreatedAt == next.CreatedAt && previous.ID > next.ID)
+}
diff --git a/vendor/github.com/fiatjaf/eventstore/postgresql/delete.go b/vendor/github.com/fiatjaf/eventstore/postgresql/delete.go
new file mode 100644
index 0000000..32260b6
--- /dev/null
+++ b/vendor/github.com/fiatjaf/eventstore/postgresql/delete.go
@@ -0,0 +1,12 @@
+package postgresql
+
+import (
+ "context"
+
+ "github.com/nbd-wtf/go-nostr"
+)
+
+func (b PostgresBackend) DeleteEvent(ctx context.Context, evt *nostr.Event) error {
+ _, err := b.DB.ExecContext(ctx, "DELETE FROM event WHERE id = $1", evt.ID)
+ return err
+}
diff --git a/vendor/github.com/fiatjaf/eventstore/postgresql/init.go b/vendor/github.com/fiatjaf/eventstore/postgresql/init.go
new file mode 100644
index 0000000..acc9194
--- /dev/null
+++ b/vendor/github.com/fiatjaf/eventstore/postgresql/init.go
@@ -0,0 +1,75 @@
+package postgresql
+
+import (
+ "github.com/fiatjaf/eventstore"
+ "github.com/jmoiron/sqlx"
+ "github.com/jmoiron/sqlx/reflectx"
+ _ "github.com/lib/pq"
+)
+
+const (
+ queryLimit = 100
+ queryIDsLimit = 500
+ queryAuthorsLimit = 500
+ queryKindsLimit = 10
+ queryTagsLimit = 10
+)
+
+var _ eventstore.Store = (*PostgresBackend)(nil)
+
+func (b *PostgresBackend) Init() error {
+ db, err := sqlx.Connect("postgres", b.DatabaseURL)
+ if err != nil {
+ return err
+ }
+
+ // sqlx default is 0 (unlimited), while postgresql by default accepts up to 100 connections
+ db.SetMaxOpenConns(80)
+
+ db.Mapper = reflectx.NewMapperFunc("json", sqlx.NameMapper)
+ b.DB = db
+
+ _, err = b.DB.Exec(`
+CREATE OR REPLACE FUNCTION tags_to_tagvalues(jsonb) RETURNS text[]
+ AS 'SELECT array_agg(t->>1) FROM (SELECT jsonb_array_elements($1) AS t)s WHERE length(t->>0) = 1;'
+ LANGUAGE SQL
+ IMMUTABLE
+ RETURNS NULL ON NULL INPUT;
+
+CREATE TABLE IF NOT EXISTS event (
+ id text NOT NULL,
+ pubkey text NOT NULL,
+ created_at integer NOT NULL,
+ kind integer NOT NULL,
+ tags jsonb NOT NULL,
+ content text NOT NULL,
+ sig text NOT NULL,
+
+ tagvalues text[] GENERATED ALWAYS AS (tags_to_tagvalues(tags)) STORED
+);
+
+CREATE UNIQUE INDEX IF NOT EXISTS ididx ON event USING btree (id text_pattern_ops);
+CREATE INDEX IF NOT EXISTS pubkeyprefix ON event USING btree (pubkey text_pattern_ops);
+CREATE INDEX IF NOT EXISTS timeidx ON event (created_at DESC);
+CREATE INDEX IF NOT EXISTS kindidx ON event (kind);
+CREATE INDEX IF NOT EXISTS kindtimeidx ON event(kind,created_at DESC);
+CREATE INDEX IF NOT EXISTS arbitrarytagvalues ON event USING gin (tagvalues);
+ `)
+
+ if b.QueryLimit == 0 {
+ b.QueryLimit = queryLimit
+ }
+ if b.QueryIDsLimit == 0 {
+ b.QueryIDsLimit = queryIDsLimit
+ }
+ if b.QueryAuthorsLimit == 0 {
+ b.QueryAuthorsLimit = queryAuthorsLimit
+ }
+ if b.QueryKindsLimit == 0 {
+ b.QueryKindsLimit = queryKindsLimit
+ }
+ if b.QueryTagsLimit == 0 {
+ b.QueryTagsLimit = queryTagsLimit
+ }
+ return err
+}
diff --git a/vendor/github.com/fiatjaf/eventstore/postgresql/postgresql.go b/vendor/github.com/fiatjaf/eventstore/postgresql/postgresql.go
new file mode 100644
index 0000000..1e79450
--- /dev/null
+++ b/vendor/github.com/fiatjaf/eventstore/postgresql/postgresql.go
@@ -0,0 +1,20 @@
+package postgresql
+
+import (
+ "github.com/jmoiron/sqlx"
+)
+
+type PostgresBackend struct {
+ *sqlx.DB
+ DatabaseURL string
+ QueryLimit int
+ QueryIDsLimit int
+ QueryAuthorsLimit int
+ QueryKindsLimit int
+ QueryTagsLimit int
+ KeepRecentEvents bool
+}
+
+func (b *PostgresBackend) Close() {
+ b.DB.Close()
+}
diff --git a/vendor/github.com/fiatjaf/eventstore/postgresql/query.go b/vendor/github.com/fiatjaf/eventstore/postgresql/query.go
new file mode 100644
index 0000000..fa4fe06
--- /dev/null
+++ b/vendor/github.com/fiatjaf/eventstore/postgresql/query.go
@@ -0,0 +1,178 @@
+package postgresql
+
+import (
+ "context"
+ "database/sql"
+ "errors"
+ "fmt"
+ "strings"
+
+ "github.com/jmoiron/sqlx"
+ "github.com/nbd-wtf/go-nostr"
+)
+
+func (b PostgresBackend) QueryEvents(ctx context.Context, filter nostr.Filter) (ch chan *nostr.Event, err error) {
+ query, params, err := b.queryEventsSql(filter, false)
+ if err != nil {
+ return nil, err
+ }
+
+ rows, err := b.DB.QueryContext(ctx, query, params...)
+ if err != nil && err != sql.ErrNoRows {
+ return nil, fmt.Errorf("failed to fetch events using query %q: %w", query, err)
+ }
+
+ ch = make(chan *nostr.Event)
+ go func() {
+ defer rows.Close()
+ defer close(ch)
+ for rows.Next() {
+ var evt nostr.Event
+ var timestamp int64
+ err := rows.Scan(&evt.ID, &evt.PubKey, ×tamp,
+ &evt.Kind, &evt.Tags, &evt.Content, &evt.Sig)
+ if err != nil {
+ return
+ }
+ evt.CreatedAt = nostr.Timestamp(timestamp)
+ select {
+ case ch <- &evt:
+ case <-ctx.Done():
+ return
+ }
+ }
+ }()
+
+ return ch, nil
+}
+
+func (b PostgresBackend) CountEvents(ctx context.Context, filter nostr.Filter) (int64, error) {
+ query, params, err := b.queryEventsSql(filter, true)
+ if err != nil {
+ return 0, err
+ }
+
+ var count int64
+ if err = b.DB.QueryRowContext(ctx, query, params...).Scan(&count); err != nil && err != sql.ErrNoRows {
+ return 0, fmt.Errorf("failed to fetch events using query %q: %w", query, err)
+ }
+ return count, nil
+}
+
+func makePlaceHolders(n int) string {
+ return strings.TrimRight(strings.Repeat("?,", n), ",")
+}
+
+var (
+ TooManyIDs = errors.New("too many ids")
+ TooManyAuthors = errors.New("too many authors")
+ TooManyKinds = errors.New("too many kinds")
+ TooManyTagValues = errors.New("too many tag values")
+ EmptyTagSet = errors.New("empty tag set")
+)
+
+func (b PostgresBackend) queryEventsSql(filter nostr.Filter, doCount bool) (string, []any, error) {
+ var conditions []string
+ var params []any
+
+ if len(filter.IDs) > 0 {
+ if len(filter.IDs) > b.QueryIDsLimit {
+ // too many ids, fail everything
+ return "", nil, TooManyIDs
+ }
+
+ for _, v := range filter.IDs {
+ params = append(params, v)
+ }
+ conditions = append(conditions, ` id IN (`+makePlaceHolders(len(filter.IDs))+`)`)
+ }
+
+ if len(filter.Authors) > 0 {
+ if len(filter.Authors) > b.QueryAuthorsLimit {
+ // too many authors, fail everything
+ return "", nil, TooManyAuthors
+ }
+
+ for _, v := range filter.Authors {
+ params = append(params, v)
+ }
+ conditions = append(conditions, ` pubkey IN (`+makePlaceHolders(len(filter.Authors))+`)`)
+ }
+
+ if len(filter.Kinds) > 0 {
+ if len(filter.Kinds) > b.QueryKindsLimit {
+ // too many kinds, fail everything
+ return "", nil, TooManyKinds
+ }
+
+ for _, v := range filter.Kinds {
+ params = append(params, v)
+ }
+ conditions = append(conditions, `kind IN (`+makePlaceHolders(len(filter.Kinds))+`)`)
+ }
+
+ tagQuery := make([]string, 0, 1)
+ for _, values := range filter.Tags {
+ if len(values) == 0 {
+ // any tag set to [] is wrong
+ return "", nil, EmptyTagSet
+ }
+
+ // add these tags to the query
+ tagQuery = append(tagQuery, values...)
+
+ if len(tagQuery) > b.QueryTagsLimit {
+ // too many tags, fail everything
+ return "", nil, TooManyTagValues
+ }
+ }
+
+ if len(tagQuery) > 0 {
+ for _, tagValue := range tagQuery {
+ params = append(params, tagValue)
+ }
+
+ conditions = append(conditions, `tagvalues <@ ARRAY[`+makePlaceHolders(len(tagQuery))+`]`)
+ }
+
+ if filter.Since != nil {
+ conditions = append(conditions, `created_at >= ?`)
+ params = append(params, filter.Since)
+ }
+ if filter.Until != nil {
+ conditions = append(conditions, `created_at <= ?`)
+ params = append(params, filter.Until)
+ }
+ if filter.Search != "" {
+ conditions = append(conditions, `content LIKE ?`)
+ params = append(params, `%`+strings.ReplaceAll(filter.Search, `%`, `\%`)+`%`)
+ }
+
+ if len(conditions) == 0 {
+ // fallback
+ conditions = append(conditions, `true`)
+ }
+
+ if filter.Limit < 1 || filter.Limit > b.QueryLimit {
+ params = append(params, b.QueryLimit)
+ } else {
+ params = append(params, filter.Limit)
+ }
+
+ var query string
+ if doCount {
+ query = sqlx.Rebind(sqlx.BindType("postgres"), `SELECT
+ COUNT(*)
+ FROM event WHERE `+
+ strings.Join(conditions, " AND ")+
+ " LIMIT ?")
+ } else {
+ query = sqlx.Rebind(sqlx.BindType("postgres"), `SELECT
+ id, pubkey, created_at, kind, tags, content, sig
+ FROM event WHERE `+
+ strings.Join(conditions, " AND ")+
+ " ORDER BY created_at DESC, id LIMIT ?")
+ }
+
+ return query, params, nil
+}
diff --git a/vendor/github.com/fiatjaf/eventstore/postgresql/save.go b/vendor/github.com/fiatjaf/eventstore/postgresql/save.go
new file mode 100644
index 0000000..31b45a6
--- /dev/null
+++ b/vendor/github.com/fiatjaf/eventstore/postgresql/save.go
@@ -0,0 +1,57 @@
+package postgresql
+
+import (
+ "context"
+ "encoding/json"
+
+ "github.com/fiatjaf/eventstore"
+ "github.com/nbd-wtf/go-nostr"
+)
+
+func (b *PostgresBackend) SaveEvent(ctx context.Context, evt *nostr.Event) error {
+ sql, params, _ := saveEventSql(evt)
+ res, err := b.DB.ExecContext(ctx, sql, params...)
+ if err != nil {
+ return err
+ }
+
+ nr, err := res.RowsAffected()
+ if err != nil {
+ return err
+ }
+
+ if nr == 0 {
+ return eventstore.ErrDupEvent
+ }
+
+ return nil
+}
+
+func (b *PostgresBackend) BeforeSave(ctx context.Context, evt *nostr.Event) {
+ // do nothing
+}
+
+func (b *PostgresBackend) AfterSave(evt *nostr.Event) {
+ if b.KeepRecentEvents {
+ return
+ }
+ // delete all but the 100 most recent ones for each key
+ b.DB.Exec(`DELETE FROM event WHERE pubkey = $1 AND kind = $2 AND created_at < (
+ SELECT created_at FROM event WHERE pubkey = $1
+ ORDER BY created_at DESC, id OFFSET 100 LIMIT 1
+ )`, evt.PubKey, evt.Kind)
+}
+
+func saveEventSql(evt *nostr.Event) (string, []any, error) {
+ const query = `INSERT INTO event (
+ id, pubkey, created_at, kind, tags, content, sig)
+ VALUES ($1, $2, $3, $4, $5, $6, $7)
+ ON CONFLICT (id) DO NOTHING`
+
+ var (
+ tagsj, _ = json.Marshal(evt.Tags)
+ params = []any{evt.ID, evt.PubKey, evt.CreatedAt, evt.Kind, tagsj, evt.Content, evt.Sig}
+ )
+
+ return query, params, nil
+}
diff --git a/vendor/github.com/fiatjaf/eventstore/relay_interface.go b/vendor/github.com/fiatjaf/eventstore/relay_interface.go
new file mode 100644
index 0000000..19cff17
--- /dev/null
+++ b/vendor/github.com/fiatjaf/eventstore/relay_interface.go
@@ -0,0 +1,102 @@
+package eventstore
+
+import (
+ "context"
+ "fmt"
+
+ "github.com/nbd-wtf/go-nostr"
+)
+
+type RelayWrapper struct {
+ Store
+}
+
+var _ nostr.RelayStore = (*RelayWrapper)(nil)
+
+func (w RelayWrapper) Publish(ctx context.Context, evt nostr.Event) error {
+ ctx, cancel := context.WithCancel(ctx)
+ defer cancel()
+
+ if 20000 <= evt.Kind && evt.Kind < 30000 {
+ // do not store ephemeral events
+ return nil
+ } else if evt.Kind == 0 || evt.Kind == 3 || (10000 <= evt.Kind && evt.Kind < 20000) {
+ // replaceable event, delete before storing
+ ch, err := w.Store.QueryEvents(ctx, nostr.Filter{Authors: []string{evt.PubKey}, Kinds: []int{evt.Kind}})
+ if err != nil {
+ return fmt.Errorf("failed to query before replacing: %w", err)
+ }
+ isNewer := true
+ for previous := range ch {
+ if previous == nil {
+ continue
+ }
+ if isOlder(previous, &evt) {
+ if err := w.Store.DeleteEvent(ctx, previous); err != nil {
+ return fmt.Errorf("failed to delete event for replacing: %w", err)
+ }
+ } else {
+ // already, newer event is stored.
+ isNewer = false
+ break
+ }
+ }
+ if !isNewer {
+ return nil
+ }
+ } else if 30000 <= evt.Kind && evt.Kind < 40000 {
+ // parameterized replaceable event, delete before storing
+ d := evt.Tags.GetFirst([]string{"d", ""})
+ if d == nil {
+ return fmt.Errorf("failed to add event missing d tag for parameterized replacing")
+ }
+ ch, err := w.Store.QueryEvents(ctx, nostr.Filter{Authors: []string{evt.PubKey}, Kinds: []int{evt.Kind}, Tags: nostr.TagMap{"d": []string{d.Value()}}})
+ if err != nil {
+ return fmt.Errorf("failed to query before parameterized replacing: %w", err)
+ }
+ isNewer := true
+ for previous := range ch {
+ if previous == nil {
+ continue
+ }
+
+ if !isOlder(previous, &evt) {
+ if err := w.Store.DeleteEvent(ctx, previous); err != nil {
+ return fmt.Errorf("failed to delete event for parameterized replacing: %w", err)
+ }
+ } else {
+ // already, newer event is stored.
+ isNewer = false
+ break
+ }
+ }
+ if !isNewer {
+ return nil
+ }
+ }
+
+ if err := w.SaveEvent(ctx, &evt); err != nil && err != ErrDupEvent {
+ return fmt.Errorf("failed to save: %w", err)
+ }
+
+ return nil
+}
+
+func (w RelayWrapper) QuerySync(ctx context.Context, filter nostr.Filter) ([]*nostr.Event, error) {
+ ch, err := w.Store.QueryEvents(ctx, filter)
+ if err != nil {
+ return nil, fmt.Errorf("failed to query: %w", err)
+ }
+
+ n := filter.Limit
+ if n == 0 {
+ n = 500
+ }
+
+ results := make([]*nostr.Event, 0, n)
+ for evt := range ch {
+ results = append(results, evt)
+ }
+
+ return results, nil
+}
diff --git a/vendor/github.com/fiatjaf/eventstore/store.go b/vendor/github.com/fiatjaf/eventstore/store.go
new file mode 100644
index 0000000..7083900
--- /dev/null
+++ b/vendor/github.com/fiatjaf/eventstore/store.go
@@ -0,0 +1,30 @@
+package eventstore
+
+import (
+ "context"
+
+ "github.com/nbd-wtf/go-nostr"
+)
+
+// Store is a persistence layer for nostr events handled by a relay.
+type Store interface {
+ // Init is called at the very beginning by [Server.Start], after [Relay.Init],
+ // allowing a storage to initialize its internal resources.
+ Init() error
+
+ // Close must be called after you're done using the store, to free up resources and so on.
+ Close()
+
+ // QueryEvents is invoked upon a client's REQ as described in NIP-01.
+ // it should return a channel with the events as they're recovered from a database.
+ // the channel should be closed after the events are all delivered.
+ QueryEvents(context.Context, nostr.Filter) (chan *nostr.Event, error)
+ // DeleteEvent is used to handle deletion events, as per NIP-09.
+ DeleteEvent(context.Context, *nostr.Event) error
+ // SaveEvent is called once Relay.AcceptEvent reports true.
+ SaveEvent(context.Context, *nostr.Event) error
+}
+
+type Counter interface {
+ CountEvents(context.Context, nostr.Filter) (int64, error)
+}
diff --git a/vendor/github.com/fiatjaf/eventstore/utils.go b/vendor/github.com/fiatjaf/eventstore/utils.go
new file mode 100644
index 0000000..3718cc4
--- /dev/null
+++ b/vendor/github.com/fiatjaf/eventstore/utils.go
@@ -0,0 +1,19 @@
+package eventstore
+
+import (
+ "encoding/hex"
+ "strconv"
+ "strings"
+)
+
+func GetAddrTagElements(tagValue string) (kind uint16, pkb []byte, d string) {
+ spl := strings.Split(tagValue, ":")
+ if len(spl) == 3 {
+ if pkb, _ := hex.DecodeString(spl[1]); len(pkb) == 32 {
+ if kind, err := strconv.ParseUint(spl[0], 10, 16); err == nil {
+ return uint16(kind), pkb, spl[2]
+ }
+ }
+ }
+ return 0, nil, ""
+}
diff --git a/vendor/github.com/fiatjaf/khatru/.gitignore b/vendor/github.com/fiatjaf/khatru/.gitignore
new file mode 100644
index 0000000..f85f391
--- /dev/null
+++ b/vendor/github.com/fiatjaf/khatru/.gitignore
@@ -0,0 +1,2 @@
+*.env
+rss-bridge
\ No newline at end of file
diff --git a/vendor/github.com/fiatjaf/khatru/LICENSE b/vendor/github.com/fiatjaf/khatru/LICENSE
new file mode 100644
index 0000000..fdddb29
--- /dev/null
+++ b/vendor/github.com/fiatjaf/khatru/LICENSE
@@ -0,0 +1,24 @@
+This is free and unencumbered software released into the public domain.
+
+Anyone is free to copy, modify, publish, use, compile, sell, or
+distribute this software, either in source code form or as a compiled
+binary, for any purpose, commercial or non-commercial, and by any
+means.
+
+In jurisdictions that recognize copyright laws, the author or authors
+of this software dedicate any and all copyright interest in the
+software to the public domain. We make this dedication for the benefit
+of the public at large and to the detriment of our heirs and
+successors. We intend this dedication to be an overt act of
+relinquishment in perpetuity of all present and future rights to this
+software under copyright law.
+
+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 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.
+
+For more information, please refer to
diff --git a/vendor/github.com/fiatjaf/khatru/README.md b/vendor/github.com/fiatjaf/khatru/README.md
new file mode 100644
index 0000000..e0d552f
--- /dev/null
+++ b/vendor/github.com/fiatjaf/khatru/README.md
@@ -0,0 +1,140 @@
+# khatru, a relay framework [![docs badge](https://img.shields.io/badge/docs-reference-blue)](https://pkg.go.dev/github.com/fiatjaf/khatru#Relay)
+
+[![Run Tests](https://github.com/fiatjaf/khatru/actions/workflows/test.yml/badge.svg)](https://github.com/fiatjaf/khatru/actions/workflows/test.yml)
+[![Go Reference](https://pkg.go.dev/badge/github.com/fiatjaf/khatru.svg)](https://pkg.go.dev/github.com/fiatjaf/khatru)
+[![Go Report Card](https://goreportcard.com/badge/github.com/fiatjaf/khatru)](https://goreportcard.com/report/github.com/fiatjaf/khatru)
+
+Khatru makes it easy to write very very custom relays:
+
+ - custom event or filter acceptance policies
+ - custom `AUTH` handlers
+ - custom storage and pluggable databases
+ - custom webpages and other HTTP handlers
+
+Here's a sample:
+
+```go
+package main
+
+import (
+ "context"
+ "fmt"
+ "log"
+ "net/http"
+
+ "github.com/fiatjaf/khatru"
+ "github.com/nbd-wtf/go-nostr"
+)
+
+func main() {
+ // create the relay instance
+ relay := khatru.NewRelay()
+
+ // set up some basic properties (will be returned on the NIP-11 endpoint)
+ relay.Info.Name = "my relay"
+ relay.Info.PubKey = "79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798"
+ relay.Info.Description = "this is my custom relay"
+ relay.Info.Icon = "https://external-content.duckduckgo.com/iu/?u=https%3A%2F%2Fliquipedia.net%2Fcommons%2Fimages%2F3%2F35%2FSCProbe.jpg&f=1&nofb=1&ipt=0cbbfef25bce41da63d910e86c3c343e6c3b9d63194ca9755351bb7c2efa3359&ipo=images"
+
+ // you must bring your own storage scheme -- if you want to have any
+ store := make(map[string]*nostr.Event, 120)
+
+ // set up the basic relay functions
+ relay.StoreEvent = append(relay.StoreEvent,
+ func(ctx context.Context, event *nostr.Event) error {
+ store[event.ID] = event
+ return nil
+ },
+ )
+ relay.QueryEvents = append(relay.QueryEvents,
+ func(ctx context.Context, filter nostr.Filter) (chan *nostr.Event, error) {
+ ch := make(chan *nostr.Event)
+ go func() {
+ for _, evt := range store {
+ if filter.Matches(evt) {
+ ch <- evt
+ }
+ }
+ close(ch)
+ }()
+ return ch, nil
+ },
+ )
+ relay.DeleteEvent = append(relay.DeleteEvent,
+ func(ctx context.Context, event *nostr.Event) error {
+ delete(store, event.ID)
+ return nil
+ },
+ )
+
+ // there are many other configurable things you can set
+ relay.RejectEvent = append(relay.RejectEvent,
+ // built-in policies
+ policies.ValidateKind,
+
+ // define your own policies
+ policies.PreventLargeTags(80),
+ func(ctx context.Context, event *nostr.Event) (reject bool, msg string) {
+ if event.PubKey == "fa984bd7dbb282f07e16e7ae87b26a2a7b9b90b7246a44771f0cf5ae58018f52" {
+ return true, "we don't allow this person to write here"
+ }
+ return false, "" // anyone else can
+ },
+ )
+
+ // you can request auth by rejecting an event or a request with the prefix "auth-required: "
+ relay.RejectFilter = append(relay.RejectFilter,
+ // built-in policies
+ policies.NoComplexFilters,
+
+ // define your own policies
+ func(ctx context.Context, filter nostr.Filter) (reject bool, msg string) {
+ if pubkey := khatru.GetAuthed(ctx); pubkey != "" {
+ log.Printf("request from %s\n", pubkey)
+ return false, ""
+ }
+ return true, "auth-required: only authenticated users can read from this relay"
+ // (this will cause an AUTH message to be sent and then a CLOSED message such that clients can
+ // authenticate and then request again)
+ },
+ )
+ // check the docs for more goodies!
+
+ mux := relay.Router()
+ // set up other http handlers
+ mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
+ w.Header().Set("content-type", "text/html")
+ fmt.Fprintf(w, `welcome to my relay!`)
+ })
+
+ // start the server
+ fmt.Println("running on :3334")
+ http.ListenAndServe(":3334", relay)
+}
+```
+
+### But I don't want to write my own database!
+
+Fear no more. Using the https://github.com/fiatjaf/eventstore module you get a bunch of compatible databases out of the box and you can just plug them into your relay. For example, [sqlite](https://pkg.go.dev/github.com/fiatjaf/eventstore/sqlite3):
+
+```go
+ db := sqlite3.SQLite3Backend{DatabaseURL: "/tmp/khatru-sqlite-tmp"}
+ if err := db.Init(); err != nil {
+ panic(err)
+ }
+
+ relay.StoreEvent = append(relay.StoreEvent, db.SaveEvent)
+ relay.QueryEvents = append(relay.QueryEvents, db.QueryEvents)
+ relay.CountEvents = append(relay.CountEvents, db.CountEvents)
+ relay.DeleteEvent = append(relay.DeleteEvent, db.DeleteEvent)
+```
+
+### But I don't want to write a bunch of custom policies!
+
+Fear no more. We have a bunch of common policies written in the `github.com/fiatjaf/khatru/policies` package and also a handpicked selection of base sane defaults, which you can apply with:
+
+```go
+ policies.ApplySaneDefaults(relay)
+```
+
+Contributions to this are very much welcomed.
diff --git a/vendor/github.com/fiatjaf/khatru/adding.go b/vendor/github.com/fiatjaf/khatru/adding.go
new file mode 100644
index 0000000..aa232fd
--- /dev/null
+++ b/vendor/github.com/fiatjaf/khatru/adding.go
@@ -0,0 +1,107 @@
+package khatru
+
+import (
+ "context"
+ "errors"
+ "fmt"
+
+ "github.com/fiatjaf/eventstore"
+ "github.com/nbd-wtf/go-nostr"
+)
+
+// AddEvent sends an event through then normal add pipeline, as if it was received from a websocket.
+func (rl *Relay) AddEvent(ctx context.Context, evt *nostr.Event) (skipBroadcast bool, writeError error) {
+ if evt == nil {
+ return false, errors.New("error: event is nil")
+ }
+
+ for _, reject := range rl.RejectEvent {
+ if reject, msg := reject(ctx, evt); reject {
+ if msg == "" {
+ return false, errors.New("blocked: no reason")
+ } else {
+ return false, errors.New(nostr.NormalizeOKMessage(msg, "blocked"))
+ }
+ }
+ }
+
+ if 20000 <= evt.Kind && evt.Kind < 30000 {
+ // do not store ephemeral events
+ for _, oee := range rl.OnEphemeralEvent {
+ oee(ctx, evt)
+ }
+ } else {
+ // will store
+
+ // but first check if we already have it
+ filter := nostr.Filter{IDs: []string{evt.ID}}
+ for _, query := range rl.QueryEvents {
+ ch, err := query(ctx, filter)
+ if err != nil {
+ continue
+ }
+ for range ch {
+ // if we run this it means we already have this event, so we just return a success and exit
+ return true, nil
+ }
+ }
+
+ // if it's replaceable we first delete old versions
+ if evt.Kind == 0 || evt.Kind == 3 || (10000 <= evt.Kind && evt.Kind < 20000) {
+ // replaceable event, delete before storing
+ filter := nostr.Filter{Authors: []string{evt.PubKey}, Kinds: []int{evt.Kind}}
+ for _, query := range rl.QueryEvents {
+ ch, err := query(ctx, filter)
+ if err != nil {
+ continue
+ }
+ for previous := range ch {
+ if isOlder(previous, evt) {
+ for _, del := range rl.DeleteEvent {
+ del(ctx, previous)
+ }
+ }
+ }
+ }
+ } else if 30000 <= evt.Kind && evt.Kind < 40000 {
+ // parameterized replaceable event, delete before storing
+ d := evt.Tags.GetFirst([]string{"d", ""})
+ if d == nil {
+ return false, fmt.Errorf("invalid: missing 'd' tag on parameterized replaceable event")
+ }
+
+ filter := nostr.Filter{Authors: []string{evt.PubKey}, Kinds: []int{evt.Kind}, Tags: nostr.TagMap{"d": []string{(*d)[1]}}}
+ for _, query := range rl.QueryEvents {
+ ch, err := query(ctx, filter)
+ if err != nil {
+ continue
+ }
+ for previous := range ch {
+ if isOlder(previous, evt) {
+ for _, del := range rl.DeleteEvent {
+ del(ctx, previous)
+ }
+ }
+ }
+ }
+ }
+
+ // store
+ for _, store := range rl.StoreEvent {
+ if saveErr := store(ctx, evt); saveErr != nil {
+ switch saveErr {
+ case eventstore.ErrDupEvent:
+ return true, nil
+ default:
+ return false, fmt.Errorf(nostr.NormalizeOKMessage(saveErr.Error(), "error"))
+ }
+ }
+ }
+
+ for _, ons := range rl.OnEventSaved {
+ ons(ctx, evt)
+ }
+ }
+
+ return false, nil
+}
diff --git a/vendor/github.com/fiatjaf/khatru/broadcasting.go b/vendor/github.com/fiatjaf/khatru/broadcasting.go
new file mode 100644
index 0000000..f35268c
--- /dev/null
+++ b/vendor/github.com/fiatjaf/khatru/broadcasting.go
@@ -0,0 +1,11 @@
+package khatru
+
+import (
+ "github.com/nbd-wtf/go-nostr"
+)
+
+// BroadcastEvent emits an event to all listeners whose filters' match, skipping all filters and actions
+// it also doesn't attempt to store the event or trigger any reactions or callbacks
+func (rl *Relay) BroadcastEvent(evt *nostr.Event) {
+ rl.notifyListeners(evt)
+}
diff --git a/vendor/github.com/fiatjaf/khatru/deleting.go b/vendor/github.com/fiatjaf/khatru/deleting.go
new file mode 100644
index 0000000..9257f49
--- /dev/null
+++ b/vendor/github.com/fiatjaf/khatru/deleting.go
@@ -0,0 +1,81 @@
+package khatru
+
+import (
+ "context"
+ "fmt"
+ "strconv"
+ "strings"
+
+ "github.com/nbd-wtf/go-nostr"
+)
+
+func (rl *Relay) handleDeleteRequest(ctx context.Context, evt *nostr.Event) error {
+ // event deletion -- nip09
+ for _, tag := range evt.Tags {
+ if len(tag) >= 2 {
+ var f nostr.Filter
+
+ switch tag[0] {
+ case "e":
+ f = nostr.Filter{IDs: []string{tag[1]}}
+ case "a":
+ spl := strings.Split(tag[1], ":")
+ if len(spl) != 3 {
+ continue
+ }
+ kind, err := strconv.Atoi(spl[0])
+ if err != nil {
+ continue
+ }
+ author := spl[1]
+ identifier := spl[2]
+ f = nostr.Filter{
+ Kinds: []int{kind},
+ Authors: []string{author},
+ Tags: nostr.TagMap{"d": []string{identifier}},
+ Until: &evt.CreatedAt,
+ }
+ default:
+ continue
+ }
+
+ for _, query := range rl.QueryEvents {
+ ch, err := query(ctx, f)
+ if err != nil {
+ continue
+ }
+ target := <-ch
+ if target == nil {
+ continue
+ }
+ // got the event, now check if the user can delete it
+ acceptDeletion := target.PubKey == evt.PubKey
+ var msg string
+ if !acceptDeletion {
+ msg = "you are not the author of this event"
+ }
+ // but if we have a function to overwrite this outcome, use that instead
+ for _, odo := range rl.OverwriteDeletionOutcome {
+ acceptDeletion, msg = odo(ctx, target, evt)
+ }
+
+ if acceptDeletion {
+ // delete it
+ for _, del := range rl.DeleteEvent {
+ if err := del(ctx, target); err != nil {
+ return err
+ }
+ }
+ } else {
+ // fail and stop here
+ return fmt.Errorf("blocked: %s", msg)
+ }
+
+ // don't try to query this same event again
+ break
+ }
+ }
+ }
+
+ return nil
+}
diff --git a/vendor/github.com/fiatjaf/khatru/get-started.go b/vendor/github.com/fiatjaf/khatru/get-started.go
new file mode 100644
index 0000000..fcc5503
--- /dev/null
+++ b/vendor/github.com/fiatjaf/khatru/get-started.go
@@ -0,0 +1,60 @@
+package khatru
+
+import (
+ "context"
+ "net"
+ "net/http"
+ "strconv"
+ "time"
+
+ "github.com/fasthttp/websocket"
+ "github.com/rs/cors"
+)
+
+func (rl *Relay) Router() *http.ServeMux {
+ return rl.serveMux
+}
+
+// Start creates an http server and starts listening on given host and port.
+func (rl *Relay) Start(host string, port int, started ...chan bool) error {
+ addr := net.JoinHostPort(host, strconv.Itoa(port))
+ ln, err := net.Listen("tcp", addr)
+ if err != nil {
+ return err
+ }
+
+ rl.Addr = ln.Addr().String()
+ rl.httpServer = &http.Server{
+ Handler: cors.Default().Handler(rl),
+ Addr: addr,
+ WriteTimeout: 2 * time.Second,
+ ReadTimeout: 2 * time.Second,
+ IdleTimeout: 30 * time.Second,
+ }
+
+ // notify caller that we're starting
+ for _, started := range started {
+ close(started)
+ }
+
+ if err := rl.httpServer.Serve(ln); err == http.ErrServerClosed {
+ return nil
+ } else if err != nil {
+ return err
+ } else {
+ return nil
+ }
+}
+
+// Shutdown sends a websocket close control message to all connected clients.
+func (rl *Relay) Shutdown(ctx context.Context) {
+ rl.httpServer.Shutdown(ctx)
+ rl.clientsMutex.Lock()
+ defer rl.clientsMutex.Unlock()
+ for ws := range rl.clients {
+ ws.conn.WriteControl(websocket.CloseMessage, nil, time.Now().Add(time.Second))
+ ws.conn.Close()
+ }
+ clear(rl.clients)
+ rl.listeners = rl.listeners[:0]
+}
diff --git a/vendor/github.com/fiatjaf/khatru/handlers.go b/vendor/github.com/fiatjaf/khatru/handlers.go
new file mode 100644
index 0000000..1ffd500
--- /dev/null
+++ b/vendor/github.com/fiatjaf/khatru/handlers.go
@@ -0,0 +1,298 @@
+package khatru
+
+import (
+ "context"
+ "crypto/rand"
+ "crypto/sha256"
+ "encoding/hex"
+ "errors"
+ "net/http"
+ "strings"
+ "sync"
+ "time"
+
+ "github.com/fasthttp/websocket"
+ "github.com/nbd-wtf/go-nostr"
+ "github.com/nbd-wtf/go-nostr/nip42"
+ "github.com/rs/cors"
+)
+
+// ServeHTTP implements http.Handler interface.
+func (rl *Relay) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+ if rl.ServiceURL == "" {
+ rl.ServiceURL = getServiceBaseURL(r)
+ }
+
+ if r.Header.Get("Upgrade") == "websocket" {
+ rl.HandleWebsocket(w, r)
+ } else if r.Header.Get("Accept") == "application/nostr+json" {
+ cors.AllowAll().Handler(http.HandlerFunc(rl.HandleNIP11)).ServeHTTP(w, r)
+ } else if r.Header.Get("Content-Type") == "application/nostr+json+rpc" {
+ cors.AllowAll().Handler(http.HandlerFunc(rl.HandleNIP86)).ServeHTTP(w, r)
+ } else {
+ rl.serveMux.ServeHTTP(w, r)
+ }
+}
+
+func (rl *Relay) HandleWebsocket(w http.ResponseWriter, r *http.Request) {
+ for _, reject := range rl.RejectConnection {
+ if reject(r) {
+ w.WriteHeader(429) // Too many requests
+ return
+ }
+ }
+
+ conn, err := rl.upgrader.Upgrade(w, r, nil)
+ if err != nil {
+ rl.Log.Printf("failed to upgrade websocket: %v\n", err)
+ return
+ }
+
+ ticker := time.NewTicker(rl.PingPeriod)
+
+ // NIP-42 challenge
+ challenge := make([]byte, 8)
+ rand.Read(challenge)
+
+ ws := &WebSocket{
+ conn: conn,
+ Request: r,
+ Challenge: hex.EncodeToString(challenge),
+ }
+
+ rl.clientsMutex.Lock()
+ rl.clients[ws] = make([]listenerSpec, 0, 2)
+ rl.clientsMutex.Unlock()
+
+ ctx, cancel := context.WithCancel(
+ context.WithValue(
+ context.Background(),
+ wsKey, ws,
+ ),
+ )
+
+ kill := func() {
+ for _, ondisconnect := range rl.OnDisconnect {
+ ondisconnect(ctx)
+ }
+
+ ticker.Stop()
+ cancel()
+ conn.Close()
+
+ rl.removeClientAndListeners(ws)
+ }
+
+ go func() {
+ defer kill()
+
+ conn.SetReadLimit(rl.MaxMessageSize)
+ conn.SetReadDeadline(time.Now().Add(rl.PongWait))
+ conn.SetPongHandler(func(string) error {
+ conn.SetReadDeadline(time.Now().Add(rl.PongWait))
+ return nil
+ })
+
+ for _, onconnect := range rl.OnConnect {
+ onconnect(ctx)
+ }
+
+ for {
+ typ, message, err := conn.ReadMessage()
+ if err != nil {
+ if websocket.IsUnexpectedCloseError(
+ err,
+ websocket.CloseNormalClosure, // 1000
+ websocket.CloseGoingAway, // 1001
+ websocket.CloseNoStatusReceived, // 1005
+ websocket.CloseAbnormalClosure, // 1006
+ 4537, // some client seems to send many of these
+ ) {
+ rl.Log.Printf("unexpected close error from %s: %v\n", r.Header.Get("X-Forwarded-For"), err)
+ }
+ return
+ }
+
+ if typ == websocket.PingMessage {
+ ws.WriteMessage(websocket.PongMessage, nil)
+ continue
+ }
+
+ go func(message []byte) {
+ envelope := nostr.ParseMessage(message)
+ if envelope == nil {
+ // stop silently
+ return
+ }
+
+ switch env := envelope.(type) {
+ case *nostr.EventEnvelope:
+ // check id
+ hash := sha256.Sum256(env.Event.Serialize())
+ id := hex.EncodeToString(hash[:])
+ if id != env.Event.ID {
+ ws.WriteJSON(nostr.OKEnvelope{EventID: env.Event.ID, OK: false, Reason: "invalid: id is computed incorrectly"})
+ return
+ }
+
+ // check signature
+ if ok, err := env.Event.CheckSignature(); err != nil {
+ ws.WriteJSON(nostr.OKEnvelope{EventID: env.Event.ID, OK: false, Reason: "error: failed to verify signature"})
+ return
+ } else if !ok {
+ ws.WriteJSON(nostr.OKEnvelope{EventID: env.Event.ID, OK: false, Reason: "invalid: signature is invalid"})
+ return
+ }
+
+ // check NIP-70 protected
+ for _, v := range env.Event.Tags {
+ if len(v) == 1 && v[0] == "-" {
+ msg := "must be published by event author"
+ authed := GetAuthed(ctx)
+ if authed == "" {
+ RequestAuth(ctx)
+ ws.WriteJSON(nostr.OKEnvelope{
+ EventID: env.Event.ID,
+ OK: false,
+ Reason: "auth-required: " + msg,
+ })
+ return
+ }
+ if authed != env.Event.PubKey {
+ ws.WriteJSON(nostr.OKEnvelope{
+ EventID: env.Event.ID,
+ OK: false,
+ Reason: "blocked: " + msg,
+ })
+ return
+ }
+ }
+ }
+
+ srl := rl
+ if rl.getSubRelayFromEvent != nil {
+ srl = rl.getSubRelayFromEvent(&env.Event)
+ }
+
+ var ok bool
+ var writeErr error
+ var skipBroadcast bool
+
+ if env.Event.Kind == 5 {
+ // this always returns "blocked: " whenever it returns an error
+ writeErr = srl.handleDeleteRequest(ctx, &env.Event)
+ } else {
+ // this will also always return a prefixed reason
+ skipBroadcast, writeErr = srl.AddEvent(ctx, &env.Event)
+ }
+
+ var reason string
+ if writeErr == nil {
+ ok = true
+ for _, ovw := range srl.OverwriteResponseEvent {
+ ovw(ctx, &env.Event)
+ }
+ if !skipBroadcast {
+ srl.notifyListeners(&env.Event)
+ }
+ } else {
+ reason = writeErr.Error()
+ if strings.HasPrefix(reason, "auth-required:") {
+ RequestAuth(ctx)
+ }
+ }
+ ws.WriteJSON(nostr.OKEnvelope{EventID: env.Event.ID, OK: ok, Reason: reason})
+ case *nostr.CountEnvelope:
+ if rl.CountEvents == nil {
+ ws.WriteJSON(nostr.ClosedEnvelope{SubscriptionID: env.SubscriptionID, Reason: "unsupported: this relay does not support NIP-45"})
+ return
+ }
+
+ var total int64
+ for _, filter := range env.Filters {
+ srl := rl
+ if rl.getSubRelayFromFilter != nil {
+ srl = rl.getSubRelayFromFilter(filter)
+ }
+ total += srl.handleCountRequest(ctx, ws, filter)
+ }
+ ws.WriteJSON(nostr.CountEnvelope{SubscriptionID: env.SubscriptionID, Count: &total})
+ case *nostr.ReqEnvelope:
+ eose := sync.WaitGroup{}
+ eose.Add(len(env.Filters))
+
+ // a context just for the "stored events" request handler
+ reqCtx, cancelReqCtx := context.WithCancelCause(ctx)
+
+ // expose subscription id in the context
+ reqCtx = context.WithValue(reqCtx, subscriptionIdKey, env.SubscriptionID)
+
+ // handle each filter separately -- dispatching events as they're loaded from databases
+ for _, filter := range env.Filters {
+ srl := rl
+ if rl.getSubRelayFromFilter != nil {
+ srl = rl.getSubRelayFromFilter(filter)
+ }
+ err := srl.handleRequest(reqCtx, env.SubscriptionID, &eose, ws, filter)
+ if err != nil {
+ // fail everything if any filter is rejected
+ reason := err.Error()
+ if strings.HasPrefix(reason, "auth-required:") {
+ RequestAuth(ctx)
+ }
+ ws.WriteJSON(nostr.ClosedEnvelope{SubscriptionID: env.SubscriptionID, Reason: reason})
+ cancelReqCtx(errors.New("filter rejected"))
+ return
+ } else {
+ rl.addListener(ws, env.SubscriptionID, srl, filter, cancelReqCtx)
+ }
+ }
+
+ go func() {
+ // when all events have been loaded from databases and dispatched
+ // we can cancel the context and fire the EOSE message
+ eose.Wait()
+ cancelReqCtx(nil)
+ ws.WriteJSON(nostr.EOSEEnvelope(env.SubscriptionID))
+ }()
+ case *nostr.CloseEnvelope:
+ id := string(*env)
+ rl.removeListenerId(ws, id)
+ case *nostr.AuthEnvelope:
+ wsBaseUrl := strings.Replace(rl.ServiceURL, "http", "ws", 1)
+ if pubkey, ok := nip42.ValidateAuthEvent(&env.Event, ws.Challenge, wsBaseUrl); ok {
+ ws.AuthedPublicKey = pubkey
+ ws.authLock.Lock()
+ if ws.Authed != nil {
+ close(ws.Authed)
+ ws.Authed = nil
+ }
+ ws.authLock.Unlock()
+ ws.WriteJSON(nostr.OKEnvelope{EventID: env.Event.ID, OK: true})
+ } else {
+ ws.WriteJSON(nostr.OKEnvelope{EventID: env.Event.ID, OK: false, Reason: "error: failed to authenticate"})
+ }
+ }
+ }(message)
+ }
+ }()
+
+ go func() {
+ defer kill()
+
+ for {
+ select {
+ case <-ctx.Done():
+ return
+ case <-ticker.C:
+ err := ws.WriteMessage(websocket.PingMessage, nil)
+ if err != nil {
+ if !strings.HasSuffix(err.Error(), "use of closed network connection") {
+ rl.Log.Printf("error writing ping: %v; closing websocket\n", err)
+ }
+ return
+ }
+ }
+ }
+ }()
+}
diff --git a/vendor/github.com/fiatjaf/khatru/helpers.go b/vendor/github.com/fiatjaf/khatru/helpers.go
new file mode 100644
index 0000000..05c0fea
--- /dev/null
+++ b/vendor/github.com/fiatjaf/khatru/helpers.go
@@ -0,0 +1,77 @@
+package khatru
+
+import (
+ "net"
+ "net/http"
+ "strconv"
+ "strings"
+
+ "github.com/nbd-wtf/go-nostr"
+)
+
+func isOlder(previous, next *nostr.Event) bool {
+ return previous.CreatedAt < next.CreatedAt ||
+ (previous.CreatedAt == next.CreatedAt && previous.ID > next.ID)
+}
+
+func getServiceBaseURL(r *http.Request) string {
+ host := r.Header.Get("X-Forwarded-Host")
+ if host == "" {
+ host = r.Host
+ }
+ proto := r.Header.Get("X-Forwarded-Proto")
+ if proto == "" {
+ if host == "localhost" {
+ proto = "http"
+ } else if strings.Index(host, ":") != -1 {
+ // has a port number
+ proto = "http"
+ } else if _, err := strconv.Atoi(strings.ReplaceAll(host, ".", "")); err == nil {
+ // it's a naked IP
+ proto = "http"
+ } else {
+ proto = "https"
+ }
+ }
+ return proto + "://" + host
+}
+
+var privateMasks = func() []net.IPNet {
+ privateCIDRs := []string{
+ "127.0.0.0/8",
+ "10.0.0.0/8",
+ "172.16.0.0/12",
+ "192.168.0.0/16",
+ "fc00::/7",
+ }
+ masks := make([]net.IPNet, len(privateCIDRs))
+ for i, cidr := range privateCIDRs {
+ _, netw, err := net.ParseCIDR(cidr)
+ if err != nil {
+ return nil
+ }
+ masks[i] = *netw
+ }
+ return masks
+}()
+
+func isPrivate(ip net.IP) bool {
+ for _, mask := range privateMasks {
+ if mask.Contains(ip) {
+ return true
+ }
+ }
+ return false
+}
+
+func GetIPFromRequest(r *http.Request) string {
+ if xffh := r.Header.Get("X-Forwarded-For"); xffh != "" {
+ for _, v := range strings.Split(xffh, ",") {
+ if ip := net.ParseIP(strings.TrimSpace(v)); ip != nil && ip.IsGlobalUnicast() && !isPrivate(ip) {
+ return ip.String()
+ }
+ }
+ }
+ ip, _, _ := net.SplitHostPort(r.RemoteAddr)
+ return ip
+}
diff --git a/vendor/github.com/fiatjaf/khatru/listener.go b/vendor/github.com/fiatjaf/khatru/listener.go
new file mode 100644
index 0000000..88d158a
--- /dev/null
+++ b/vendor/github.com/fiatjaf/khatru/listener.go
@@ -0,0 +1,146 @@
+package khatru
+
+import (
+ "context"
+ "errors"
+ "slices"
+
+ "github.com/nbd-wtf/go-nostr"
+)
+
+var ErrSubscriptionClosedByClient = errors.New("subscription closed by client")
+
+type listenerSpec struct {
+ id string // kept here so we can easily match against it removeListenerId
+ cancel context.CancelCauseFunc
+ index int
+ subrelay *Relay // this is important when we're dealing with routing, otherwise it will be always the same
+}
+
+type listener struct {
+ id string // duplicated here so we can easily send it on notifyListeners
+ filter nostr.Filter
+ ws *WebSocket
+}
+
+func (rl *Relay) GetListeningFilters() []nostr.Filter {
+ respfilters := make([]nostr.Filter, len(rl.listeners))
+ for i, l := range rl.listeners {
+ respfilters[i] = l.filter
+ }
+ return respfilters
+}
+
+// addListener may be called multiple times for each id and ws -- in which case each filter will
+// be added as an independent listener
+func (rl *Relay) addListener(
+ ws *WebSocket,
+ id string,
+ subrelay *Relay,
+ filter nostr.Filter,
+ cancel context.CancelCauseFunc,
+) {
+ rl.clientsMutex.Lock()
+ defer rl.clientsMutex.Unlock()
+
+ if specs, ok := rl.clients[ws]; ok /* this will always be true unless client has disconnected very rapidly */ {
+ idx := len(subrelay.listeners)
+ rl.clients[ws] = append(specs, listenerSpec{
+ id: id,
+ cancel: cancel,
+ subrelay: subrelay,
+ index: idx,
+ })
+ subrelay.listeners = append(subrelay.listeners, listener{
+ ws: ws,
+ id: id,
+ filter: filter,
+ })
+ }
+}
+
+// remove a specific subscription id from listeners for a given ws client
+// and cancel its specific context
+func (rl *Relay) removeListenerId(ws *WebSocket, id string) {
+ rl.clientsMutex.Lock()
+ defer rl.clientsMutex.Unlock()
+
+ if specs, ok := rl.clients[ws]; ok {
+ // swap delete specs that match this id
+ for s := len(specs) - 1; s >= 0; s-- {
+ spec := specs[s]
+ if spec.id == id {
+ spec.cancel(ErrSubscriptionClosedByClient)
+ specs[s] = specs[len(specs)-1]
+ specs = specs[0 : len(specs)-1]
+ rl.clients[ws] = specs
+
+ // swap delete listeners one at a time, as they may be each in a different subrelay
+ srl := spec.subrelay // == rl in normal cases, but different when this came from a route
+
+ if spec.index != len(srl.listeners)-1 {
+ movedFromIndex := len(srl.listeners) - 1
+ moved := srl.listeners[movedFromIndex] // this wasn't removed, but will be moved
+ srl.listeners[spec.index] = moved
+
+ // now we must update the the listener we just moved
+ // so its .index reflects its new position on srl.listeners
+ movedSpecs := rl.clients[moved.ws]
+ idx := slices.IndexFunc(movedSpecs, func(ls listenerSpec) bool {
+ return ls.index == movedFromIndex && ls.subrelay == srl
+ })
+ movedSpecs[idx].index = spec.index
+ rl.clients[moved.ws] = movedSpecs
+ }
+ srl.listeners = srl.listeners[0 : len(srl.listeners)-1] // finally reduce the slice length
+ }
+ }
+ }
+}
+
+func (rl *Relay) removeClientAndListeners(ws *WebSocket) {
+ rl.clientsMutex.Lock()
+ defer rl.clientsMutex.Unlock()
+ if specs, ok := rl.clients[ws]; ok {
+ // swap delete listeners and delete client (all specs will be deleted)
+ for s, spec := range specs {
+ // no need to cancel contexts since they inherit from the main connection context
+ // just delete the listeners (swap-delete)
+ srl := spec.subrelay
+
+ if spec.index != len(srl.listeners)-1 {
+ movedFromIndex := len(srl.listeners) - 1
+ moved := srl.listeners[movedFromIndex] // this wasn't removed, but will be moved
+ srl.listeners[spec.index] = moved
+
+ // temporarily update the spec of the listener being removed to have index == -1
+ // (since it was removed) so it doesn't match in the search below
+ rl.clients[ws][s].index = -1
+
+ // now we must update the the listener we just moved
+ // so its .index reflects its new position on srl.listeners
+ movedSpecs := rl.clients[moved.ws]
+ idx := slices.IndexFunc(movedSpecs, func(ls listenerSpec) bool {
+ return ls.index == movedFromIndex && ls.subrelay == srl
+ })
+ movedSpecs[idx].index = spec.index
+ rl.clients[moved.ws] = movedSpecs
+ }
+ srl.listeners = srl.listeners[0 : len(srl.listeners)-1] // finally reduce the slice length
+ }
+ }
+ delete(rl.clients, ws)
+}
+
+func (rl *Relay) notifyListeners(event *nostr.Event) {
+ for _, listener := range rl.listeners {
+ if listener.filter.Matches(event) {
+ for _, pb := range rl.PreventBroadcast {
+ if pb(listener.ws, event) {
+ return
+ }
+ }
+ listener.ws.WriteJSON(nostr.EventEnvelope{SubscriptionID: &listener.id, Event: *event})
+ }
+ }
+}
diff --git a/vendor/github.com/fiatjaf/khatru/nip11.go b/vendor/github.com/fiatjaf/khatru/nip11.go
new file mode 100644
index 0000000..87bc5c4
--- /dev/null
+++ b/vendor/github.com/fiatjaf/khatru/nip11.go
@@ -0,0 +1,25 @@
+package khatru
+
+import (
+ "encoding/json"
+ "net/http"
+)
+
+func (rl *Relay) HandleNIP11(w http.ResponseWriter, r *http.Request) {
+ w.Header().Set("Content-Type", "application/nostr+json")
+
+ info := *rl.Info
+
+ if len(rl.DeleteEvent) > 0 {
+ info.SupportedNIPs = append(info.SupportedNIPs, 9)
+ }
+ if len(rl.CountEvents) > 0 {
+ info.SupportedNIPs = append(info.SupportedNIPs, 45)
+ }
+
+ for _, ovw := range rl.OverwriteRelayInformation {
+ info = ovw(r.Context(), r, info)
+ }
+
+ json.NewEncoder(w).Encode(info)
+}
diff --git a/vendor/github.com/fiatjaf/khatru/nip86.go b/vendor/github.com/fiatjaf/khatru/nip86.go
new file mode 100644
index 0000000..35523bb
--- /dev/null
+++ b/vendor/github.com/fiatjaf/khatru/nip86.go
@@ -0,0 +1,270 @@
+package khatru
+
+import (
+ "context"
+ "crypto/sha256"
+ "encoding/base64"
+ "encoding/hex"
+ "encoding/json"
+ "fmt"
+ "io"
+ "net"
+ "net/http"
+ "reflect"
+ "strings"
+
+ "github.com/nbd-wtf/go-nostr"
+ "github.com/nbd-wtf/go-nostr/nip86"
+)
+
+type RelayManagementAPI struct {
+ RejectAPICall []func(ctx context.Context, mp nip86.MethodParams) (reject bool, msg string)
+
+ BanPubKey func(ctx context.Context, pubkey string, reason string) error
+ ListBannedPubKeys func(ctx context.Context) ([]nip86.PubKeyReason, error)
+ AllowPubKey func(ctx context.Context, pubkey string, reason string) error
+ ListAllowedPubKeys func(ctx context.Context) ([]nip86.PubKeyReason, error)
+ ListEventsNeedingModeration func(ctx context.Context) ([]nip86.IDReason, error)
+ AllowEvent func(ctx context.Context, id string, reason string) error
+ BanEvent func(ctx context.Context, id string, reason string) error
+ ListBannedEvents func(ctx context.Context) ([]nip86.IDReason, error)
+ ChangeRelayName func(ctx context.Context, name string) error
+ ChangeRelayDescription func(ctx context.Context, desc string) error
+ ChangeRelayIcon func(ctx context.Context, icon string) error
+ AllowKind func(ctx context.Context, kind int) error
+ DisallowKind func(ctx context.Context, kind int) error
+ ListAllowedKinds func(ctx context.Context) ([]int, error)
+ BlockIP func(ctx context.Context, ip net.IP, reason string) error
+ UnblockIP func(ctx context.Context, ip net.IP, reason string) error
+ ListBlockedIPs func(ctx context.Context) ([]nip86.IPReason, error)
+}
+
+func (rl *Relay) HandleNIP86(w http.ResponseWriter, r *http.Request) {
+ w.Header().Set("Content-Type", "application/nostr+json+rpc")
+
+ var (
+ resp nip86.Response
+ ctx = r.Context()
+ req nip86.Request
+ mp nip86.MethodParams
+ evt nostr.Event
+ payloadHash [32]byte
+ )
+
+ payload, err := io.ReadAll(r.Body)
+ if err != nil {
+ resp.Error = "empty request"
+ goto respond
+ }
+ payloadHash = sha256.Sum256(payload)
+
+ {
+ auth := r.Header.Get("Authorization")
+ spl := strings.Split(auth, "Nostr ")
+ if len(spl) != 2 {
+ resp.Error = "missing auth"
+ goto respond
+ }
+ if evtj, err := base64.StdEncoding.DecodeString(spl[1]); err != nil {
+ resp.Error = "invalid base64 auth"
+ goto respond
+ } else if err := json.Unmarshal(evtj, &evt); err != nil {
+ resp.Error = "invalid auth event json"
+ goto respond
+ } else if ok, _ := evt.CheckSignature(); !ok {
+ resp.Error = "invalid auth event"
+ goto respond
+ } else if uTag := evt.Tags.GetFirst([]string{"u", ""}); uTag == nil || getServiceBaseURL(r) != (*uTag)[1] {
+ resp.Error = "invalid 'u' tag"
+ goto respond
+ } else if pht := evt.Tags.GetFirst([]string{"payload", hex.EncodeToString(payloadHash[:])}); pht == nil {
+ resp.Error = "invalid auth event payload hash"
+ goto respond
+ } else if evt.CreatedAt < nostr.Now()-30 {
+ resp.Error = "auth event is too old"
+ goto respond
+ }
+ }
+
+ if err := json.Unmarshal(payload, &req); err != nil {
+ resp.Error = "invalid json body"
+ goto respond
+ }
+
+ mp, err = nip86.DecodeRequest(req)
+ if err != nil {
+ resp.Error = fmt.Sprintf("invalid params: %s", err)
+ goto respond
+ }
+
+ ctx = context.WithValue(ctx, nip86HeaderAuthKey, evt.PubKey)
+ for _, rac := range rl.ManagementAPI.RejectAPICall {
+ if reject, msg := rac(ctx, mp); reject {
+ resp.Error = msg
+ goto respond
+ }
+ }
+
+ if _, ok := mp.(nip86.SupportedMethods); ok {
+ mat := reflect.TypeOf(rl.ManagementAPI)
+ mav := reflect.ValueOf(rl.ManagementAPI)
+
+ methods := make([]string, 0, mat.NumField())
+ for i := 0; i < mat.NumField(); i++ {
+ field := mat.Field(i)
+
+ // danger: this assumes the struct fields are appropriately named
+ methodName := strings.ToLower(field.Name)
+
+ // assign this only if the function was defined
+ if mav.Field(i).Interface() != nil {
+ methods[i] = methodName
+ }
+ }
+ resp.Result = methods
+ } else {
+ switch thing := mp.(type) {
+ case nip86.BanPubKey:
+ if rl.ManagementAPI.BanPubKey == nil {
+ resp.Error = fmt.Sprintf("method %s not supported", thing.MethodName())
+ } else if err := rl.ManagementAPI.BanPubKey(ctx, thing.PubKey, thing.Reason); err != nil {
+ resp.Error = err.Error()
+ } else {
+ resp.Result = true
+ }
+ case nip86.ListBannedPubKeys:
+ if rl.ManagementAPI.ListBannedPubKeys == nil {
+ resp.Error = fmt.Sprintf("method %s not supported", thing.MethodName())
+ } else if result, err := rl.ManagementAPI.ListBannedPubKeys(ctx); err != nil {
+ resp.Error = err.Error()
+ } else {
+ resp.Result = result
+ }
+ case nip86.AllowPubKey:
+ if rl.ManagementAPI.AllowPubKey == nil {
+ resp.Error = fmt.Sprintf("method %s not supported", thing.MethodName())
+ } else if err := rl.ManagementAPI.AllowPubKey(ctx, thing.PubKey, thing.Reason); err != nil {
+ resp.Error = err.Error()
+ } else {
+ resp.Result = true
+ }
+ case nip86.ListAllowedPubKeys:
+ if rl.ManagementAPI.ListAllowedPubKeys == nil {
+ resp.Error = fmt.Sprintf("method %s not supported", thing.MethodName())
+ } else if result, err := rl.ManagementAPI.ListAllowedPubKeys(ctx); err != nil {
+ resp.Error = err.Error()
+ } else {
+ resp.Result = result
+ }
+ case nip86.BanEvent:
+ if rl.ManagementAPI.BanEvent == nil {
+ resp.Error = fmt.Sprintf("method %s not supported", thing.MethodName())
+ } else if err := rl.ManagementAPI.BanEvent(ctx, thing.ID, thing.Reason); err != nil {
+ resp.Error = err.Error()
+ } else {
+ resp.Result = true
+ }
+ case nip86.AllowEvent:
+ if rl.ManagementAPI.AllowEvent == nil {
+ resp.Error = fmt.Sprintf("method %s not supported", thing.MethodName())
+ } else if err := rl.ManagementAPI.AllowEvent(ctx, thing.ID, thing.Reason); err != nil {
+ resp.Error = err.Error()
+ } else {
+ resp.Result = true
+ }
+ case nip86.ListEventsNeedingModeration:
+ if rl.ManagementAPI.ListEventsNeedingModeration == nil {
+ resp.Error = fmt.Sprintf("method %s not supported", thing.MethodName())
+ } else if result, err := rl.ManagementAPI.ListEventsNeedingModeration(ctx); err != nil {
+ resp.Error = err.Error()
+ } else {
+ resp.Result = result
+ }
+ case nip86.ListBannedEvents:
+ if rl.ManagementAPI.ListBannedEvents == nil {
+ resp.Error = fmt.Sprintf("method %s not supported", thing.MethodName())
+ } else if result, err := rl.ManagementAPI.ListEventsNeedingModeration(ctx); err != nil {
+ resp.Error = err.Error()
+ } else {
+ resp.Result = result
+ }
+ case nip86.ChangeRelayName:
+ if rl.ManagementAPI.ChangeRelayName == nil {
+ resp.Error = fmt.Sprintf("method %s not supported", thing.MethodName())
+ } else if err := rl.ManagementAPI.ChangeRelayName(ctx, thing.Name); err != nil {
+ resp.Error = err.Error()
+ } else {
+ resp.Result = true
+ }
+ case nip86.ChangeRelayDescription:
+ if rl.ManagementAPI.ChangeRelayDescription == nil {
+ resp.Error = fmt.Sprintf("method %s not supported", thing.MethodName())
+ } else if err := rl.ManagementAPI.ChangeRelayDescription(ctx, thing.Description); err != nil {
+ resp.Error = err.Error()
+ } else {
+ resp.Result = true
+ }
+ case nip86.ChangeRelayIcon:
+ if rl.ManagementAPI.ChangeRelayIcon == nil {
+ resp.Error = fmt.Sprintf("method %s not supported", thing.MethodName())
+ } else if err := rl.ManagementAPI.ChangeRelayIcon(ctx, thing.IconURL); err != nil {
+ resp.Error = err.Error()
+ } else {
+ resp.Result = true
+ }
+ case nip86.AllowKind:
+ if rl.ManagementAPI.AllowKind == nil {
+ resp.Error = fmt.Sprintf("method %s not supported", thing.MethodName())
+ } else if err := rl.ManagementAPI.AllowKind(ctx, thing.Kind); err != nil {
+ resp.Error = err.Error()
+ } else {
+ resp.Result = true
+ }
+ case nip86.DisallowKind:
+ if rl.ManagementAPI.DisallowKind == nil {
+ resp.Error = fmt.Sprintf("method %s not supported", thing.MethodName())
+ } else if err := rl.ManagementAPI.DisallowKind(ctx, thing.Kind); err != nil {
+ resp.Error = err.Error()
+ } else {
+ resp.Result = true
+ }
+ case nip86.ListAllowedKinds:
+ if rl.ManagementAPI.ListAllowedKinds == nil {
+ resp.Error = fmt.Sprintf("method %s not supported", thing.MethodName())
+ } else if result, err := rl.ManagementAPI.ListAllowedKinds(ctx); err != nil {
+ resp.Error = err.Error()
+ } else {
+ resp.Result = result
+ }
+ case nip86.BlockIP:
+ if rl.ManagementAPI.BlockIP == nil {
+ resp.Error = fmt.Sprintf("method %s not supported", thing.MethodName())
+ } else if err := rl.ManagementAPI.BlockIP(ctx, thing.IP, thing.Reason); err != nil {
+ resp.Error = err.Error()
+ } else {
+ resp.Result = true
+ }
+ case nip86.UnblockIP:
+ if rl.ManagementAPI.UnblockIP == nil {
+ resp.Error = fmt.Sprintf("method %s not supported", thing.MethodName())
+ } else if err := rl.ManagementAPI.UnblockIP(ctx, thing.IP, thing.Reason); err != nil {
+ resp.Error = err.Error()
+ } else {
+ resp.Result = true
+ }
+ case nip86.ListBlockedIPs:
+ if rl.ManagementAPI.ListBlockedIPs == nil {
+ resp.Error = fmt.Sprintf("method %s not supported", thing.MethodName())
+ } else if result, err := rl.ManagementAPI.ListBlockedIPs(ctx); err != nil {
+ resp.Error = err.Error()
+ } else {
+ resp.Result = result
+ }
+ default:
+ resp.Error = fmt.Sprintf("method '%s' not known", mp.MethodName())
+ }
+ }
+
+respond:
+ json.NewEncoder(w).Encode(resp)
+}
diff --git a/vendor/github.com/fiatjaf/khatru/policies/events.go b/vendor/github.com/fiatjaf/khatru/policies/events.go
new file mode 100644
index 0000000..aa2019b
--- /dev/null
+++ b/vendor/github.com/fiatjaf/khatru/policies/events.go
@@ -0,0 +1,105 @@
+package policies
+
+import (
+ "context"
+ "fmt"
+ "slices"
+ "strings"
+ "time"
+
+ "github.com/nbd-wtf/go-nostr"
+)
+
+// PreventTooManyIndexableTags returns a function that can be used as a RejectFilter that will reject
+// events with more indexable (single-character) tags than the specified number.
+//
+// If ignoreKinds is given this restriction will not apply to these kinds (useful for allowing a bigger).
+// If onlyKinds is given then all other kinds will be ignored.
+func PreventTooManyIndexableTags(max int, ignoreKinds []int, onlyKinds []int) func(context.Context, *nostr.Event) (bool, string) {
+ slices.Sort(ignoreKinds)
+ slices.Sort(onlyKinds)
+
+ ignore := func(kind int) bool { return false }
+ if len(ignoreKinds) > 0 {
+ ignore = func(kind int) bool {
+ _, isIgnored := slices.BinarySearch(ignoreKinds, kind)
+ return isIgnored
+ }
+ }
+ if len(onlyKinds) > 0 {
+ ignore = func(kind int) bool {
+ _, isApplicable := slices.BinarySearch(onlyKinds, kind)
+ return !isApplicable
+ }
+ }
+
+ return func(ctx context.Context, event *nostr.Event) (reject bool, msg string) {
+ if ignore(event.Kind) {
+ return false, ""
+ }
+
+ ntags := 0
+ for _, tag := range event.Tags {
+ if len(tag) > 0 && len(tag[0]) == 1 {
+ ntags++
+ }
+ }
+ if ntags > max {
+ return true, "too many indexable tags"
+ }
+ return false, ""
+ }
+}
+
+// PreventLargeTags rejects events that have indexable tag values greater than maxTagValueLen.
+func PreventLargeTags(maxTagValueLen int) func(context.Context, *nostr.Event) (bool, string) {
+ return func(ctx context.Context, event *nostr.Event) (reject bool, msg string) {
+ for _, tag := range event.Tags {
+ if len(tag) > 1 && len(tag[0]) == 1 {
+ if len(tag[1]) > maxTagValueLen {
+ return true, "event contains too large tags"
+ }
+ }
+ }
+ return false, ""
+ }
+}
+
+// RestrictToSpecifiedKinds returns a function that can be used as a RejectFilter that will reject
+// any events with kinds different than the specified ones.
+func RestrictToSpecifiedKinds(kinds ...uint16) func(context.Context, *nostr.Event) (bool, string) {
+ // sort the kinds in increasing order
+ slices.Sort(kinds)
+
+ return func(ctx context.Context, event *nostr.Event) (reject bool, msg string) {
+ if _, allowed := slices.BinarySearch(kinds, uint16(event.Kind)); allowed {
+ return false, ""
+ }
+
+ return true, fmt.Sprintf("received event kind %d not allowed", event.Kind)
+ }
+}
+
+func PreventTimestampsInThePast(threshold time.Duration) func(context.Context, *nostr.Event) (bool, string) {
+ thresholdSeconds := nostr.Timestamp(threshold.Seconds())
+ return func(ctx context.Context, event *nostr.Event) (reject bool, msg string) {
+ if nostr.Now()-event.CreatedAt > thresholdSeconds {
+ return true, "event too old"
+ }
+ return false, ""
+ }
+}
+
+func PreventTimestampsInTheFuture(threshold time.Duration) func(context.Context, *nostr.Event) (bool, string) {
+ thresholdSeconds := nostr.Timestamp(threshold.Seconds())
+ return func(ctx context.Context, event *nostr.Event) (reject bool, msg string) {
+ if event.CreatedAt-nostr.Now() > thresholdSeconds {
+ return true, "event too much in the future"
+ }
+ return false, ""
+ }
+}
+
+func RejectEventsWithBase64Media(ctx context.Context, evt *nostr.Event) (bool, string) {
+ return strings.Contains(evt.Content, "data:image/") || strings.Contains(evt.Content, "data:video/"), "event with base64 media"
+}
diff --git a/vendor/github.com/fiatjaf/khatru/policies/filters.go b/vendor/github.com/fiatjaf/khatru/policies/filters.go
new file mode 100644
index 0000000..6c56fba
--- /dev/null
+++ b/vendor/github.com/fiatjaf/khatru/policies/filters.go
@@ -0,0 +1,84 @@
+package policies
+
+import (
+ "context"
+ "slices"
+
+ "github.com/nbd-wtf/go-nostr"
+)
+
+// NoComplexFilters disallows filters with more than 2 tags.
+func NoComplexFilters(ctx context.Context, filter nostr.Filter) (reject bool, msg string) {
+ items := len(filter.Tags) + len(filter.Kinds)
+
+ if items > 4 && len(filter.Tags) > 2 {
+ return true, "too many things to filter for"
+ }
+
+ return false, ""
+}
+
+// NoEmptyFilters disallows filters that don't have at least a tag, a kind, an author or an id.
+func NoEmptyFilters(ctx context.Context, filter nostr.Filter) (reject bool, msg string) {
+ c := len(filter.Kinds) + len(filter.IDs) + len(filter.Authors)
+ for _, tagItems := range filter.Tags {
+ c += len(tagItems)
+ }
+ if c == 0 {
+ return true, "can't handle empty filters"
+ }
+ return false, ""
+}
+
+// AntiSyncBots tries to prevent people from syncing kind:1s from this relay to else by always
+// requiring an author parameter at least.
+func AntiSyncBots(ctx context.Context, filter nostr.Filter) (reject bool, msg string) {
+ return (len(filter.Kinds) == 0 || slices.Contains(filter.Kinds, 1)) &&
+ len(filter.Authors) == 0, "an author must be specified to get their kind:1 notes"
+}
+
+func NoSearchQueries(ctx context.Context, filter nostr.Filter) (reject bool, msg string) {
+ if filter.Search != "" {
+ return true, "search is not supported"
+ }
+ return false, ""
+}
+
+func RemoveSearchQueries(ctx context.Context, filter *nostr.Filter) {
+ if filter.Search != "" {
+ filter.Search = ""
+ filter.LimitZero = true // signals that this query should be just skipped
+ }
+}
+
+func RemoveAllButKinds(kinds ...uint16) func(context.Context, *nostr.Filter) {
+ return func(ctx context.Context, filter *nostr.Filter) {
+ if n := len(filter.Kinds); n > 0 {
+ newKinds := make([]int, 0, n)
+ for i := 0; i < n; i++ {
+ if k := filter.Kinds[i]; slices.Contains(kinds, uint16(k)) {
+ newKinds = append(newKinds, k)
+ }
+ }
+ filter.Kinds = newKinds
+ if len(filter.Kinds) == 0 {
+ filter.LimitZero = true // signals that this query should be just skipped
+ }
+ }
+ }
+}
+
+func RemoveAllButTags(tagNames ...string) func(context.Context, *nostr.Filter) {
+ return func(ctx context.Context, filter *nostr.Filter) {
+ if n := len(filter.Tags); n > 0 {
+ for tagName := range filter.Tags {
+ if !slices.Contains(tagNames, tagName) {
+ delete(filter.Tags, tagName)
+ }
+ }
+ if len(filter.Tags) == 0 {
+ filter.LimitZero = true // signals that this query should be just skipped
+ }
+ }
+ }
+}
diff --git a/vendor/github.com/fiatjaf/khatru/policies/helpers.go b/vendor/github.com/fiatjaf/khatru/policies/helpers.go
new file mode 100644
index 0000000..b3bfe70
--- /dev/null
+++ b/vendor/github.com/fiatjaf/khatru/policies/helpers.go
@@ -0,0 +1,43 @@
+package policies
+
+import (
+ "sync/atomic"
+ "time"
+
+ "github.com/puzpuzpuz/xsync/v3"
+)
+
+func startRateLimitSystem[K comparable](
+ tokensPerInterval int,
+ interval time.Duration,
+ maxTokens int,
+) func(key K) (ratelimited bool) {
+ negativeBuckets := xsync.NewMapOf[K, *atomic.Int32]()
+ maxTokensInt32 := int32(maxTokens)
+
+ go func() {
+ for {
+ time.Sleep(interval)
+ negativeBuckets.Range(func(key K, bucket *atomic.Int32) bool {
+ newv := bucket.Add(int32(-tokensPerInterval))
+ if newv <= 0 {
+ negativeBuckets.Delete(key)
+ }
+ return true
+ })
+ }
+ }()
+
+ return func(key K) bool {
+ nb, _ := negativeBuckets.LoadOrStore(key, &atomic.Int32{})
+
+ if nb.Load() < maxTokensInt32 {
+ nb.Add(1)
+ // rate limit not reached yet
+ return false
+ }
+
+ // rate limit reached
+ return true
+ }
+}
diff --git a/vendor/github.com/fiatjaf/khatru/policies/kind_validation.go b/vendor/github.com/fiatjaf/khatru/policies/kind_validation.go
new file mode 100644
index 0000000..e3506ce
--- /dev/null
+++ b/vendor/github.com/fiatjaf/khatru/policies/kind_validation.go
@@ -0,0 +1,29 @@
+package policies
+
+import (
+ "context"
+ "encoding/json"
+
+ "github.com/nbd-wtf/go-nostr"
+)
+
+func ValidateKind(ctx context.Context, evt *nostr.Event) (bool, string) {
+ switch evt.Kind {
+ case 0:
+ var m struct {
+ Name string `json:"name"`
+ }
+ json.Unmarshal([]byte(evt.Content), &m)
+ if m.Name == "" {
+ return true, "missing json name in kind 0"
+ }
+ case 1:
+ return false, ""
+ case 2:
+ return true, "this kind has been deprecated"
+ }
+
+ // TODO: all other kinds
+
+ return false, ""
+}
diff --git a/vendor/github.com/fiatjaf/khatru/policies/nip04.go b/vendor/github.com/fiatjaf/khatru/policies/nip04.go
new file mode 100644
index 0000000..087746d
--- /dev/null
+++ b/vendor/github.com/fiatjaf/khatru/policies/nip04.go
@@ -0,0 +1,39 @@
+package policies
+
+import (
+ "context"
+
+ "slices"
+
+ "github.com/fiatjaf/khatru"
+ "github.com/nbd-wtf/go-nostr"
+)
+
+// RejectKind04Snoopers prevents reading NIP-04 messages from people not involved in the conversation.
+func RejectKind04Snoopers(ctx context.Context, filter nostr.Filter) (bool, string) {
+ // prevent kind-4 events from being returned to unauthed users,
+ // only when authentication is a thing
+ if !slices.Contains(filter.Kinds, 4) {
+ return false, ""
+ }
+
+ ws := khatru.GetConnection(ctx)
+ senders := filter.Authors
+ receivers, _ := filter.Tags["p"]
+ switch {
+ case ws.AuthedPublicKey == "":
+ // not authenticated
+ return true, "restricted: this relay does not serve kind-4 to unauthenticated users, does your client implement NIP-42?"
+ case len(senders) == 1 && len(receivers) < 2 && (senders[0] == ws.AuthedPublicKey):
+ // allowed filter: ws.authed is sole sender (filter specifies one or all receivers)
+ return false, ""
+ case len(receivers) == 1 && len(senders) < 2 && (receivers[0] == ws.AuthedPublicKey):
+ // allowed filter: ws.authed is sole receiver (filter specifies one or all senders)
+ return false, ""
+ default:
+ // restricted filter: do not return any events,
+ // even if other elements in filters array were not restricted).
+ // client should know better.
+ return true, "restricted: authenticated user does not have authorization for requested filters."
+ }
+}
diff --git a/vendor/github.com/fiatjaf/khatru/policies/ratelimits.go b/vendor/github.com/fiatjaf/khatru/policies/ratelimits.go
new file mode 100644
index 0000000..6a78e7c
--- /dev/null
+++ b/vendor/github.com/fiatjaf/khatru/policies/ratelimits.go
@@ -0,0 +1,42 @@
+package policies
+
+import (
+ "context"
+ "net/http"
+ "time"
+
+ "github.com/fiatjaf/khatru"
+ "github.com/nbd-wtf/go-nostr"
+)
+
+func EventIPRateLimiter(tokensPerInterval int, interval time.Duration, maxTokens int) func(ctx context.Context, _ *nostr.Event) (reject bool, msg string) {
+ rl := startRateLimitSystem[string](tokensPerInterval, interval, maxTokens)
+
+ return func(ctx context.Context, _ *nostr.Event) (reject bool, msg string) {
+ return rl(khatru.GetIP(ctx)), "rate-limited: slow down, please"
+ }
+}
+
+func EventPubKeyRateLimiter(tokensPerInterval int, interval time.Duration, maxTokens int) func(ctx context.Context, _ *nostr.Event) (reject bool, msg string) {
+ rl := startRateLimitSystem[string](tokensPerInterval, interval, maxTokens)
+
+ return func(ctx context.Context, evt *nostr.Event) (reject bool, msg string) {
+ return rl(evt.PubKey), "rate-limited: slow down, please"
+ }
+}
+
+func ConnectionRateLimiter(tokensPerInterval int, interval time.Duration, maxTokens int) func(r *http.Request) bool {
+ rl := startRateLimitSystem[string](tokensPerInterval, interval, maxTokens)
+
+ return func(r *http.Request) bool {
+ return rl(khatru.GetIPFromRequest(r))
+ }
+}
+
+func FilterIPRateLimiter(tokensPerInterval int, interval time.Duration, maxTokens int) func(ctx context.Context, _ nostr.Filter) (reject bool, msg string) {
+ rl := startRateLimitSystem[string](tokensPerInterval, interval, maxTokens)
+
+ return func(ctx context.Context, _ nostr.Filter) (reject bool, msg string) {
+ return rl(khatru.GetIP(ctx)), "rate-limited: there is a bug in the client, no one should be making so many requests"
+ }
+}
diff --git a/vendor/github.com/fiatjaf/khatru/policies/sane_defaults.go b/vendor/github.com/fiatjaf/khatru/policies/sane_defaults.go
new file mode 100644
index 0000000..4230b14
--- /dev/null
+++ b/vendor/github.com/fiatjaf/khatru/policies/sane_defaults.go
@@ -0,0 +1,24 @@
+package policies
+
+import (
+ "time"
+
+ "github.com/fiatjaf/khatru"
+)
+
+func ApplySaneDefaults(relay *khatru.Relay) {
+ relay.RejectEvent = append(relay.RejectEvent,
+ RejectEventsWithBase64Media,
+ EventIPRateLimiter(2, time.Minute*3, 5),
+ )
+
+ relay.RejectFilter = append(relay.RejectFilter,
+ NoEmptyFilters,
+ NoComplexFilters,
+ FilterIPRateLimiter(20, time.Minute, 100),
+ )
+
+ relay.RejectConnection = append(relay.RejectConnection,
+ ConnectionRateLimiter(1, time.Minute*5, 10),
+ )
+}
diff --git a/vendor/github.com/fiatjaf/khatru/relay.go b/vendor/github.com/fiatjaf/khatru/relay.go
new file mode 100644
index 0000000..69297db
--- /dev/null
+++ b/vendor/github.com/fiatjaf/khatru/relay.go
@@ -0,0 +1,103 @@
+package khatru
+
+import (
+ "context"
+ "log"
+ "net/http"
+ "os"
+ "sync"
+ "time"
+
+ "github.com/fasthttp/websocket"
+ "github.com/nbd-wtf/go-nostr"
+ "github.com/nbd-wtf/go-nostr/nip11"
+)
+
+func NewRelay() *Relay {
+ rl := &Relay{
+ Log: log.New(os.Stderr, "[khatru-relay] ", log.LstdFlags),
+
+ Info: &nip11.RelayInformationDocument{
+ Software: "https://github.com/fiatjaf/khatru",
+ Version: "n/a",
+ SupportedNIPs: []int{1, 11, 42, 70, 86},
+ },
+
+ upgrader: websocket.Upgrader{
+ ReadBufferSize: 1024,
+ WriteBufferSize: 1024,
+ CheckOrigin: func(r *http.Request) bool { return true },
+ },
+
+ clients: make(map[*WebSocket][]listenerSpec, 100),
+ listeners: make([]listener, 0, 100),
+
+ serveMux: &http.ServeMux{},
+
+ WriteWait: 10 * time.Second,
+ PongWait: 60 * time.Second,
+ PingPeriod: 30 * time.Second,
+ MaxMessageSize: 512000,
+ }
+
+ return rl
+}
+
+type Relay struct {
+ ServiceURL string
+
+ // these structs keeps track of all the things that can be customized when handling events or requests
+ RejectEvent []func(ctx context.Context, event *nostr.Event) (reject bool, msg string)
+ OverwriteDeletionOutcome []func(ctx context.Context, target *nostr.Event, deletion *nostr.Event) (acceptDeletion bool, msg string)
+ StoreEvent []func(ctx context.Context, event *nostr.Event) error
+ DeleteEvent []func(ctx context.Context, event *nostr.Event) error
+ OnEventSaved []func(ctx context.Context, event *nostr.Event)
+ OnEphemeralEvent []func(ctx context.Context, event *nostr.Event)
+ RejectFilter []func(ctx context.Context, filter nostr.Filter) (reject bool, msg string)
+ RejectCountFilter []func(ctx context.Context, filter nostr.Filter) (reject bool, msg string)
+ OverwriteFilter []func(ctx context.Context, filter *nostr.Filter)
+ OverwriteCountFilter []func(ctx context.Context, filter *nostr.Filter)
+ QueryEvents []func(ctx context.Context, filter nostr.Filter) (chan *nostr.Event, error)
+ CountEvents []func(ctx context.Context, filter nostr.Filter) (int64, error)
+ RejectConnection []func(r *http.Request) bool
+ OnConnect []func(ctx context.Context)
+ OnDisconnect []func(ctx context.Context)
+ OverwriteRelayInformation []func(ctx context.Context, r *http.Request, info nip11.RelayInformationDocument) nip11.RelayInformationDocument
+ OverwriteResponseEvent []func(ctx context.Context, event *nostr.Event)
+ PreventBroadcast []func(ws *WebSocket, event *nostr.Event) bool
+
+ // these are used when this relays acts as a router
+ routes []Route
+ getSubRelayFromEvent func(*nostr.Event) *Relay // used for handling EVENTs
+ getSubRelayFromFilter func(nostr.Filter) *Relay // used for handling REQs
+
+ // setting up handlers here will enable these methods
+ ManagementAPI RelayManagementAPI
+
+ // editing info will affect the NIP-11 responses
+ Info *nip11.RelayInformationDocument
+
+ // Default logger, as set by NewServer, is a stdlib logger prefixed with "[khatru-relay] ",
+ // outputting to stderr.
+ Log *log.Logger
+
+ // for establishing websockets
+ upgrader websocket.Upgrader
+
+ // keep a connection reference to all connected clients for Server.Shutdown
+ // also used for keeping track of who is listening to what
+ clients map[*WebSocket][]listenerSpec
+ listeners []listener
+ clientsMutex sync.Mutex
+
+ // in case you call Server.Start
+ Addr string
+ serveMux *http.ServeMux
+ httpServer *http.Server
+
+ // websocket options
+ WriteWait time.Duration // Time allowed to write a message to the peer.
+ PongWait time.Duration // Time allowed to read the next pong message from the peer.
+ PingPeriod time.Duration // Send pings to peer with this period. Must be less than pongWait.
+ MaxMessageSize int64 // Maximum message size allowed from peer.
+}
diff --git a/vendor/github.com/fiatjaf/khatru/responding.go b/vendor/github.com/fiatjaf/khatru/responding.go
new file mode 100644
index 0000000..bb72cb6
--- /dev/null
+++ b/vendor/github.com/fiatjaf/khatru/responding.go
@@ -0,0 +1,88 @@
+package khatru
+
+import (
+ "context"
+ "errors"
+ "sync"
+
+ "github.com/nbd-wtf/go-nostr"
+)
+
+func (rl *Relay) handleRequest(ctx context.Context, id string, eose *sync.WaitGroup, ws *WebSocket, filter nostr.Filter) error {
+ defer eose.Done()
+
+ // overwrite the filter (for example, to eliminate some kinds or
+ // that we know we don't support)
+ for _, ovw := range rl.OverwriteFilter {
+ ovw(ctx, &filter)
+ }
+
+ if filter.LimitZero {
+ // don't do any queries, just subscribe to future events
+ return nil
+ }
+
+ // then check if we'll reject this filter (we apply this after overwriting
+ // because we may, for example, remove some things from the incoming filters
+ // that we know we don't support, and then if the end result is an empty
+ // filter we can just reject it)
+ for _, reject := range rl.RejectFilter {
+ if reject, msg := reject(ctx, filter); reject {
+ return errors.New(nostr.NormalizeOKMessage(msg, "blocked"))
+ }
+ }
+
+ // run the functions to query events (generally just one,
+ // but we might be fetching stuff from multiple places)
+ eose.Add(len(rl.QueryEvents))
+ for _, query := range rl.QueryEvents {
+ ch, err := query(ctx, filter)
+ if err != nil {
+ ws.WriteJSON(nostr.NoticeEnvelope(err.Error()))
+ eose.Done()
+ continue
+ } else if ch == nil {
+ eose.Done()
+ continue
+ }
+
+ go func(ch chan *nostr.Event) {
+ for event := range ch {
+ for _, ovw := range rl.OverwriteResponseEvent {
+ ovw(ctx, event)
+ }
+ ws.WriteJSON(nostr.EventEnvelope{SubscriptionID: &id, Event: *event})
+ }
+ eose.Done()
+ }(ch)
+ }
+
+ return nil
+}
+
+func (rl *Relay) handleCountRequest(ctx context.Context, ws *WebSocket, filter nostr.Filter) int64 {
+ // overwrite the filter (for example, to eliminate some kinds or tags that we know we don't support)
+ for _, ovw := range rl.OverwriteCountFilter {
+ ovw(ctx, &filter)
+ }
+
+ // then check if we'll reject this filter
+ for _, reject := range rl.RejectCountFilter {
+ if rejecting, msg := reject(ctx, filter); rejecting {
+ ws.WriteJSON(nostr.NoticeEnvelope(msg))
+ return 0
+ }
+ }
+
+ // run the functions to count (generally it will be just one)
+ var subtotal int64 = 0
+ for _, count := range rl.CountEvents {
+ res, err := count(ctx, filter)
+ if err != nil {
+ ws.WriteJSON(nostr.NoticeEnvelope(err.Error()))
+ }
+ subtotal += res
+ }
+
+ return subtotal
+}
diff --git a/vendor/github.com/fiatjaf/khatru/router.go b/vendor/github.com/fiatjaf/khatru/router.go
new file mode 100644
index 0000000..bab833b
--- /dev/null
+++ b/vendor/github.com/fiatjaf/khatru/router.go
@@ -0,0 +1,67 @@
+package khatru
+
+import (
+ "github.com/nbd-wtf/go-nostr"
+)
+
+type Router struct{ *Relay }
+
+type Route struct {
+ eventMatcher func(*nostr.Event) bool
+ filterMatcher func(nostr.Filter) bool
+ relay *Relay
+}
+
+type routeBuilder struct {
+ router *Router
+ eventMatcher func(*nostr.Event) bool
+ filterMatcher func(nostr.Filter) bool
+}
+
+func NewRouter() *Router {
+ rr := &Router{Relay: NewRelay()}
+ rr.routes = make([]Route, 0, 3)
+ rr.getSubRelayFromFilter = func(f nostr.Filter) *Relay {
+ for _, route := range rr.routes {
+ if route.filterMatcher(f) {
+ return route.relay
+ }
+ }
+ return rr.Relay
+ }
+ rr.getSubRelayFromEvent = func(e *nostr.Event) *Relay {
+ for _, route := range rr.routes {
+ if route.eventMatcher(e) {
+ return route.relay
+ }
+ }
+ return rr.Relay
+ }
+ return rr
+}
+
+func (rr *Router) Route() routeBuilder {
+ return routeBuilder{
+ router: rr,
+ filterMatcher: func(f nostr.Filter) bool { return false },
+ eventMatcher: func(e *nostr.Event) bool { return false },
+ }
+}
+
+func (rb routeBuilder) Req(fn func(nostr.Filter) bool) routeBuilder {
+ rb.filterMatcher = fn
+ return rb
+}
+
+func (rb routeBuilder) Event(fn func(*nostr.Event) bool) routeBuilder {
+ rb.eventMatcher = fn
+ return rb
+}
+
+func (rb routeBuilder) Relay(relay *Relay) {
+ rb.router.routes = append(rb.router.routes, Route{
+ filterMatcher: rb.filterMatcher,
+ eventMatcher: rb.eventMatcher,
+ relay: relay,
+ })
+}
diff --git a/vendor/github.com/fiatjaf/khatru/utils.go b/vendor/github.com/fiatjaf/khatru/utils.go
new file mode 100644
index 0000000..4060764
--- /dev/null
+++ b/vendor/github.com/fiatjaf/khatru/utils.go
@@ -0,0 +1,49 @@
+package khatru
+
+import (
+ "context"
+
+ "github.com/nbd-wtf/go-nostr"
+)
+
+const (
+ wsKey = iota
+ subscriptionIdKey
+ nip86HeaderAuthKey
+)
+
+func RequestAuth(ctx context.Context) {
+ ws := GetConnection(ctx)
+ ws.authLock.Lock()
+ if ws.Authed == nil {
+ ws.Authed = make(chan struct{})
+ }
+ ws.authLock.Unlock()
+ ws.WriteJSON(nostr.AuthEnvelope{Challenge: &ws.Challenge})
+}
+
+func GetConnection(ctx context.Context) *WebSocket {
+ wsi := ctx.Value(wsKey)
+ if wsi != nil {
+ return wsi.(*WebSocket)
+ }
+ return nil
+}
+
+func GetAuthed(ctx context.Context) string {
+ if conn := GetConnection(ctx); conn != nil {
+ return conn.AuthedPublicKey
+ }
+ if nip86Auth := ctx.Value(nip86HeaderAuthKey); nip86Auth != nil {
+ return nip86Auth.(string)
+ }
+ return ""
+}
+
+func GetIP(ctx context.Context) string {
+ return GetIPFromRequest(GetConnection(ctx).Request)
+}
+
+func GetSubscriptionID(ctx context.Context) string {
+ return ctx.Value(subscriptionIdKey).(string)
+}
diff --git a/vendor/github.com/fiatjaf/khatru/websocket.go b/vendor/github.com/fiatjaf/khatru/websocket.go
new file mode 100644
index 0000000..f00a636
--- /dev/null
+++ b/vendor/github.com/fiatjaf/khatru/websocket.go
@@ -0,0 +1,35 @@
+package khatru
+
+import (
+ "net/http"
+ "sync"
+
+ "github.com/fasthttp/websocket"
+)
+
+type WebSocket struct {
+ conn *websocket.Conn
+ mutex sync.Mutex
+
+ // original request
+ Request *http.Request
+
+ // nip42
+ Challenge string
+ AuthedPublicKey string
+ Authed chan struct{}
+
+ authLock sync.Mutex
+}
+
+func (ws *WebSocket) WriteJSON(any any) error {
+ ws.mutex.Lock()
+ defer ws.mutex.Unlock()
+ return ws.conn.WriteJSON(any)
+}
+
+func (ws *WebSocket) WriteMessage(t int, b []byte) error {
+ ws.mutex.Lock()
+ defer ws.mutex.Unlock()
+ return ws.conn.WriteMessage(t, b)
+}
diff --git a/vendor/github.com/gobwas/httphead/LICENSE b/vendor/github.com/gobwas/httphead/LICENSE
new file mode 100644
index 0000000..2744317
--- /dev/null
+++ b/vendor/github.com/gobwas/httphead/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2017 Sergey Kamardin
+
+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/gobwas/httphead/README.md b/vendor/github.com/gobwas/httphead/README.md
new file mode 100644
index 0000000..67a97fd
--- /dev/null
+++ b/vendor/github.com/gobwas/httphead/README.md
@@ -0,0 +1,63 @@
+# httphead.[go](https://golang.org)
+
+[![GoDoc][godoc-image]][godoc-url]
+
+> Tiny HTTP header value parsing library in go.
+
+## Overview
+
+This library contains low-level functions for scanning HTTP RFC2616 compatible header value grammars.
+
+## Install
+
+```shell
+ go get github.com/gobwas/httphead
+```
+
+## Example
+
+The example below shows how multiple-choise HTTP header value could be parsed with this library:
+
+```go
+ options, ok := httphead.ParseOptions([]byte(`foo;bar=1,baz`), nil)
+ fmt.Println(options, ok)
+ // Output: [{foo map[bar:1]} {baz map[]}] true
+```
+
+The low-level example below shows how to optimize keys skipping and selection
+of some key:
+
+```go
+ // The right part of full header line like:
+ // X-My-Header: key;foo=bar;baz,key;baz
+ header := []byte(`foo;a=0,foo;a=1,foo;a=2,foo;a=3`)
+
+ // We want to search key "foo" with an "a" parameter that equal to "2".
+ var (
+ foo = []byte(`foo`)
+ a = []byte(`a`)
+ v = []byte(`2`)
+ )
+ var found bool
+ httphead.ScanOptions(header, func(i int, key, param, value []byte) Control {
+ if !bytes.Equal(key, foo) {
+ return ControlSkip
+ }
+ if !bytes.Equal(param, a) {
+ if bytes.Equal(value, v) {
+ // Found it!
+ found = true
+ return ControlBreak
+ }
+ return ControlSkip
+ }
+ return ControlContinue
+ })
+```
+
+For more usage examples please see [docs][godoc-url] or package tests.
+
+[godoc-image]: https://godoc.org/github.com/gobwas/httphead?status.svg
+[godoc-url]: https://godoc.org/github.com/gobwas/httphead
+[travis-image]: https://travis-ci.org/gobwas/httphead.svg?branch=master
+[travis-url]: https://travis-ci.org/gobwas/httphead
diff --git a/vendor/github.com/gobwas/httphead/cookie.go b/vendor/github.com/gobwas/httphead/cookie.go
new file mode 100644
index 0000000..05c9a1f
--- /dev/null
+++ b/vendor/github.com/gobwas/httphead/cookie.go
@@ -0,0 +1,200 @@
+package httphead
+
+import (
+ "bytes"
+)
+
+// ScanCookie scans cookie pairs from data using DefaultCookieScanner.Scan()
+// method.
+func ScanCookie(data []byte, it func(key, value []byte) bool) bool {
+ return DefaultCookieScanner.Scan(data, it)
+}
+
+// DefaultCookieScanner is a CookieScanner which is used by ScanCookie().
+// Note that it is intended to have the same behavior as http.Request.Cookies()
+// has.
+var DefaultCookieScanner = CookieScanner{}
+
+// CookieScanner contains options for scanning cookie pairs.
+// See https://tools.ietf.org/html/rfc6265#section-4.1.1
+type CookieScanner struct {
+ // DisableNameValidation disables name validation of a cookie. If false,
+ // only RFC2616 "tokens" are accepted.
+ DisableNameValidation bool
+
+ // DisableValueValidation disables value validation of a cookie. If false,
+ // only RFC6265 "cookie-octet" characters are accepted.
+ //
+ // Note that Strict option also affects validation of a value.
+ //
+ // If Strict is false, then scanner begins to allow space and comma
+ // characters inside the value for better compatibility with non standard
+ // cookies implementations.
+ DisableValueValidation bool
+
+ // BreakOnPairError sets scanner to immediately return after first pair syntax
+ // validation error.
+ // If false, scanner will try to skip invalid pair bytes and go ahead.
+ BreakOnPairError bool
+
+ // Strict enables strict RFC6265 mode scanning. It affects name and value
+ // validation, as also some other rules.
+ // If false, it is intended to bring the same behavior as
+ // http.Request.Cookies().
+ Strict bool
+}
+
+// Scan maps data to name and value pairs. Usually data represents value of the
+// Cookie header.
+func (c CookieScanner) Scan(data []byte, it func(name, value []byte) bool) bool {
+ lexer := &Scanner{data: data}
+
+ const (
+ statePair = iota
+ stateBefore
+ )
+
+ state := statePair
+
+ for lexer.Buffered() > 0 {
+ switch state {
+ case stateBefore:
+ // Pairs separated by ";" and space, according to the RFC6265:
+ // cookie-pair *( ";" SP cookie-pair )
+ //
+ // Cookie pairs MUST be separated by (";" SP). So our only option
+ // here is to fail as syntax error.
+ a, b := lexer.Peek2()
+ if a != ';' {
+ return false
+ }
+
+ state = statePair
+
+ advance := 1
+ if b == ' ' {
+ advance++
+ } else if c.Strict {
+ return false
+ }
+
+ lexer.Advance(advance)
+
+ case statePair:
+ if !lexer.FetchUntil(';') {
+ return false
+ }
+
+ var value []byte
+ name := lexer.Bytes()
+ if i := bytes.IndexByte(name, '='); i != -1 {
+ value = name[i+1:]
+ name = name[:i]
+ } else if c.Strict {
+ if !c.BreakOnPairError {
+ goto nextPair
+ }
+ return false
+ }
+
+ if !c.Strict {
+ trimLeft(name)
+ }
+ if !c.DisableNameValidation && !ValidCookieName(name) {
+ if !c.BreakOnPairError {
+ goto nextPair
+ }
+ return false
+ }
+
+ if !c.Strict {
+ value = trimRight(value)
+ }
+ value = stripQuotes(value)
+ if !c.DisableValueValidation && !ValidCookieValue(value, c.Strict) {
+ if !c.BreakOnPairError {
+ goto nextPair
+ }
+ return false
+ }
+
+ if !it(name, value) {
+ return true
+ }
+
+ nextPair:
+ state = stateBefore
+ }
+ }
+
+ return true
+}
+
+// ValidCookieValue reports whether given value is a valid RFC6265
+// "cookie-octet" bytes.
+//
+// cookie-octet = %x21 / %x23-2B / %x2D-3A / %x3C-5B / %x5D-7E
+// ; US-ASCII characters excluding CTLs,
+// ; whitespace DQUOTE, comma, semicolon,
+// ; and backslash
+//
+// Note that the false strict parameter disables errors on space 0x20 and comma
+// 0x2c. This could be useful to bring some compatibility with non-compliant
+// clients/servers in the real world.
+// It acts the same as standard library cookie parser if strict is false.
+func ValidCookieValue(value []byte, strict bool) bool {
+ if len(value) == 0 {
+ return true
+ }
+ for _, c := range value {
+ switch c {
+ case '"', ';', '\\':
+ return false
+ case ',', ' ':
+ if strict {
+ return false
+ }
+ default:
+ if c <= 0x20 {
+ return false
+ }
+ if c >= 0x7f {
+ return false
+ }
+ }
+ }
+ return true
+}
+
+// ValidCookieName reports wheter given bytes is a valid RFC2616 "token" bytes.
+func ValidCookieName(name []byte) bool {
+ for _, c := range name {
+ if !OctetTypes[c].IsToken() {
+ return false
+ }
+ }
+ return true
+}
+
+func stripQuotes(bts []byte) []byte {
+ if last := len(bts) - 1; last > 0 && bts[0] == '"' && bts[last] == '"' {
+ return bts[1:last]
+ }
+ return bts
+}
+
+func trimLeft(p []byte) []byte {
+ var i int
+ for i < len(p) && OctetTypes[p[i]].IsSpace() {
+ i++
+ }
+ return p[i:]
+}
+
+func trimRight(p []byte) []byte {
+ j := len(p)
+ for j > 0 && OctetTypes[p[j-1]].IsSpace() {
+ j--
+ }
+ return p[:j]
+}
diff --git a/vendor/github.com/gobwas/httphead/head.go b/vendor/github.com/gobwas/httphead/head.go
new file mode 100644
index 0000000..a50e907
--- /dev/null
+++ b/vendor/github.com/gobwas/httphead/head.go
@@ -0,0 +1,275 @@
+package httphead
+
+import (
+ "bufio"
+ "bytes"
+)
+
+// Version contains protocol major and minor version.
+type Version struct {
+ Major int
+ Minor int
+}
+
+// RequestLine contains parameters parsed from the first request line.
+type RequestLine struct {
+ Method []byte
+ URI []byte
+ Version Version
+}
+
+// ResponseLine contains parameters parsed from the first response line.
+type ResponseLine struct {
+ Version Version
+ Status int
+ Reason []byte
+}
+
+// SplitRequestLine splits given slice of bytes into three chunks without
+// parsing.
+func SplitRequestLine(line []byte) (method, uri, version []byte) {
+ return split3(line, ' ')
+}
+
+// ParseRequestLine parses http request line like "GET / HTTP/1.0".
+func ParseRequestLine(line []byte) (r RequestLine, ok bool) {
+ var i int
+ for i = 0; i < len(line); i++ {
+ c := line[i]
+ if !OctetTypes[c].IsToken() {
+ if i > 0 && c == ' ' {
+ break
+ }
+ return
+ }
+ }
+ if i == len(line) {
+ return
+ }
+
+ var proto []byte
+ r.Method = line[:i]
+ r.URI, proto = split2(line[i+1:], ' ')
+ if len(r.URI) == 0 {
+ return
+ }
+ if major, minor, ok := ParseVersion(proto); ok {
+ r.Version.Major = major
+ r.Version.Minor = minor
+ return r, true
+ }
+
+ return r, false
+}
+
+// SplitResponseLine splits given slice of bytes into three chunks without
+// parsing.
+func SplitResponseLine(line []byte) (version, status, reason []byte) {
+ return split3(line, ' ')
+}
+
+// ParseResponseLine parses first response line into ResponseLine struct.
+func ParseResponseLine(line []byte) (r ResponseLine, ok bool) {
+ var (
+ proto []byte
+ status []byte
+ )
+ proto, status, r.Reason = split3(line, ' ')
+ if major, minor, ok := ParseVersion(proto); ok {
+ r.Version.Major = major
+ r.Version.Minor = minor
+ } else {
+ return r, false
+ }
+ if n, ok := IntFromASCII(status); ok {
+ r.Status = n
+ } else {
+ return r, false
+ }
+ // TODO(gobwas): parse here r.Reason fot TEXT rule:
+ // TEXT =
+ return r, true
+}
+
+var (
+ httpVersion10 = []byte("HTTP/1.0")
+ httpVersion11 = []byte("HTTP/1.1")
+ httpVersionPrefix = []byte("HTTP/")
+)
+
+// ParseVersion parses major and minor version of HTTP protocol.
+// It returns parsed values and true if parse is ok.
+func ParseVersion(bts []byte) (major, minor int, ok bool) {
+ switch {
+ case bytes.Equal(bts, httpVersion11):
+ return 1, 1, true
+ case bytes.Equal(bts, httpVersion10):
+ return 1, 0, true
+ case len(bts) < 8:
+ return
+ case !bytes.Equal(bts[:5], httpVersionPrefix):
+ return
+ }
+
+ bts = bts[5:]
+
+ dot := bytes.IndexByte(bts, '.')
+ if dot == -1 {
+ return
+ }
+ major, ok = IntFromASCII(bts[:dot])
+ if !ok {
+ return
+ }
+ minor, ok = IntFromASCII(bts[dot+1:])
+ if !ok {
+ return
+ }
+
+ return major, minor, true
+}
+
+// ReadLine reads line from br. It reads until '\n' and returns bytes without
+// '\n' or '\r\n' at the end.
+// It returns err if and only if line does not end in '\n'. Note that read
+// bytes returned in any case of error.
+//
+// It is much like the textproto/Reader.ReadLine() except the thing that it
+// returns raw bytes, instead of string. That is, it avoids copying bytes read
+// from br.
+//
+// textproto/Reader.ReadLineBytes() is also makes copy of resulting bytes to be
+// safe with future I/O operations on br.
+//
+// We could control I/O operations on br and do not need to make additional
+// copy for safety.
+func ReadLine(br *bufio.Reader) ([]byte, error) {
+ var line []byte
+ for {
+ bts, err := br.ReadSlice('\n')
+ if err == bufio.ErrBufferFull {
+ // Copy bytes because next read will discard them.
+ line = append(line, bts...)
+ continue
+ }
+ // Avoid copy of single read.
+ if line == nil {
+ line = bts
+ } else {
+ line = append(line, bts...)
+ }
+ if err != nil {
+ return line, err
+ }
+ // Size of line is at least 1.
+ // In other case bufio.ReadSlice() returns error.
+ n := len(line)
+ // Cut '\n' or '\r\n'.
+ if n > 1 && line[n-2] == '\r' {
+ line = line[:n-2]
+ } else {
+ line = line[:n-1]
+ }
+ return line, nil
+ }
+}
+
+// ParseHeaderLine parses HTTP header as key-value pair. It returns parsed
+// values and true if parse is ok.
+func ParseHeaderLine(line []byte) (k, v []byte, ok bool) {
+ colon := bytes.IndexByte(line, ':')
+ if colon == -1 {
+ return
+ }
+ k = trim(line[:colon])
+ for _, c := range k {
+ if !OctetTypes[c].IsToken() {
+ return nil, nil, false
+ }
+ }
+ v = trim(line[colon+1:])
+ return k, v, true
+}
+
+// IntFromASCII converts ascii encoded decimal numeric value from HTTP entities
+// to an integer.
+func IntFromASCII(bts []byte) (ret int, ok bool) {
+ // ASCII numbers all start with the high-order bits 0011.
+ // If you see that, and the next bits are 0-9 (0000 - 1001) you can grab those
+ // bits and interpret them directly as an integer.
+ var n int
+ if n = len(bts); n < 1 {
+ return 0, false
+ }
+ for i := 0; i < n; i++ {
+ if bts[i]&0xf0 != 0x30 {
+ return 0, false
+ }
+ ret += int(bts[i]&0xf) * pow(10, n-i-1)
+ }
+ return ret, true
+}
+
+const (
+ toLower = 'a' - 'A' // for use with OR.
+ toUpper = ^byte(toLower) // for use with AND.
+)
+
+// CanonicalizeHeaderKey is like standard textproto/CanonicalMIMEHeaderKey,
+// except that it operates with slice of bytes and modifies it inplace without
+// copying.
+func CanonicalizeHeaderKey(k []byte) {
+ upper := true
+ for i, c := range k {
+ if upper && 'a' <= c && c <= 'z' {
+ k[i] &= toUpper
+ } else if !upper && 'A' <= c && c <= 'Z' {
+ k[i] |= toLower
+ }
+ upper = c == '-'
+ }
+}
+
+// pow for integers implementation.
+// See Donald Knuth, The Art of Computer Programming, Volume 2, Section 4.6.3
+func pow(a, b int) int {
+ p := 1
+ for b > 0 {
+ if b&1 != 0 {
+ p *= a
+ }
+ b >>= 1
+ a *= a
+ }
+ return p
+}
+
+func split3(p []byte, sep byte) (p1, p2, p3 []byte) {
+ a := bytes.IndexByte(p, sep)
+ b := bytes.IndexByte(p[a+1:], sep)
+ if a == -1 || b == -1 {
+ return p, nil, nil
+ }
+ b += a + 1
+ return p[:a], p[a+1 : b], p[b+1:]
+}
+
+func split2(p []byte, sep byte) (p1, p2 []byte) {
+ i := bytes.IndexByte(p, sep)
+ if i == -1 {
+ return p, nil
+ }
+ return p[:i], p[i+1:]
+}
+
+func trim(p []byte) []byte {
+ var i, j int
+ for i = 0; i < len(p) && (p[i] == ' ' || p[i] == '\t'); {
+ i++
+ }
+ for j = len(p); j > i && (p[j-1] == ' ' || p[j-1] == '\t'); {
+ j--
+ }
+ return p[i:j]
+}
diff --git a/vendor/github.com/gobwas/httphead/httphead.go b/vendor/github.com/gobwas/httphead/httphead.go
new file mode 100644
index 0000000..2387e80
--- /dev/null
+++ b/vendor/github.com/gobwas/httphead/httphead.go
@@ -0,0 +1,331 @@
+// Package httphead contains utils for parsing HTTP and HTTP-grammar compatible
+// text protocols headers.
+//
+// That is, this package first aim is to bring ability to easily parse
+// constructions, described here https://tools.ietf.org/html/rfc2616#section-2
+package httphead
+
+import (
+ "bytes"
+ "strings"
+)
+
+// ScanTokens parses data in this form:
+//
+// list = 1#token
+//
+// It returns false if data is malformed.
+func ScanTokens(data []byte, it func([]byte) bool) bool {
+ lexer := &Scanner{data: data}
+
+ var ok bool
+ for lexer.Next() {
+ switch lexer.Type() {
+ case ItemToken:
+ ok = true
+ if !it(lexer.Bytes()) {
+ return true
+ }
+ case ItemSeparator:
+ if !isComma(lexer.Bytes()) {
+ return false
+ }
+ default:
+ return false
+ }
+ }
+
+ return ok && !lexer.err
+}
+
+// ParseOptions parses all header options and appends it to given slice of
+// Option. It returns flag of successful (wellformed input) parsing.
+//
+// Note that appended options are all consist of subslices of data. That is,
+// mutation of data will mutate appended options.
+func ParseOptions(data []byte, options []Option) ([]Option, bool) {
+ var i int
+ index := -1
+ return options, ScanOptions(data, func(idx int, name, attr, val []byte) Control {
+ if idx != index {
+ index = idx
+ i = len(options)
+ options = append(options, Option{Name: name})
+ }
+ if attr != nil {
+ options[i].Parameters.Set(attr, val)
+ }
+ return ControlContinue
+ })
+}
+
+// SelectFlag encodes way of options selection.
+type SelectFlag byte
+
+// String represetns flag as string.
+func (f SelectFlag) String() string {
+ var flags [2]string
+ var n int
+ if f&SelectCopy != 0 {
+ flags[n] = "copy"
+ n++
+ }
+ if f&SelectUnique != 0 {
+ flags[n] = "unique"
+ n++
+ }
+ return "[" + strings.Join(flags[:n], "|") + "]"
+}
+
+const (
+ // SelectCopy causes selector to copy selected option before appending it
+ // to resulting slice.
+ // If SelectCopy flag is not passed to selector, then appended options will
+ // contain sub-slices of the initial data.
+ SelectCopy SelectFlag = 1 << iota
+
+ // SelectUnique causes selector to append only not yet existing option to
+ // resulting slice. Unique is checked by comparing option names.
+ SelectUnique
+)
+
+// OptionSelector contains configuration for selecting Options from header value.
+type OptionSelector struct {
+ // Check is a filter function that applied to every Option that possibly
+ // could be selected.
+ // If Check is nil all options will be selected.
+ Check func(Option) bool
+
+ // Flags contains flags for options selection.
+ Flags SelectFlag
+
+ // Alloc used to allocate slice of bytes when selector is configured with
+ // SelectCopy flag. It will be called with number of bytes needed for copy
+ // of single Option.
+ // If Alloc is nil make is used.
+ Alloc func(n int) []byte
+}
+
+// Select parses header data and appends it to given slice of Option.
+// It also returns flag of successful (wellformed input) parsing.
+func (s OptionSelector) Select(data []byte, options []Option) ([]Option, bool) {
+ var current Option
+ var has bool
+ index := -1
+
+ alloc := s.Alloc
+ if alloc == nil {
+ alloc = defaultAlloc
+ }
+ check := s.Check
+ if check == nil {
+ check = defaultCheck
+ }
+
+ ok := ScanOptions(data, func(idx int, name, attr, val []byte) Control {
+ if idx != index {
+ if has && check(current) {
+ if s.Flags&SelectCopy != 0 {
+ current = current.Copy(alloc(current.Size()))
+ }
+ options = append(options, current)
+ has = false
+ }
+ if s.Flags&SelectUnique != 0 {
+ for i := len(options) - 1; i >= 0; i-- {
+ if bytes.Equal(options[i].Name, name) {
+ return ControlSkip
+ }
+ }
+ }
+ index = idx
+ current = Option{Name: name}
+ has = true
+ }
+ if attr != nil {
+ current.Parameters.Set(attr, val)
+ }
+
+ return ControlContinue
+ })
+ if has && check(current) {
+ if s.Flags&SelectCopy != 0 {
+ current = current.Copy(alloc(current.Size()))
+ }
+ options = append(options, current)
+ }
+
+ return options, ok
+}
+
+func defaultAlloc(n int) []byte { return make([]byte, n) }
+func defaultCheck(Option) bool { return true }
+
+// Control represents operation that scanner should perform.
+type Control byte
+
+const (
+ // ControlContinue causes scanner to continue scan tokens.
+ ControlContinue Control = iota
+ // ControlBreak causes scanner to stop scan tokens.
+ ControlBreak
+ // ControlSkip causes scanner to skip current entity.
+ ControlSkip
+)
+
+// ScanOptions parses data in this form:
+//
+// values = 1#value
+// value = token *( ";" param )
+// param = token [ "=" (token | quoted-string) ]
+//
+// It calls given callback with the index of the option, option itself and its
+// parameter (attribute and its value, both could be nil). Index is useful when
+// header contains multiple choises for the same named option.
+//
+// Given callback should return one of the defined Control* values.
+// ControlSkip means that passed key is not in caller's interest. That is, all
+// parameters of that key will be skipped.
+// ControlBreak means that no more keys and parameters should be parsed. That
+// is, it must break parsing immediately.
+// ControlContinue means that caller want to receive next parameter and its
+// value or the next key.
+//
+// It returns false if data is malformed.
+func ScanOptions(data []byte, it func(index int, option, attribute, value []byte) Control) bool {
+ lexer := &Scanner{data: data}
+
+ var ok bool
+ var state int
+ const (
+ stateKey = iota
+ stateParamBeforeName
+ stateParamName
+ stateParamBeforeValue
+ stateParamValue
+ )
+
+ var (
+ index int
+ key, param, value []byte
+ mustCall bool
+ )
+ for lexer.Next() {
+ var (
+ call bool
+ growIndex int
+ )
+
+ t := lexer.Type()
+ v := lexer.Bytes()
+
+ switch t {
+ case ItemToken:
+ switch state {
+ case stateKey, stateParamBeforeName:
+ key = v
+ state = stateParamBeforeName
+ mustCall = true
+ case stateParamName:
+ param = v
+ state = stateParamBeforeValue
+ mustCall = true
+ case stateParamValue:
+ value = v
+ state = stateParamBeforeName
+ call = true
+ default:
+ return false
+ }
+
+ case ItemString:
+ if state != stateParamValue {
+ return false
+ }
+ value = v
+ state = stateParamBeforeName
+ call = true
+
+ case ItemSeparator:
+ switch {
+ case isComma(v) && state == stateKey:
+ // Nothing to do.
+
+ case isComma(v) && state == stateParamBeforeName:
+ state = stateKey
+ // Make call only if we have not called this key yet.
+ call = mustCall
+ if !call {
+ // If we have already called callback with the key
+ // that just ended.
+ index++
+ } else {
+ // Else grow the index after calling callback.
+ growIndex = 1
+ }
+
+ case isComma(v) && state == stateParamBeforeValue:
+ state = stateKey
+ growIndex = 1
+ call = true
+
+ case isSemicolon(v) && state == stateParamBeforeName:
+ state = stateParamName
+
+ case isSemicolon(v) && state == stateParamBeforeValue:
+ state = stateParamName
+ call = true
+
+ case isEquality(v) && state == stateParamBeforeValue:
+ state = stateParamValue
+
+ default:
+ return false
+ }
+
+ default:
+ return false
+ }
+
+ if call {
+ switch it(index, key, param, value) {
+ case ControlBreak:
+ // User want to stop to parsing parameters.
+ return true
+
+ case ControlSkip:
+ // User want to skip current param.
+ state = stateKey
+ lexer.SkipEscaped(',')
+
+ case ControlContinue:
+ // User is interested in rest of parameters.
+ // Nothing to do.
+
+ default:
+ panic("unexpected control value")
+ }
+ ok = true
+ param = nil
+ value = nil
+ mustCall = false
+ index += growIndex
+ }
+ }
+ if mustCall {
+ ok = true
+ it(index, key, param, value)
+ }
+
+ return ok && !lexer.err
+}
+
+func isComma(b []byte) bool {
+ return len(b) == 1 && b[0] == ','
+}
+func isSemicolon(b []byte) bool {
+ return len(b) == 1 && b[0] == ';'
+}
+func isEquality(b []byte) bool {
+ return len(b) == 1 && b[0] == '='
+}
diff --git a/vendor/github.com/gobwas/httphead/lexer.go b/vendor/github.com/gobwas/httphead/lexer.go
new file mode 100644
index 0000000..729855e
--- /dev/null
+++ b/vendor/github.com/gobwas/httphead/lexer.go
@@ -0,0 +1,360 @@
+package httphead
+
+import (
+ "bytes"
+)
+
+// ItemType encodes type of the lexing token.
+type ItemType int
+
+const (
+ // ItemUndef reports that token is undefined.
+ ItemUndef ItemType = iota
+ // ItemToken reports that token is RFC2616 token.
+ ItemToken
+ // ItemSeparator reports that token is RFC2616 separator.
+ ItemSeparator
+ // ItemString reports that token is RFC2616 quouted string.
+ ItemString
+ // ItemComment reports that token is RFC2616 comment.
+ ItemComment
+ // ItemOctet reports that token is octet slice.
+ ItemOctet
+)
+
+// Scanner represents header tokens scanner.
+// See https://tools.ietf.org/html/rfc2616#section-2
+type Scanner struct {
+ data []byte
+ pos int
+
+ itemType ItemType
+ itemBytes []byte
+
+ err bool
+}
+
+// NewScanner creates new RFC2616 data scanner.
+func NewScanner(data []byte) *Scanner {
+ return &Scanner{data: data}
+}
+
+// Next scans for next token. It returns true on successful scanning, and false
+// on error or EOF.
+func (l *Scanner) Next() bool {
+ c, ok := l.nextChar()
+ if !ok {
+ return false
+ }
+ switch c {
+ case '"': // quoted-string;
+ return l.fetchQuotedString()
+
+ case '(': // comment;
+ return l.fetchComment()
+
+ case '\\', ')': // unexpected chars;
+ l.err = true
+ return false
+
+ default:
+ return l.fetchToken()
+ }
+}
+
+// FetchUntil fetches ItemOctet from current scanner position to first
+// occurence of the c or to the end of the underlying data.
+func (l *Scanner) FetchUntil(c byte) bool {
+ l.resetItem()
+ if l.pos == len(l.data) {
+ return false
+ }
+ return l.fetchOctet(c)
+}
+
+// Peek reads byte at current position without advancing it. On end of data it
+// returns 0.
+func (l *Scanner) Peek() byte {
+ if l.pos == len(l.data) {
+ return 0
+ }
+ return l.data[l.pos]
+}
+
+// Peek2 reads two first bytes at current position without advancing it.
+// If there not enough data it returs 0.
+func (l *Scanner) Peek2() (a, b byte) {
+ if l.pos == len(l.data) {
+ return 0, 0
+ }
+ if l.pos+1 == len(l.data) {
+ return l.data[l.pos], 0
+ }
+ return l.data[l.pos], l.data[l.pos+1]
+}
+
+// Buffered reporst how many bytes there are left to scan.
+func (l *Scanner) Buffered() int {
+ return len(l.data) - l.pos
+}
+
+// Advance moves current position index at n bytes. It returns true on
+// successful move.
+func (l *Scanner) Advance(n int) bool {
+ l.pos += n
+ if l.pos > len(l.data) {
+ l.pos = len(l.data)
+ return false
+ }
+ return true
+}
+
+// Skip skips all bytes until first occurence of c.
+func (l *Scanner) Skip(c byte) {
+ if l.err {
+ return
+ }
+ // Reset scanner state.
+ l.resetItem()
+
+ if i := bytes.IndexByte(l.data[l.pos:], c); i == -1 {
+ // Reached the end of data.
+ l.pos = len(l.data)
+ } else {
+ l.pos += i + 1
+ }
+}
+
+// SkipEscaped skips all bytes until first occurence of non-escaped c.
+func (l *Scanner) SkipEscaped(c byte) {
+ if l.err {
+ return
+ }
+ // Reset scanner state.
+ l.resetItem()
+
+ if i := ScanUntil(l.data[l.pos:], c); i == -1 {
+ // Reached the end of data.
+ l.pos = len(l.data)
+ } else {
+ l.pos += i + 1
+ }
+}
+
+// Type reports current token type.
+func (l *Scanner) Type() ItemType {
+ return l.itemType
+}
+
+// Bytes returns current token bytes.
+func (l *Scanner) Bytes() []byte {
+ return l.itemBytes
+}
+
+func (l *Scanner) nextChar() (byte, bool) {
+ // Reset scanner state.
+ l.resetItem()
+
+ if l.err {
+ return 0, false
+ }
+ l.pos += SkipSpace(l.data[l.pos:])
+ if l.pos == len(l.data) {
+ return 0, false
+ }
+ return l.data[l.pos], true
+}
+
+func (l *Scanner) resetItem() {
+ l.itemType = ItemUndef
+ l.itemBytes = nil
+}
+
+func (l *Scanner) fetchOctet(c byte) bool {
+ i := l.pos
+ if j := bytes.IndexByte(l.data[l.pos:], c); j == -1 {
+ // Reached the end of data.
+ l.pos = len(l.data)
+ } else {
+ l.pos += j
+ }
+
+ l.itemType = ItemOctet
+ l.itemBytes = l.data[i:l.pos]
+
+ return true
+}
+
+func (l *Scanner) fetchToken() bool {
+ n, t := ScanToken(l.data[l.pos:])
+ if n == -1 {
+ l.err = true
+ return false
+ }
+
+ l.itemType = t
+ l.itemBytes = l.data[l.pos : l.pos+n]
+ l.pos += n
+
+ return true
+}
+
+func (l *Scanner) fetchQuotedString() (ok bool) {
+ l.pos++
+
+ n := ScanUntil(l.data[l.pos:], '"')
+ if n == -1 {
+ l.err = true
+ return false
+ }
+
+ l.itemType = ItemString
+ l.itemBytes = RemoveByte(l.data[l.pos:l.pos+n], '\\')
+ l.pos += n + 1
+
+ return true
+}
+
+func (l *Scanner) fetchComment() (ok bool) {
+ l.pos++
+
+ n := ScanPairGreedy(l.data[l.pos:], '(', ')')
+ if n == -1 {
+ l.err = true
+ return false
+ }
+
+ l.itemType = ItemComment
+ l.itemBytes = RemoveByte(l.data[l.pos:l.pos+n], '\\')
+ l.pos += n + 1
+
+ return true
+}
+
+// ScanUntil scans for first non-escaped character c in given data.
+// It returns index of matched c and -1 if c is not found.
+func ScanUntil(data []byte, c byte) (n int) {
+ for {
+ i := bytes.IndexByte(data[n:], c)
+ if i == -1 {
+ return -1
+ }
+ n += i
+ if n == 0 || data[n-1] != '\\' {
+ break
+ }
+ n++
+ }
+ return
+}
+
+// ScanPairGreedy scans for complete pair of opening and closing chars in greedy manner.
+// Note that first opening byte must not be present in data.
+func ScanPairGreedy(data []byte, open, close byte) (n int) {
+ var m int
+ opened := 1
+ for {
+ i := bytes.IndexByte(data[n:], close)
+ if i == -1 {
+ return -1
+ }
+ n += i
+ // If found index is not escaped then it is the end.
+ if n == 0 || data[n-1] != '\\' {
+ opened--
+ }
+
+ for m < i {
+ j := bytes.IndexByte(data[m:i], open)
+ if j == -1 {
+ break
+ }
+ m += j + 1
+ opened++
+ }
+
+ if opened == 0 {
+ break
+ }
+
+ n++
+ m = n
+ }
+ return
+}
+
+// RemoveByte returns data without c. If c is not present in data it returns
+// the same slice. If not, it copies data without c.
+func RemoveByte(data []byte, c byte) []byte {
+ j := bytes.IndexByte(data, c)
+ if j == -1 {
+ return data
+ }
+
+ n := len(data) - 1
+
+ // If character is present, than allocate slice with n-1 capacity. That is,
+ // resulting bytes could be at most n-1 length.
+ result := make([]byte, n)
+ k := copy(result, data[:j])
+
+ for i := j + 1; i < n; {
+ j = bytes.IndexByte(data[i:], c)
+ if j != -1 {
+ k += copy(result[k:], data[i:i+j])
+ i = i + j + 1
+ } else {
+ k += copy(result[k:], data[i:])
+ break
+ }
+ }
+
+ return result[:k]
+}
+
+// SkipSpace skips spaces and lws-sequences from p.
+// It returns number ob bytes skipped.
+func SkipSpace(p []byte) (n int) {
+ for len(p) > 0 {
+ switch {
+ case len(p) >= 3 &&
+ p[0] == '\r' &&
+ p[1] == '\n' &&
+ OctetTypes[p[2]].IsSpace():
+ p = p[3:]
+ n += 3
+ case OctetTypes[p[0]].IsSpace():
+ p = p[1:]
+ n++
+ default:
+ return
+ }
+ }
+ return
+}
+
+// ScanToken scan for next token in p. It returns length of the token and its
+// type. It do not trim p.
+func ScanToken(p []byte) (n int, t ItemType) {
+ if len(p) == 0 {
+ return 0, ItemUndef
+ }
+
+ c := p[0]
+ switch {
+ case OctetTypes[c].IsSeparator():
+ return 1, ItemSeparator
+
+ case OctetTypes[c].IsToken():
+ for n = 1; n < len(p); n++ {
+ c := p[n]
+ if !OctetTypes[c].IsToken() {
+ break
+ }
+ }
+ return n, ItemToken
+
+ default:
+ return -1, ItemUndef
+ }
+}
diff --git a/vendor/github.com/gobwas/httphead/octet.go b/vendor/github.com/gobwas/httphead/octet.go
new file mode 100644
index 0000000..2a04cdd
--- /dev/null
+++ b/vendor/github.com/gobwas/httphead/octet.go
@@ -0,0 +1,83 @@
+package httphead
+
+// OctetType desribes character type.
+//
+// From the "Basic Rules" chapter of RFC2616
+// See https://tools.ietf.org/html/rfc2616#section-2.2
+//
+// OCTET =
+// CHAR =
+// UPALPHA =
+// LOALPHA =
+// ALPHA = UPALPHA | LOALPHA
+// DIGIT =
+// CTL =
+// CR =
+// LF =
+// SP =
+// HT =
+// <"> =
+// CRLF = CR LF
+// LWS = [CRLF] 1*( SP | HT )
+//
+// Many HTTP/1.1 header field values consist of words separated by LWS
+// or special characters. These special characters MUST be in a quoted
+// string to be used within a parameter value (as defined in section
+// 3.6).
+//
+// token = 1*
+// separators = "(" | ")" | "<" | ">" | "@"
+// | "," | ";" | ":" | "\" | <">
+// | "/" | "[" | "]" | "?" | "="
+// | "{" | "}" | SP | HT
+type OctetType byte
+
+// IsChar reports whether octet is CHAR.
+func (t OctetType) IsChar() bool { return t&octetChar != 0 }
+
+// IsControl reports whether octet is CTL.
+func (t OctetType) IsControl() bool { return t&octetControl != 0 }
+
+// IsSeparator reports whether octet is separator.
+func (t OctetType) IsSeparator() bool { return t&octetSeparator != 0 }
+
+// IsSpace reports whether octet is space (SP or HT).
+func (t OctetType) IsSpace() bool { return t&octetSpace != 0 }
+
+// IsToken reports whether octet is token.
+func (t OctetType) IsToken() bool { return t&octetToken != 0 }
+
+const (
+ octetChar OctetType = 1 << iota
+ octetControl
+ octetSpace
+ octetSeparator
+ octetToken
+)
+
+// OctetTypes is a table of octets.
+var OctetTypes [256]OctetType
+
+func init() {
+ for c := 32; c < 256; c++ {
+ var t OctetType
+ if c <= 127 {
+ t |= octetChar
+ }
+ if 0 <= c && c <= 31 || c == 127 {
+ t |= octetControl
+ }
+ switch c {
+ case '(', ')', '<', '>', '@', ',', ';', ':', '"', '/', '[', ']', '?', '=', '{', '}', '\\':
+ t |= octetSeparator
+ case ' ', '\t':
+ t |= octetSpace | octetSeparator
+ }
+
+ if t.IsChar() && !t.IsControl() && !t.IsSeparator() && !t.IsSpace() {
+ t |= octetToken
+ }
+
+ OctetTypes[c] = t
+ }
+}
diff --git a/vendor/github.com/gobwas/httphead/option.go b/vendor/github.com/gobwas/httphead/option.go
new file mode 100644
index 0000000..0a18c7c
--- /dev/null
+++ b/vendor/github.com/gobwas/httphead/option.go
@@ -0,0 +1,193 @@
+package httphead
+
+import (
+ "bytes"
+ "sort"
+)
+
+// Option represents a header option.
+type Option struct {
+ Name []byte
+ Parameters Parameters
+}
+
+// Size returns number of bytes need to be allocated for use in opt.Copy.
+func (opt Option) Size() int {
+ return len(opt.Name) + opt.Parameters.bytes
+}
+
+// Copy copies all underlying []byte slices into p and returns new Option.
+// Note that p must be at least of opt.Size() length.
+func (opt Option) Copy(p []byte) Option {
+ n := copy(p, opt.Name)
+ opt.Name = p[:n]
+ opt.Parameters, p = opt.Parameters.Copy(p[n:])
+ return opt
+}
+
+// Clone is a shorthand for making slice of opt.Size() sequenced with Copy()
+// call.
+func (opt Option) Clone() Option {
+ return opt.Copy(make([]byte, opt.Size()))
+}
+
+// String represents option as a string.
+func (opt Option) String() string {
+ return "{" + string(opt.Name) + " " + opt.Parameters.String() + "}"
+}
+
+// NewOption creates named option with given parameters.
+func NewOption(name string, params map[string]string) Option {
+ p := Parameters{}
+ for k, v := range params {
+ p.Set([]byte(k), []byte(v))
+ }
+ return Option{
+ Name: []byte(name),
+ Parameters: p,
+ }
+}
+
+// Equal reports whether option is equal to b.
+func (opt Option) Equal(b Option) bool {
+ if bytes.Equal(opt.Name, b.Name) {
+ return opt.Parameters.Equal(b.Parameters)
+ }
+ return false
+}
+
+// Parameters represents option's parameters.
+type Parameters struct {
+ pos int
+ bytes int
+ arr [8]pair
+ dyn []pair
+}
+
+// Equal reports whether a equal to b.
+func (p Parameters) Equal(b Parameters) bool {
+ switch {
+ case p.dyn == nil && b.dyn == nil:
+ case p.dyn != nil && b.dyn != nil:
+ default:
+ return false
+ }
+
+ ad, bd := p.data(), b.data()
+ if len(ad) != len(bd) {
+ return false
+ }
+
+ sort.Sort(pairs(ad))
+ sort.Sort(pairs(bd))
+
+ for i := 0; i < len(ad); i++ {
+ av, bv := ad[i], bd[i]
+ if !bytes.Equal(av.key, bv.key) || !bytes.Equal(av.value, bv.value) {
+ return false
+ }
+ }
+ return true
+}
+
+// Size returns number of bytes that needed to copy p.
+func (p *Parameters) Size() int {
+ return p.bytes
+}
+
+// Copy copies all underlying []byte slices into dst and returns new
+// Parameters.
+// Note that dst must be at least of p.Size() length.
+func (p *Parameters) Copy(dst []byte) (Parameters, []byte) {
+ ret := Parameters{
+ pos: p.pos,
+ bytes: p.bytes,
+ }
+ if p.dyn != nil {
+ ret.dyn = make([]pair, len(p.dyn))
+ for i, v := range p.dyn {
+ ret.dyn[i], dst = v.copy(dst)
+ }
+ } else {
+ for i, p := range p.arr {
+ ret.arr[i], dst = p.copy(dst)
+ }
+ }
+ return ret, dst
+}
+
+// Get returns value by key and flag about existence such value.
+func (p *Parameters) Get(key string) (value []byte, ok bool) {
+ for _, v := range p.data() {
+ if string(v.key) == key {
+ return v.value, true
+ }
+ }
+ return nil, false
+}
+
+// Set sets value by key.
+func (p *Parameters) Set(key, value []byte) {
+ p.bytes += len(key) + len(value)
+
+ if p.pos < len(p.arr) {
+ p.arr[p.pos] = pair{key, value}
+ p.pos++
+ return
+ }
+
+ if p.dyn == nil {
+ p.dyn = make([]pair, len(p.arr), len(p.arr)+1)
+ copy(p.dyn, p.arr[:])
+ }
+ p.dyn = append(p.dyn, pair{key, value})
+}
+
+// ForEach iterates over parameters key-value pairs and calls cb for each one.
+func (p *Parameters) ForEach(cb func(k, v []byte) bool) {
+ for _, v := range p.data() {
+ if !cb(v.key, v.value) {
+ break
+ }
+ }
+}
+
+// String represents parameters as a string.
+func (p *Parameters) String() (ret string) {
+ ret = "["
+ for i, v := range p.data() {
+ if i > 0 {
+ ret += " "
+ }
+ ret += string(v.key) + ":" + string(v.value)
+ }
+ return ret + "]"
+}
+
+func (p *Parameters) data() []pair {
+ if p.dyn != nil {
+ return p.dyn
+ }
+ return p.arr[:p.pos]
+}
+
+type pair struct {
+ key, value []byte
+}
+
+func (p pair) copy(dst []byte) (pair, []byte) {
+ n := copy(dst, p.key)
+ p.key = dst[:n]
+ m := n + copy(dst[n:], p.value)
+ p.value = dst[n:m]
+
+ dst = dst[m:]
+
+ return p, dst
+}
+
+type pairs []pair
+
+func (p pairs) Len() int { return len(p) }
+func (p pairs) Less(a, b int) bool { return bytes.Compare(p[a].key, p[b].key) == -1 }
+func (p pairs) Swap(a, b int) { p[a], p[b] = p[b], p[a] }
diff --git a/vendor/github.com/gobwas/httphead/writer.go b/vendor/github.com/gobwas/httphead/writer.go
new file mode 100644
index 0000000..e5df3dd
--- /dev/null
+++ b/vendor/github.com/gobwas/httphead/writer.go
@@ -0,0 +1,101 @@
+package httphead
+
+import "io"
+
+var (
+ comma = []byte{','}
+ equality = []byte{'='}
+ semicolon = []byte{';'}
+ quote = []byte{'"'}
+ escape = []byte{'\\'}
+)
+
+// WriteOptions write options list to the dest.
+// It uses the same form as {Scan,Parse}Options functions:
+// values = 1#value
+// value = token *( ";" param )
+// param = token [ "=" (token | quoted-string) ]
+//
+// It wraps valuse into the quoted-string sequence if it contains any
+// non-token characters.
+func WriteOptions(dest io.Writer, options []Option) (n int, err error) {
+ w := writer{w: dest}
+ for i, opt := range options {
+ if i > 0 {
+ w.write(comma)
+ }
+
+ writeTokenSanitized(&w, opt.Name)
+
+ for _, p := range opt.Parameters.data() {
+ w.write(semicolon)
+ writeTokenSanitized(&w, p.key)
+ if len(p.value) != 0 {
+ w.write(equality)
+ writeTokenSanitized(&w, p.value)
+ }
+ }
+ }
+ return w.result()
+}
+
+// writeTokenSanitized writes token as is or as quouted string if it contains
+// non-token characters.
+//
+// Note that is is not expects LWS sequnces be in s, cause LWS is used only as
+// header field continuation:
+// "A CRLF is allowed in the definition of TEXT only as part of a header field
+// continuation. It is expected that the folding LWS will be replaced with a
+// single SP before interpretation of the TEXT value."
+// See https://tools.ietf.org/html/rfc2616#section-2
+//
+// That is we sanitizing s for writing, so there could not be any header field
+// continuation.
+// That is any CRLF will be escaped as any other control characters not allowd in TEXT.
+func writeTokenSanitized(bw *writer, bts []byte) {
+ var qt bool
+ var pos int
+ for i := 0; i < len(bts); i++ {
+ c := bts[i]
+ if !OctetTypes[c].IsToken() && !qt {
+ qt = true
+ bw.write(quote)
+ }
+ if OctetTypes[c].IsControl() || c == '"' {
+ if !qt {
+ qt = true
+ bw.write(quote)
+ }
+ bw.write(bts[pos:i])
+ bw.write(escape)
+ bw.write(bts[i : i+1])
+ pos = i + 1
+ }
+ }
+ if !qt {
+ bw.write(bts)
+ } else {
+ bw.write(bts[pos:])
+ bw.write(quote)
+ }
+}
+
+type writer struct {
+ w io.Writer
+ n int
+ err error
+}
+
+func (w *writer) write(p []byte) {
+ if w.err != nil {
+ return
+ }
+ var n int
+ n, w.err = w.w.Write(p)
+ w.n += n
+ return
+}
+
+func (w *writer) result() (int, error) {
+ return w.n, w.err
+}
diff --git a/vendor/github.com/gobwas/pool/LICENSE b/vendor/github.com/gobwas/pool/LICENSE
new file mode 100644
index 0000000..c41ffde
--- /dev/null
+++ b/vendor/github.com/gobwas/pool/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2017-2019 Sergey Kamardin
+
+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/gobwas/pool/README.md b/vendor/github.com/gobwas/pool/README.md
new file mode 100644
index 0000000..4568558
--- /dev/null
+++ b/vendor/github.com/gobwas/pool/README.md
@@ -0,0 +1,107 @@
+# pool
+
+[![GoDoc][godoc-image]][godoc-url]
+
+> Tiny memory reuse helpers for Go.
+
+## generic
+
+Without use of subpackages, `pool` allows to reuse any struct distinguishable
+by size in generic way:
+
+```go
+package main
+
+import "github.com/gobwas/pool"
+
+func main() {
+ x, n := pool.Get(100) // Returns object with size 128 or nil.
+ if x == nil {
+ // Create x somehow with knowledge that n is 128.
+ }
+ defer pool.Put(x, n)
+
+ // Work with x.
+}
+```
+
+Pool allows you to pass specific options for constructing custom pool:
+
+```go
+package main
+
+import "github.com/gobwas/pool"
+
+func main() {
+ p := pool.Custom(
+ pool.WithLogSizeMapping(), // Will ceil size n passed to Get(n) to nearest power of two.
+ pool.WithLogSizeRange(64, 512), // Will reuse objects in logarithmic range [64, 512].
+ pool.WithSize(65536), // Will reuse object with size 65536.
+ )
+ x, n := p.Get(1000) // Returns nil and 1000 because mapped size 1000 => 1024 is not reusing by the pool.
+ defer pool.Put(x, n) // Will not reuse x.
+
+ // Work with x.
+}
+```
+
+Note that there are few non-generic pooling implementations inside subpackages.
+
+## pbytes
+
+Subpackage `pbytes` is intended for `[]byte` reuse.
+
+```go
+package main
+
+import "github.com/gobwas/pool/pbytes"
+
+func main() {
+ bts := pbytes.GetCap(100) // Returns make([]byte, 0, 128).
+ defer pbytes.Put(bts)
+
+ // Work with bts.
+}
+```
+
+You can also create your own range for pooling:
+
+```go
+package main
+
+import "github.com/gobwas/pool/pbytes"
+
+func main() {
+ // Reuse only slices whose capacity is 128, 256, 512 or 1024.
+ pool := pbytes.New(128, 1024)
+
+ bts := pool.GetCap(100) // Returns make([]byte, 0, 128).
+ defer pool.Put(bts)
+
+ // Work with bts.
+}
+```
+
+## pbufio
+
+Subpackage `pbufio` is intended for `*bufio.{Reader, Writer}` reuse.
+
+```go
+package main
+
+import "github.com/gobwas/pool/pbufio"
+
+func main() {
+ bw := pbufio.GetWriter(os.Stdout, 100) // Returns bufio.NewWriterSize(128).
+ defer pbufio.PutWriter(bw)
+
+ // Work with bw.
+}
+```
+
+Like with `pbytes`, you can also create pool with custom reuse bounds.
+
+
+
+[godoc-image]: https://godoc.org/github.com/gobwas/pool?status.svg
+[godoc-url]: https://godoc.org/github.com/gobwas/pool
diff --git a/vendor/github.com/gobwas/pool/generic.go b/vendor/github.com/gobwas/pool/generic.go
new file mode 100644
index 0000000..d40b362
--- /dev/null
+++ b/vendor/github.com/gobwas/pool/generic.go
@@ -0,0 +1,87 @@
+package pool
+
+import (
+ "sync"
+
+ "github.com/gobwas/pool/internal/pmath"
+)
+
+var DefaultPool = New(128, 65536)
+
+// Get pulls object whose generic size is at least of given size. It also
+// returns a real size of x for further pass to Put(). It returns -1 as real
+// size for nil x. Size >-1 does not mean that x is non-nil, so checks must be
+// done.
+//
+// Note that size could be ceiled to the next power of two.
+//
+// Get is a wrapper around DefaultPool.Get().
+func Get(size int) (interface{}, int) { return DefaultPool.Get(size) }
+
+// Put takes x and its size for future reuse.
+// Put is a wrapper around DefaultPool.Put().
+func Put(x interface{}, size int) { DefaultPool.Put(x, size) }
+
+// Pool contains logic of reusing objects distinguishable by size in generic
+// way.
+type Pool struct {
+ pool map[int]*sync.Pool
+ size func(int) int
+}
+
+// New creates new Pool that reuses objects which size is in logarithmic range
+// [min, max].
+//
+// Note that it is a shortcut for Custom() constructor with Options provided by
+// WithLogSizeMapping() and WithLogSizeRange(min, max) calls.
+func New(min, max int) *Pool {
+ return Custom(
+ WithLogSizeMapping(),
+ WithLogSizeRange(min, max),
+ )
+}
+
+// Custom creates new Pool with given options.
+func Custom(opts ...Option) *Pool {
+ p := &Pool{
+ pool: make(map[int]*sync.Pool),
+ size: pmath.Identity,
+ }
+
+ c := (*poolConfig)(p)
+ for _, opt := range opts {
+ opt(c)
+ }
+
+ return p
+}
+
+// Get pulls object whose generic size is at least of given size.
+// It also returns a real size of x for further pass to Put() even if x is nil.
+// Note that size could be ceiled to the next power of two.
+func (p *Pool) Get(size int) (interface{}, int) {
+ n := p.size(size)
+ if pool := p.pool[n]; pool != nil {
+ return pool.Get(), n
+ }
+ return nil, size
+}
+
+// Put takes x and its size for future reuse.
+func (p *Pool) Put(x interface{}, size int) {
+ if pool := p.pool[size]; pool != nil {
+ pool.Put(x)
+ }
+}
+
+type poolConfig Pool
+
+// AddSize adds size n to the map.
+func (p *poolConfig) AddSize(n int) {
+ p.pool[n] = new(sync.Pool)
+}
+
+// SetSizeMapping sets up incoming size mapping function.
+func (p *poolConfig) SetSizeMapping(size func(int) int) {
+ p.size = size
+}
diff --git a/vendor/github.com/gobwas/pool/internal/pmath/pmath.go b/vendor/github.com/gobwas/pool/internal/pmath/pmath.go
new file mode 100644
index 0000000..df152ed
--- /dev/null
+++ b/vendor/github.com/gobwas/pool/internal/pmath/pmath.go
@@ -0,0 +1,65 @@
+package pmath
+
+const (
+ bitsize = 32 << (^uint(0) >> 63)
+ maxint = int(1<<(bitsize-1) - 1)
+ maxintHeadBit = 1 << (bitsize - 2)
+)
+
+// LogarithmicRange iterates from ceiled to power of two min to max,
+// calling cb on each iteration.
+func LogarithmicRange(min, max int, cb func(int)) {
+ if min == 0 {
+ min = 1
+ }
+ for n := CeilToPowerOfTwo(min); n <= max; n <<= 1 {
+ cb(n)
+ }
+}
+
+// IsPowerOfTwo reports whether given integer is a power of two.
+func IsPowerOfTwo(n int) bool {
+ return n&(n-1) == 0
+}
+
+// Identity is identity.
+func Identity(n int) int {
+ return n
+}
+
+// CeilToPowerOfTwo returns the least power of two integer value greater than
+// or equal to n.
+func CeilToPowerOfTwo(n int) int {
+ if n&maxintHeadBit != 0 && n > maxintHeadBit {
+ panic("argument is too large")
+ }
+ if n <= 2 {
+ return n
+ }
+ n--
+ n = fillBits(n)
+ n++
+ return n
+}
+
+// FloorToPowerOfTwo returns the greatest power of two integer value less than
+// or equal to n.
+func FloorToPowerOfTwo(n int) int {
+ if n <= 2 {
+ return n
+ }
+ n = fillBits(n)
+ n >>= 1
+ n++
+ return n
+}
+
+func fillBits(n int) int {
+ n |= n >> 1
+ n |= n >> 2
+ n |= n >> 4
+ n |= n >> 8
+ n |= n >> 16
+ n |= n >> 32
+ return n
+}
diff --git a/vendor/github.com/gobwas/pool/option.go b/vendor/github.com/gobwas/pool/option.go
new file mode 100644
index 0000000..d6e42b7
--- /dev/null
+++ b/vendor/github.com/gobwas/pool/option.go
@@ -0,0 +1,43 @@
+package pool
+
+import "github.com/gobwas/pool/internal/pmath"
+
+// Option configures pool.
+type Option func(Config)
+
+// Config describes generic pool configuration.
+type Config interface {
+ AddSize(n int)
+ SetSizeMapping(func(int) int)
+}
+
+// WithSizeLogRange returns an Option that will add logarithmic range of
+// pooling sizes containing [min, max] values.
+func WithLogSizeRange(min, max int) Option {
+ return func(c Config) {
+ pmath.LogarithmicRange(min, max, func(n int) {
+ c.AddSize(n)
+ })
+ }
+}
+
+// WithSize returns an Option that will add given pooling size to the pool.
+func WithSize(n int) Option {
+ return func(c Config) {
+ c.AddSize(n)
+ }
+}
+
+func WithSizeMapping(sz func(int) int) Option {
+ return func(c Config) {
+ c.SetSizeMapping(sz)
+ }
+}
+
+func WithLogSizeMapping() Option {
+ return WithSizeMapping(pmath.CeilToPowerOfTwo)
+}
+
+func WithIdentitySizeMapping() Option {
+ return WithSizeMapping(pmath.Identity)
+}
diff --git a/vendor/github.com/gobwas/pool/pbufio/pbufio.go b/vendor/github.com/gobwas/pool/pbufio/pbufio.go
new file mode 100644
index 0000000..d526bd8
--- /dev/null
+++ b/vendor/github.com/gobwas/pool/pbufio/pbufio.go
@@ -0,0 +1,106 @@
+// Package pbufio contains tools for pooling bufio.Reader and bufio.Writers.
+package pbufio
+
+import (
+ "bufio"
+ "io"
+
+ "github.com/gobwas/pool"
+)
+
+var (
+ DefaultWriterPool = NewWriterPool(256, 65536)
+ DefaultReaderPool = NewReaderPool(256, 65536)
+)
+
+// GetWriter returns bufio.Writer whose buffer has at least size bytes.
+// Note that size could be ceiled to the next power of two.
+// GetWriter is a wrapper around DefaultWriterPool.Get().
+func GetWriter(w io.Writer, size int) *bufio.Writer { return DefaultWriterPool.Get(w, size) }
+
+// PutWriter takes bufio.Writer for future reuse.
+// It does not reuse bufio.Writer which underlying buffer size is not power of
+// PutWriter is a wrapper around DefaultWriterPool.Put().
+func PutWriter(bw *bufio.Writer) { DefaultWriterPool.Put(bw) }
+
+// GetReader returns bufio.Reader whose buffer has at least size bytes. It returns
+// its capacity for further pass to Put().
+// Note that size could be ceiled to the next power of two.
+// GetReader is a wrapper around DefaultReaderPool.Get().
+func GetReader(w io.Reader, size int) *bufio.Reader { return DefaultReaderPool.Get(w, size) }
+
+// PutReader takes bufio.Reader and its size for future reuse.
+// It does not reuse bufio.Reader if size is not power of two or is out of pool
+// min/max range.
+// PutReader is a wrapper around DefaultReaderPool.Put().
+func PutReader(bw *bufio.Reader) { DefaultReaderPool.Put(bw) }
+
+// WriterPool contains logic of *bufio.Writer reuse with various size.
+type WriterPool struct {
+ pool *pool.Pool
+}
+
+// NewWriterPool creates new WriterPool that reuses writers which size is in
+// logarithmic range [min, max].
+func NewWriterPool(min, max int) *WriterPool {
+ return &WriterPool{pool.New(min, max)}
+}
+
+// CustomWriterPool creates new WriterPool with given options.
+func CustomWriterPool(opts ...pool.Option) *WriterPool {
+ return &WriterPool{pool.Custom(opts...)}
+}
+
+// Get returns bufio.Writer whose buffer has at least size bytes.
+func (wp *WriterPool) Get(w io.Writer, size int) *bufio.Writer {
+ v, n := wp.pool.Get(size)
+ if v != nil {
+ bw := v.(*bufio.Writer)
+ bw.Reset(w)
+ return bw
+ }
+ return bufio.NewWriterSize(w, n)
+}
+
+// Put takes ownership of bufio.Writer for further reuse.
+func (wp *WriterPool) Put(bw *bufio.Writer) {
+ // Should reset even if we do Reset() inside Get().
+ // This is done to prevent locking underlying io.Writer from GC.
+ bw.Reset(nil)
+ wp.pool.Put(bw, writerSize(bw))
+}
+
+// ReaderPool contains logic of *bufio.Reader reuse with various size.
+type ReaderPool struct {
+ pool *pool.Pool
+}
+
+// NewReaderPool creates new ReaderPool that reuses writers which size is in
+// logarithmic range [min, max].
+func NewReaderPool(min, max int) *ReaderPool {
+ return &ReaderPool{pool.New(min, max)}
+}
+
+// CustomReaderPool creates new ReaderPool with given options.
+func CustomReaderPool(opts ...pool.Option) *ReaderPool {
+ return &ReaderPool{pool.Custom(opts...)}
+}
+
+// Get returns bufio.Reader whose buffer has at least size bytes.
+func (rp *ReaderPool) Get(r io.Reader, size int) *bufio.Reader {
+ v, n := rp.pool.Get(size)
+ if v != nil {
+ br := v.(*bufio.Reader)
+ br.Reset(r)
+ return br
+ }
+ return bufio.NewReaderSize(r, n)
+}
+
+// Put takes ownership of bufio.Reader for further reuse.
+func (rp *ReaderPool) Put(br *bufio.Reader) {
+ // Should reset even if we do Reset() inside Get().
+ // This is done to prevent locking underlying io.Reader from GC.
+ br.Reset(nil)
+ rp.pool.Put(br, readerSize(br))
+}
diff --git a/vendor/github.com/gobwas/pool/pbufio/pbufio_go110.go b/vendor/github.com/gobwas/pool/pbufio/pbufio_go110.go
new file mode 100644
index 0000000..c736ae5
--- /dev/null
+++ b/vendor/github.com/gobwas/pool/pbufio/pbufio_go110.go
@@ -0,0 +1,13 @@
+// +build go1.10
+
+package pbufio
+
+import "bufio"
+
+func writerSize(bw *bufio.Writer) int {
+ return bw.Size()
+}
+
+func readerSize(br *bufio.Reader) int {
+ return br.Size()
+}
diff --git a/vendor/github.com/gobwas/pool/pbufio/pbufio_go19.go b/vendor/github.com/gobwas/pool/pbufio/pbufio_go19.go
new file mode 100644
index 0000000..e71dd44
--- /dev/null
+++ b/vendor/github.com/gobwas/pool/pbufio/pbufio_go19.go
@@ -0,0 +1,27 @@
+// +build !go1.10
+
+package pbufio
+
+import "bufio"
+
+func writerSize(bw *bufio.Writer) int {
+ return bw.Available() + bw.Buffered()
+}
+
+// readerSize returns buffer size of the given buffered reader.
+// NOTE: current workaround implementation resets underlying io.Reader.
+func readerSize(br *bufio.Reader) int {
+ br.Reset(sizeReader)
+ br.ReadByte()
+ n := br.Buffered() + 1
+ br.Reset(nil)
+ return n
+}
+
+var sizeReader optimisticReader
+
+type optimisticReader struct{}
+
+func (optimisticReader) Read(p []byte) (int, error) {
+ return len(p), nil
+}
diff --git a/vendor/github.com/gobwas/pool/pbytes/pbytes.go b/vendor/github.com/gobwas/pool/pbytes/pbytes.go
new file mode 100644
index 0000000..919705b
--- /dev/null
+++ b/vendor/github.com/gobwas/pool/pbytes/pbytes.go
@@ -0,0 +1,24 @@
+// Package pbytes contains tools for pooling byte pool.
+// Note that by default it reuse slices with capacity from 128 to 65536 bytes.
+package pbytes
+
+// DefaultPool is used by pacakge level functions.
+var DefaultPool = New(128, 65536)
+
+// Get returns probably reused slice of bytes with at least capacity of c and
+// exactly len of n.
+// Get is a wrapper around DefaultPool.Get().
+func Get(n, c int) []byte { return DefaultPool.Get(n, c) }
+
+// GetCap returns probably reused slice of bytes with at least capacity of n.
+// GetCap is a wrapper around DefaultPool.GetCap().
+func GetCap(c int) []byte { return DefaultPool.GetCap(c) }
+
+// GetLen returns probably reused slice of bytes with at least capacity of n
+// and exactly len of n.
+// GetLen is a wrapper around DefaultPool.GetLen().
+func GetLen(n int) []byte { return DefaultPool.GetLen(n) }
+
+// Put returns given slice to reuse pool.
+// Put is a wrapper around DefaultPool.Put().
+func Put(p []byte) { DefaultPool.Put(p) }
diff --git a/vendor/github.com/gobwas/pool/pbytes/pool.go b/vendor/github.com/gobwas/pool/pbytes/pool.go
new file mode 100644
index 0000000..1dde225
--- /dev/null
+++ b/vendor/github.com/gobwas/pool/pbytes/pool.go
@@ -0,0 +1,59 @@
+// +build !pool_sanitize
+
+package pbytes
+
+import "github.com/gobwas/pool"
+
+// Pool contains logic of reusing byte slices of various size.
+type Pool struct {
+ pool *pool.Pool
+}
+
+// New creates new Pool that reuses slices which size is in logarithmic range
+// [min, max].
+//
+// Note that it is a shortcut for Custom() constructor with Options provided by
+// pool.WithLogSizeMapping() and pool.WithLogSizeRange(min, max) calls.
+func New(min, max int) *Pool {
+ return &Pool{pool.New(min, max)}
+}
+
+// New creates new Pool with given options.
+func Custom(opts ...pool.Option) *Pool {
+ return &Pool{pool.Custom(opts...)}
+}
+
+// Get returns probably reused slice of bytes with at least capacity of c and
+// exactly len of n.
+func (p *Pool) Get(n, c int) []byte {
+ if n > c {
+ panic("requested length is greater than capacity")
+ }
+
+ v, x := p.pool.Get(c)
+ if v != nil {
+ bts := v.([]byte)
+ bts = bts[:n]
+ return bts
+ }
+
+ return make([]byte, n, x)
+}
+
+// Put returns given slice to reuse pool.
+// It does not reuse bytes whose size is not power of two or is out of pool
+// min/max range.
+func (p *Pool) Put(bts []byte) {
+ p.pool.Put(bts, cap(bts))
+}
+
+// GetCap returns probably reused slice of bytes with at least capacity of n.
+func (p *Pool) GetCap(c int) []byte {
+ return p.Get(0, c)
+}
+
+// GetLen returns probably reused slice of bytes with at least capacity of n
+// and exactly len of n.
+func (p *Pool) GetLen(n int) []byte {
+ return p.Get(n, n)
+}
diff --git a/vendor/github.com/gobwas/pool/pbytes/pool_sanitize.go b/vendor/github.com/gobwas/pool/pbytes/pool_sanitize.go
new file mode 100644
index 0000000..fae9af4
--- /dev/null
+++ b/vendor/github.com/gobwas/pool/pbytes/pool_sanitize.go
@@ -0,0 +1,121 @@
+// +build pool_sanitize
+
+package pbytes
+
+import (
+ "reflect"
+ "runtime"
+ "sync/atomic"
+ "syscall"
+ "unsafe"
+
+ "golang.org/x/sys/unix"
+)
+
+const magic = uint64(0x777742)
+
+type guard struct {
+ magic uint64
+ size int
+ owners int32
+}
+
+const guardSize = int(unsafe.Sizeof(guard{}))
+
+type Pool struct {
+ min, max int
+}
+
+func New(min, max int) *Pool {
+ return &Pool{min, max}
+}
+
+// Get returns probably reused slice of bytes with at least capacity of c and
+// exactly len of n.
+func (p *Pool) Get(n, c int) []byte {
+ if n > c {
+ panic("requested length is greater than capacity")
+ }
+
+ pageSize := syscall.Getpagesize()
+ pages := (c+guardSize)/pageSize + 1
+ size := pages * pageSize
+
+ bts := alloc(size)
+
+ g := (*guard)(unsafe.Pointer(&bts[0]))
+ *g = guard{
+ magic: magic,
+ size: size,
+ owners: 1,
+ }
+
+ return bts[guardSize : guardSize+n]
+}
+
+func (p *Pool) GetCap(c int) []byte { return p.Get(0, c) }
+func (p *Pool) GetLen(n int) []byte { return Get(n, n) }
+
+// Put returns given slice to reuse pool.
+func (p *Pool) Put(bts []byte) {
+ hdr := *(*reflect.SliceHeader)(unsafe.Pointer(&bts))
+ ptr := hdr.Data - uintptr(guardSize)
+
+ g := (*guard)(unsafe.Pointer(ptr))
+ if g.magic != magic {
+ panic("unknown slice returned to the pool")
+ }
+ if n := atomic.AddInt32(&g.owners, -1); n < 0 {
+ panic("multiple Put() detected")
+ }
+
+ // Disable read and write on bytes memory pages. This will cause panic on
+ // incorrect access to returned slice.
+ mprotect(ptr, false, false, g.size)
+
+ runtime.SetFinalizer(&bts, func(b *[]byte) {
+ mprotect(ptr, true, true, g.size)
+ free(*(*[]byte)(unsafe.Pointer(&reflect.SliceHeader{
+ Data: ptr,
+ Len: g.size,
+ Cap: g.size,
+ })))
+ })
+}
+
+func alloc(n int) []byte {
+ b, err := unix.Mmap(-1, 0, n, unix.PROT_READ|unix.PROT_WRITE|unix.PROT_EXEC, unix.MAP_SHARED|unix.MAP_ANONYMOUS)
+ if err != nil {
+ panic(err.Error())
+ }
+ return b
+}
+
+func free(b []byte) {
+ if err := unix.Munmap(b); err != nil {
+ panic(err.Error())
+ }
+}
+
+func mprotect(ptr uintptr, r, w bool, size int) {
+ // Need to avoid "EINVAL addr is not a valid pointer,
+ // or not a multiple of PAGESIZE."
+ start := ptr & ^(uintptr(syscall.Getpagesize() - 1))
+
+ prot := uintptr(syscall.PROT_EXEC)
+ switch {
+ case r && w:
+ prot |= syscall.PROT_READ | syscall.PROT_WRITE
+ case r:
+ prot |= syscall.PROT_READ
+ case w:
+ prot |= syscall.PROT_WRITE
+ }
+
+ _, _, err := syscall.Syscall(syscall.SYS_MPROTECT,
+ start, uintptr(size), prot,
+ )
+ if err != 0 {
+ panic(err.Error())
+ }
+}
diff --git a/vendor/github.com/gobwas/pool/pool.go b/vendor/github.com/gobwas/pool/pool.go
new file mode 100644
index 0000000..1fe9e60
--- /dev/null
+++ b/vendor/github.com/gobwas/pool/pool.go
@@ -0,0 +1,25 @@
+// Package pool contains helpers for pooling structures distinguishable by
+// size.
+//
+// Quick example:
+//
+// import "github.com/gobwas/pool"
+//
+// func main() {
+// // Reuse objects in logarithmic range from 0 to 64 (0,1,2,4,6,8,16,32,64).
+// p := pool.New(0, 64)
+//
+// buf, n := p.Get(10) // Returns buffer with 16 capacity.
+// if buf == nil {
+// buf = bytes.NewBuffer(make([]byte, n))
+// }
+// defer p.Put(buf, n)
+//
+// // Work with buf.
+// }
+//
+// There are non-generic implementations for pooling:
+// - pool/pbytes for []byte reuse;
+// - pool/pbufio for *bufio.Reader and *bufio.Writer reuse;
+//
+package pool
diff --git a/vendor/github.com/gobwas/ws/.gitignore b/vendor/github.com/gobwas/ws/.gitignore
new file mode 100644
index 0000000..e3e2b10
--- /dev/null
+++ b/vendor/github.com/gobwas/ws/.gitignore
@@ -0,0 +1,5 @@
+bin/
+reports/
+cpu.out
+mem.out
+ws.test
diff --git a/vendor/github.com/gobwas/ws/LICENSE b/vendor/github.com/gobwas/ws/LICENSE
new file mode 100644
index 0000000..ca6dfd9
--- /dev/null
+++ b/vendor/github.com/gobwas/ws/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2017-2021 Sergey Kamardin
+
+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/gobwas/ws/Makefile b/vendor/github.com/gobwas/ws/Makefile
new file mode 100644
index 0000000..6d89f78
--- /dev/null
+++ b/vendor/github.com/gobwas/ws/Makefile
@@ -0,0 +1,54 @@
+BENCH ?=.
+BENCH_BASE?=master
+
+clean:
+ rm -f bin/reporter
+ rm -fr autobahn/report/*
+
+bin/reporter:
+ go build -o bin/reporter ./autobahn
+
+bin/gocovmerge:
+ go build -o bin/gocovmerge github.com/wadey/gocovmerge
+
+.PHONY: autobahn
+autobahn: clean bin/reporter
+ ./autobahn/script/test.sh --build --follow-logs
+ bin/reporter $(PWD)/autobahn/report/index.json
+
+.PHONY: autobahn/report
+autobahn/report: bin/reporter
+ ./bin/reporter -http localhost:5555 ./autobahn/report/index.json
+
+test:
+ go test -coverprofile=ws.coverage .
+ go test -coverprofile=wsutil.coverage ./wsutil
+ go test -coverprofile=wsfalte.coverage ./wsflate
+ # No statements to cover in ./tests (there are only tests).
+ go test ./tests
+
+cover: bin/gocovmerge test autobahn
+ bin/gocovmerge ws.coverage wsutil.coverage wsflate.coverage autobahn/report/server.coverage > total.coverage
+
+benchcmp: BENCH_BRANCH=$(shell git rev-parse --abbrev-ref HEAD)
+benchcmp: BENCH_OLD:=$(shell mktemp -t old.XXXX)
+benchcmp: BENCH_NEW:=$(shell mktemp -t new.XXXX)
+benchcmp:
+ if [ ! -z "$(shell git status -s)" ]; then\
+ echo "could not compare with $(BENCH_BASE) – found unstaged changes";\
+ exit 1;\
+ fi;\
+ if [ "$(BENCH_BRANCH)" == "$(BENCH_BASE)" ]; then\
+ echo "comparing the same branches";\
+ exit 1;\
+ fi;\
+ echo "benchmarking $(BENCH_BRANCH)...";\
+ go test -run=none -bench=$(BENCH) -benchmem > $(BENCH_NEW);\
+ echo "benchmarking $(BENCH_BASE)...";\
+ git checkout -q $(BENCH_BASE);\
+ go test -run=none -bench=$(BENCH) -benchmem > $(BENCH_OLD);\
+ git checkout -q $(BENCH_BRANCH);\
+ echo "\nresults:";\
+ echo "========\n";\
+ benchcmp $(BENCH_OLD) $(BENCH_NEW);\
+
diff --git a/vendor/github.com/gobwas/ws/README.md b/vendor/github.com/gobwas/ws/README.md
new file mode 100644
index 0000000..0bd0f6b
--- /dev/null
+++ b/vendor/github.com/gobwas/ws/README.md
@@ -0,0 +1,541 @@
+# ws
+
+[![GoDoc][godoc-image]][godoc-url]
+[![CI][ci-badge]][ci-url]
+
+> [RFC6455][rfc-url] WebSocket implementation in Go.
+
+# Features
+
+- Zero-copy upgrade
+- No intermediate allocations during I/O
+- Low-level API which allows to build your own logic of packet handling and
+ buffers reuse
+- High-level wrappers and helpers around API in `wsutil` package, which allow
+ to start fast without digging the protocol internals
+
+# Documentation
+
+[GoDoc][godoc-url].
+
+# Why
+
+Existing WebSocket implementations do not allow users to reuse I/O buffers
+between connections in clear way. This library aims to export efficient
+low-level interface for working with the protocol without forcing only one way
+it could be used.
+
+By the way, if you want get the higher-level tools, you can use `wsutil`
+package.
+
+# Status
+
+Library is tagged as `v1*` so its API must not be broken during some
+improvements or refactoring.
+
+This implementation of RFC6455 passes [Autobahn Test
+Suite](https://github.com/crossbario/autobahn-testsuite) and currently has
+about 78% coverage.
+
+# Examples
+
+Example applications using `ws` are developed in separate repository
+[ws-examples](https://github.com/gobwas/ws-examples).
+
+# Usage
+
+The higher-level example of WebSocket echo server:
+
+```go
+package main
+
+import (
+ "net/http"
+
+ "github.com/gobwas/ws"
+ "github.com/gobwas/ws/wsutil"
+)
+
+func main() {
+ http.ListenAndServe(":8080", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ conn, _, _, err := ws.UpgradeHTTP(r, w)
+ if err != nil {
+ // handle error
+ }
+ go func() {
+ defer conn.Close()
+
+ for {
+ msg, op, err := wsutil.ReadClientData(conn)
+ if err != nil {
+ // handle error
+ }
+ err = wsutil.WriteServerMessage(conn, op, msg)
+ if err != nil {
+ // handle error
+ }
+ }
+ }()
+ }))
+}
+```
+
+Lower-level, but still high-level example:
+
+
+```go
+import (
+ "net/http"
+ "io"
+
+ "github.com/gobwas/ws"
+ "github.com/gobwas/ws/wsutil"
+)
+
+func main() {
+ http.ListenAndServe(":8080", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ conn, _, _, err := ws.UpgradeHTTP(r, w)
+ if err != nil {
+ // handle error
+ }
+ go func() {
+ defer conn.Close()
+
+ var (
+ state = ws.StateServerSide
+ reader = wsutil.NewReader(conn, state)
+ writer = wsutil.NewWriter(conn, state, ws.OpText)
+ )
+ for {
+ header, err := reader.NextFrame()
+ if err != nil {
+ // handle error
+ }
+
+ // Reset writer to write frame with right operation code.
+ writer.Reset(conn, state, header.OpCode)
+
+ if _, err = io.Copy(writer, reader); err != nil {
+ // handle error
+ }
+ if err = writer.Flush(); err != nil {
+ // handle error
+ }
+ }
+ }()
+ }))
+}
+```
+
+We can apply the same pattern to read and write structured responses through a JSON encoder and decoder.:
+
+```go
+ ...
+ var (
+ r = wsutil.NewReader(conn, ws.StateServerSide)
+ w = wsutil.NewWriter(conn, ws.StateServerSide, ws.OpText)
+ decoder = json.NewDecoder(r)
+ encoder = json.NewEncoder(w)
+ )
+ for {
+ hdr, err = r.NextFrame()
+ if err != nil {
+ return err
+ }
+ if hdr.OpCode == ws.OpClose {
+ return io.EOF
+ }
+ var req Request
+ if err := decoder.Decode(&req); err != nil {
+ return err
+ }
+ var resp Response
+ if err := encoder.Encode(&resp); err != nil {
+ return err
+ }
+ if err = w.Flush(); err != nil {
+ return err
+ }
+ }
+ ...
+```
+
+The lower-level example without `wsutil`:
+
+```go
+package main
+
+import (
+ "net"
+ "io"
+
+ "github.com/gobwas/ws"
+)
+
+func main() {
+ ln, err := net.Listen("tcp", "localhost:8080")
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ for {
+ conn, err := ln.Accept()
+ if err != nil {
+ // handle error
+ }
+ _, err = ws.Upgrade(conn)
+ if err != nil {
+ // handle error
+ }
+
+ go func() {
+ defer conn.Close()
+
+ for {
+ header, err := ws.ReadHeader(conn)
+ if err != nil {
+ // handle error
+ }
+
+ payload := make([]byte, header.Length)
+ _, err = io.ReadFull(conn, payload)
+ if err != nil {
+ // handle error
+ }
+ if header.Masked {
+ ws.Cipher(payload, header.Mask, 0)
+ }
+
+ // Reset the Masked flag, server frames must not be masked as
+ // RFC6455 says.
+ header.Masked = false
+
+ if err := ws.WriteHeader(conn, header); err != nil {
+ // handle error
+ }
+ if _, err := conn.Write(payload); err != nil {
+ // handle error
+ }
+
+ if header.OpCode == ws.OpClose {
+ return
+ }
+ }
+ }()
+ }
+}
+```
+
+# Zero-copy upgrade
+
+Zero-copy upgrade helps to avoid unnecessary allocations and copying while
+handling HTTP Upgrade request.
+
+Processing of all non-websocket headers is made in place with use of registered
+user callbacks whose arguments are only valid until callback returns.
+
+The simple example looks like this:
+
+```go
+package main
+
+import (
+ "net"
+ "log"
+
+ "github.com/gobwas/ws"
+)
+
+func main() {
+ ln, err := net.Listen("tcp", "localhost:8080")
+ if err != nil {
+ log.Fatal(err)
+ }
+ u := ws.Upgrader{
+ OnHeader: func(key, value []byte) (err error) {
+ log.Printf("non-websocket header: %q=%q", key, value)
+ return
+ },
+ }
+ for {
+ conn, err := ln.Accept()
+ if err != nil {
+ // handle error
+ }
+
+ _, err = u.Upgrade(conn)
+ if err != nil {
+ // handle error
+ }
+ }
+}
+```
+
+Usage of `ws.Upgrader` here brings ability to control incoming connections on
+tcp level and simply not to accept them by some logic.
+
+Zero-copy upgrade is for high-load services which have to control many
+resources such as connections buffers.
+
+The real life example could be like this:
+
+```go
+package main
+
+import (
+ "fmt"
+ "io"
+ "log"
+ "net"
+ "net/http"
+ "runtime"
+
+ "github.com/gobwas/httphead"
+ "github.com/gobwas/ws"
+)
+
+func main() {
+ ln, err := net.Listen("tcp", "localhost:8080")
+ if err != nil {
+ // handle error
+ }
+
+ // Prepare handshake header writer from http.Header mapping.
+ header := ws.HandshakeHeaderHTTP(http.Header{
+ "X-Go-Version": []string{runtime.Version()},
+ })
+
+ u := ws.Upgrader{
+ OnHost: func(host []byte) error {
+ if string(host) == "github.com" {
+ return nil
+ }
+ return ws.RejectConnectionError(
+ ws.RejectionStatus(403),
+ ws.RejectionHeader(ws.HandshakeHeaderString(
+ "X-Want-Host: github.com\r\n",
+ )),
+ )
+ },
+ OnHeader: func(key, value []byte) error {
+ if string(key) != "Cookie" {
+ return nil
+ }
+ ok := httphead.ScanCookie(value, func(key, value []byte) bool {
+ // Check session here or do some other stuff with cookies.
+ // Maybe copy some values for future use.
+ return true
+ })
+ if ok {
+ return nil
+ }
+ return ws.RejectConnectionError(
+ ws.RejectionReason("bad cookie"),
+ ws.RejectionStatus(400),
+ )
+ },
+ OnBeforeUpgrade: func() (ws.HandshakeHeader, error) {
+ return header, nil
+ },
+ }
+ for {
+ conn, err := ln.Accept()
+ if err != nil {
+ log.Fatal(err)
+ }
+ _, err = u.Upgrade(conn)
+ if err != nil {
+ log.Printf("upgrade error: %s", err)
+ }
+ }
+}
+```
+
+# Compression
+
+There is a `ws/wsflate` package to support [Permessage-Deflate Compression
+Extension][rfc-pmce].
+
+It provides minimalistic I/O wrappers to be used in conjunction with any
+deflate implementation (for example, the standard library's
+[compress/flate][compress/flate]).
+
+It is also compatible with `wsutil`'s reader and writer by providing
+`wsflate.MessageState` type, which implements `wsutil.SendExtension` and
+`wsutil.RecvExtension` interfaces.
+
+```go
+package main
+
+import (
+ "bytes"
+ "log"
+ "net"
+
+ "github.com/gobwas/ws"
+ "github.com/gobwas/ws/wsflate"
+)
+
+func main() {
+ ln, err := net.Listen("tcp", "localhost:8080")
+ if err != nil {
+ // handle error
+ }
+ e := wsflate.Extension{
+ // We are using default parameters here since we use
+ // wsflate.{Compress,Decompress}Frame helpers below in the code.
+ // This assumes that we use standard compress/flate package as flate
+ // implementation.
+ Parameters: wsflate.DefaultParameters,
+ }
+ u := ws.Upgrader{
+ Negotiate: e.Negotiate,
+ }
+ for {
+ conn, err := ln.Accept()
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ // Reset extension after previous upgrades.
+ e.Reset()
+
+ _, err = u.Upgrade(conn)
+ if err != nil {
+ log.Printf("upgrade error: %s", err)
+ continue
+ }
+ if _, ok := e.Accepted(); !ok {
+ log.Printf("didn't negotiate compression for %s", conn.RemoteAddr())
+ conn.Close()
+ continue
+ }
+
+ go func() {
+ defer conn.Close()
+ for {
+ frame, err := ws.ReadFrame(conn)
+ if err != nil {
+ // Handle error.
+ return
+ }
+
+ frame = ws.UnmaskFrameInPlace(frame)
+
+ if wsflate.IsCompressed(frame.Header) {
+ // Note that even after successful negotiation of
+ // compression extension, both sides are able to send
+ // non-compressed messages.
+ frame, err = wsflate.DecompressFrame(frame)
+ if err != nil {
+ // Handle error.
+ return
+ }
+ }
+
+ // Do something with frame...
+
+ ack := ws.NewTextFrame([]byte("this is an acknowledgement"))
+
+ // Compress response unconditionally.
+ ack, err = wsflate.CompressFrame(ack)
+ if err != nil {
+ // Handle error.
+ return
+ }
+ if err = ws.WriteFrame(conn, ack); err != nil {
+ // Handle error.
+ return
+ }
+ }
+ }()
+ }
+}
+```
+
+You can use compression with `wsutil` package this way:
+
+```go
+ // Upgrade somehow and negotiate compression to get the conn...
+
+ // Initialize flate reader. We are using nil as a source io.Reader because
+ // we will Reset() it in the message i/o loop below.
+ fr := wsflate.NewReader(nil, func(r io.Reader) wsflate.Decompressor {
+ return flate.NewReader(r)
+ })
+ // Initialize flate writer. We are using nil as a destination io.Writer
+ // because we will Reset() it in the message i/o loop below.
+ fw := wsflate.NewWriter(nil, func(w io.Writer) wsflate.Compressor {
+ f, _ := flate.NewWriter(w, 9)
+ return f
+ })
+
+ // Declare compression message state variable.
+ //
+ // It has two goals:
+ // - Allow users to check whether received message is compressed or not.
+ // - Help wsutil.Reader and wsutil.Writer to set/unset appropriate
+ // WebSocket header bits while writing next frame to the wire (it
+ // implements wsutil.RecvExtension and wsutil.SendExtension).
+ var msg wsflate.MessageState
+
+ // Initialize WebSocket reader as previously.
+ // Please note the use of Reader.Extensions field as well as
+ // of ws.StateExtended flag.
+ rd := &wsutil.Reader{
+ Source: conn,
+ State: ws.StateServerSide | ws.StateExtended,
+ Extensions: []wsutil.RecvExtension{
+ &msg,
+ },
+ }
+
+ // Initialize WebSocket writer with ws.StateExtended flag as well.
+ wr := wsutil.NewWriter(conn, ws.StateServerSide|ws.StateExtended, 0)
+ // Use the message state as wsutil.SendExtension.
+ wr.SetExtensions(&msg)
+
+ for {
+ h, err := rd.NextFrame()
+ if err != nil {
+ // handle error.
+ }
+ if h.OpCode.IsControl() {
+ // handle control frame.
+ }
+ if !msg.IsCompressed() {
+ // handle uncompressed frame (skipped for the sake of example
+ // simplicity).
+ }
+
+ // Reset the writer to echo same op code.
+ wr.Reset(h.OpCode)
+
+ // Reset both flate reader and writer to start the new round of i/o.
+ fr.Reset(rd)
+ fw.Reset(wr)
+
+ // Copy whole message from reader to writer decompressing it and
+ // compressing again.
+ if _, err := io.Copy(fw, fr); err != nil {
+ // handle error.
+ }
+ // Flush any remaining buffers from flate writer to WebSocket writer.
+ if err := fw.Close(); err != nil {
+ // handle error.
+ }
+ // Flush the whole WebSocket message to the wire.
+ if err := wr.Flush(); err != nil {
+ // handle error.
+ }
+ }
+```
+
+
+[rfc-url]: https://tools.ietf.org/html/rfc6455
+[rfc-pmce]: https://tools.ietf.org/html/rfc7692#section-7
+[godoc-image]: https://godoc.org/github.com/gobwas/ws?status.svg
+[godoc-url]: https://godoc.org/github.com/gobwas/ws
+[compress/flate]: https://golang.org/pkg/compress/flate/
+[ci-badge]: https://github.com/gobwas/ws/workflows/CI/badge.svg
+[ci-url]: https://github.com/gobwas/ws/actions?query=workflow%3ACI
diff --git a/vendor/github.com/gobwas/ws/check.go b/vendor/github.com/gobwas/ws/check.go
new file mode 100644
index 0000000..8aa0df8
--- /dev/null
+++ b/vendor/github.com/gobwas/ws/check.go
@@ -0,0 +1,145 @@
+package ws
+
+import "unicode/utf8"
+
+// State represents state of websocket endpoint.
+// It used by some functions to be more strict when checking compatibility with RFC6455.
+type State uint8
+
+const (
+ // StateServerSide means that endpoint (caller) is a server.
+ StateServerSide State = 0x1 << iota
+ // StateClientSide means that endpoint (caller) is a client.
+ StateClientSide
+ // StateExtended means that extension was negotiated during handshake.
+ StateExtended
+ // StateFragmented means that endpoint (caller) has received fragmented
+ // frame and waits for continuation parts.
+ StateFragmented
+)
+
+// Is checks whether the s has v enabled.
+func (s State) Is(v State) bool {
+ return uint8(s)&uint8(v) != 0
+}
+
+// Set enables v state on s.
+func (s State) Set(v State) State {
+ return s | v
+}
+
+// Clear disables v state on s.
+func (s State) Clear(v State) State {
+ return s & (^v)
+}
+
+// ServerSide reports whether states represents server side.
+func (s State) ServerSide() bool { return s.Is(StateServerSide) }
+
+// ClientSide reports whether state represents client side.
+func (s State) ClientSide() bool { return s.Is(StateClientSide) }
+
+// Extended reports whether state is extended.
+func (s State) Extended() bool { return s.Is(StateExtended) }
+
+// Fragmented reports whether state is fragmented.
+func (s State) Fragmented() bool { return s.Is(StateFragmented) }
+
+// ProtocolError describes error during checking/parsing websocket frames or
+// headers.
+type ProtocolError string
+
+// Error implements error interface.
+func (p ProtocolError) Error() string { return string(p) }
+
+// Errors used by the protocol checkers.
+var (
+ ErrProtocolOpCodeReserved = ProtocolError("use of reserved op code")
+ ErrProtocolControlPayloadOverflow = ProtocolError("control frame payload limit exceeded")
+ ErrProtocolControlNotFinal = ProtocolError("control frame is not final")
+ ErrProtocolNonZeroRsv = ProtocolError("non-zero rsv bits with no extension negotiated")
+ ErrProtocolMaskRequired = ProtocolError("frames from client to server must be masked")
+ ErrProtocolMaskUnexpected = ProtocolError("frames from server to client must be not masked")
+ ErrProtocolContinuationExpected = ProtocolError("unexpected non-continuation data frame")
+ ErrProtocolContinuationUnexpected = ProtocolError("unexpected continuation data frame")
+ ErrProtocolStatusCodeNotInUse = ProtocolError("status code is not in use")
+ ErrProtocolStatusCodeApplicationLevel = ProtocolError("status code is only application level")
+ ErrProtocolStatusCodeNoMeaning = ProtocolError("status code has no meaning yet")
+ ErrProtocolStatusCodeUnknown = ProtocolError("status code is not defined in spec")
+ ErrProtocolInvalidUTF8 = ProtocolError("invalid utf8 sequence in close reason")
+)
+
+// CheckHeader checks h to contain valid header data for given state s.
+//
+// Note that zero state (0) means that state is clean,
+// neither server or client side, nor fragmented, nor extended.
+func CheckHeader(h Header, s State) error {
+ if h.OpCode.IsReserved() {
+ return ErrProtocolOpCodeReserved
+ }
+ if h.OpCode.IsControl() {
+ if h.Length > MaxControlFramePayloadSize {
+ return ErrProtocolControlPayloadOverflow
+ }
+ if !h.Fin {
+ return ErrProtocolControlNotFinal
+ }
+ }
+
+ switch {
+ // [RFC6455]: MUST be 0 unless an extension is negotiated that defines meanings for
+ // non-zero values. If a nonzero value is received and none of the
+ // negotiated extensions defines the meaning of such a nonzero value, the
+ // receiving endpoint MUST _Fail the WebSocket Connection_.
+ case h.Rsv != 0 && !s.Extended():
+ return ErrProtocolNonZeroRsv
+
+ // [RFC6455]: The server MUST close the connection upon receiving a frame that is not masked.
+ // In this case, a server MAY send a Close frame with a status code of 1002 (protocol error)
+ // as defined in Section 7.4.1. A server MUST NOT mask any frames that it sends to the client.
+ // A client MUST close a connection if it detects a masked frame. In this case, it MAY use the
+ // status code 1002 (protocol error) as defined in Section 7.4.1.
+ case s.ServerSide() && !h.Masked:
+ return ErrProtocolMaskRequired
+ case s.ClientSide() && h.Masked:
+ return ErrProtocolMaskUnexpected
+
+ // [RFC6455]: See detailed explanation in 5.4 section.
+ case s.Fragmented() && !h.OpCode.IsControl() && h.OpCode != OpContinuation:
+ return ErrProtocolContinuationExpected
+ case !s.Fragmented() && h.OpCode == OpContinuation:
+ return ErrProtocolContinuationUnexpected
+
+ default:
+ return nil
+ }
+}
+
+// CheckCloseFrameData checks received close information
+// to be valid RFC6455 compatible close info.
+//
+// Note that code.Empty() or code.IsAppLevel() will raise error.
+//
+// If endpoint sends close frame without status code (with frame.Length = 0),
+// application should not check its payload.
+func CheckCloseFrameData(code StatusCode, reason string) error {
+ switch {
+ case code.IsNotUsed():
+ return ErrProtocolStatusCodeNotInUse
+
+ case code.IsProtocolReserved():
+ return ErrProtocolStatusCodeApplicationLevel
+
+ case code == StatusNoMeaningYet:
+ return ErrProtocolStatusCodeNoMeaning
+
+ case code.IsProtocolSpec() && !code.IsProtocolDefined():
+ return ErrProtocolStatusCodeUnknown
+
+ case !utf8.ValidString(reason):
+ return ErrProtocolInvalidUTF8
+
+ default:
+ return nil
+ }
+}
diff --git a/vendor/github.com/gobwas/ws/cipher.go b/vendor/github.com/gobwas/ws/cipher.go
new file mode 100644
index 0000000..ffe4161
--- /dev/null
+++ b/vendor/github.com/gobwas/ws/cipher.go
@@ -0,0 +1,61 @@
+package ws
+
+import (
+ "encoding/binary"
+)
+
+// Cipher applies XOR cipher to the payload using mask.
+// Offset is used to cipher chunked data (e.g. in io.Reader implementations).
+//
+// To convert masked data into unmasked data, or vice versa, the following
+// algorithm is applied. The same algorithm applies regardless of the
+// direction of the translation, e.g., the same steps are applied to
+// mask the data as to unmask the data.
+func Cipher(payload []byte, mask [4]byte, offset int) {
+ n := len(payload)
+ if n < 8 {
+ for i := 0; i < n; i++ {
+ payload[i] ^= mask[(offset+i)%4]
+ }
+ return
+ }
+
+ // Calculate position in mask due to previously processed bytes number.
+ mpos := offset % 4
+ // Count number of bytes will processed one by one from the beginning of payload.
+ ln := remain[mpos]
+ // Count number of bytes will processed one by one from the end of payload.
+ // This is done to process payload by 16 bytes in each iteration of main loop.
+ rn := (n - ln) % 16
+
+ for i := 0; i < ln; i++ {
+ payload[i] ^= mask[(mpos+i)%4]
+ }
+ for i := n - rn; i < n; i++ {
+ payload[i] ^= mask[(mpos+i)%4]
+ }
+
+ // NOTE: we use here binary.LittleEndian regardless of what is real
+ // endianness on machine is. To do so, we have to use binary.LittleEndian in
+ // the masking loop below as well.
+ var (
+ m = binary.LittleEndian.Uint32(mask[:])
+ m2 = uint64(m)<<32 | uint64(m)
+ )
+ // Skip already processed right part.
+ // Get number of uint64 parts remaining to process.
+ n = (n - ln - rn) >> 4
+ j := ln
+ for i := 0; i < n; i++ {
+ chunk := payload[j : j+16]
+ p := binary.LittleEndian.Uint64(chunk) ^ m2
+ p2 := binary.LittleEndian.Uint64(chunk[8:]) ^ m2
+ binary.LittleEndian.PutUint64(chunk, p)
+ binary.LittleEndian.PutUint64(chunk[8:], p2)
+ j += 16
+ }
+}
+
+// remain maps position in masking key [0,4) to number
+// of bytes that need to be processed manually inside Cipher().
+var remain = [4]int{0, 3, 2, 1}
diff --git a/vendor/github.com/gobwas/ws/dialer.go b/vendor/github.com/gobwas/ws/dialer.go
new file mode 100644
index 0000000..e66678e
--- /dev/null
+++ b/vendor/github.com/gobwas/ws/dialer.go
@@ -0,0 +1,573 @@
+package ws
+
+import (
+ "bufio"
+ "bytes"
+ "context"
+ "crypto/tls"
+ "fmt"
+ "io"
+ "net"
+ "net/http"
+ "net/url"
+ "strconv"
+ "strings"
+ "time"
+
+ "github.com/gobwas/httphead"
+ "github.com/gobwas/pool/pbufio"
+)
+
+// Constants used by Dialer.
+const (
+ DefaultClientReadBufferSize = 4096
+ DefaultClientWriteBufferSize = 4096
+)
+
+// Handshake represents handshake result.
+type Handshake struct {
+ // Protocol is the subprotocol selected during handshake.
+ Protocol string
+
+ // Extensions is the list of negotiated extensions.
+ Extensions []httphead.Option
+}
+
+// Errors used by the websocket client.
+var (
+ ErrHandshakeBadStatus = fmt.Errorf("unexpected http status")
+ ErrHandshakeBadSubProtocol = fmt.Errorf("unexpected protocol in %q header", headerSecProtocol)
+ ErrHandshakeBadExtensions = fmt.Errorf("unexpected extensions in %q header", headerSecProtocol)
+)
+
+// DefaultDialer is dialer that holds no options and is used by Dial function.
+var DefaultDialer Dialer
+
+// Dial is like Dialer{}.Dial().
+func Dial(ctx context.Context, urlstr string) (net.Conn, *bufio.Reader, Handshake, error) {
+ return DefaultDialer.Dial(ctx, urlstr)
+}
+
+// Dialer contains options for establishing websocket connection to an url.
+type Dialer struct {
+ // ReadBufferSize and WriteBufferSize is an I/O buffer sizes.
+ // They used to read and write http data while upgrading to WebSocket.
+ // Allocated buffers are pooled with sync.Pool to avoid extra allocations.
+ //
+ // If a size is zero then default value is used.
+ ReadBufferSize, WriteBufferSize int
+
+ // Timeout is the maximum amount of time a Dial() will wait for a connect
+ // and an handshake to complete.
+ //
+ // The default is no timeout.
+ Timeout time.Duration
+
+ // Protocols is the list of subprotocols that the client wants to speak,
+ // ordered by preference.
+ //
+ // See https://tools.ietf.org/html/rfc6455#section-4.1
+ Protocols []string
+
+ // Extensions is the list of extensions that client wants to speak.
+ //
+ // Note that if server decides to use some of this extensions, Dial() will
+ // return Handshake struct containing a slice of items, which are the
+ // shallow copies of the items from this list. That is, internals of
+ // Extensions items are shared during Dial().
+ //
+ // See https://tools.ietf.org/html/rfc6455#section-4.1
+ // See https://tools.ietf.org/html/rfc6455#section-9.1
+ Extensions []httphead.Option
+
+ // Header is an optional HandshakeHeader instance that could be used to
+ // write additional headers to the handshake request.
+ //
+ // It used instead of any key-value mappings to avoid allocations in user
+ // land.
+ Header HandshakeHeader
+
+ // Host is an optional string that could be used to specify the host during
+ // HTTP upgrade request by setting 'Host' header.
+ //
+ // Default value is an empty string, which results in setting 'Host' header
+ // equal to the URL hostname given to Dialer.Dial().
+ Host string
+
+ // OnStatusError is the callback that will be called after receiving non
+ // "101 Continue" HTTP response status. It receives an io.Reader object
+ // representing server response bytes. That is, it gives ability to parse
+ // HTTP response somehow (probably with http.ReadResponse call) and make a
+ // decision of further logic.
+ //
+ // The arguments are only valid until the callback returns.
+ OnStatusError func(status int, reason []byte, resp io.Reader)
+
+ // OnHeader is the callback that will be called after successful parsing of
+ // header, that is not used during WebSocket handshake procedure. That is,
+ // it will be called with non-websocket headers, which could be relevant
+ // for application-level logic.
+ //
+ // The arguments are only valid until the callback returns.
+ //
+ // Returned value could be used to prevent processing response.
+ OnHeader func(key, value []byte) (err error)
+
+ // NetDial is the function that is used to get plain tcp connection.
+ // If it is not nil, then it is used instead of net.Dialer.
+ NetDial func(ctx context.Context, network, addr string) (net.Conn, error)
+
+ // TLSClient is the callback that will be called after successful dial with
+ // received connection and its remote host name. If it is nil, then the
+ // default tls.Client() will be used.
+ // If it is not nil, then TLSConfig field is ignored.
+ TLSClient func(conn net.Conn, hostname string) net.Conn
+
+ // TLSConfig is passed to tls.Client() to start TLS over established
+ // connection. If TLSClient is not nil, then it is ignored. If TLSConfig is
+ // non-nil and its ServerName is empty, then for every Dial() it will be
+ // cloned and appropriate ServerName will be set.
+ TLSConfig *tls.Config
+
+ // WrapConn is the optional callback that will be called when connection is
+ // ready for an i/o. That is, it will be called after successful dial and
+ // TLS initialization (for "wss" schemes). It may be helpful for different
+ // user land purposes such as end to end encryption.
+ //
+ // Note that for debugging purposes of an http handshake (e.g. sent request
+ // and received response), there is an wsutil.DebugDialer struct.
+ WrapConn func(conn net.Conn) net.Conn
+}
+
+// Dial connects to the url host and upgrades connection to WebSocket.
+//
+// If server has sent frames right after successful handshake then returned
+// buffer will be non-nil. In other cases buffer is always nil. For better
+// memory efficiency received non-nil bufio.Reader should be returned to the
+// inner pool with PutReader() function after use.
+//
+// Note that Dialer does not implement IDNA (RFC5895) logic as net/http does.
+// If you want to dial non-ascii host name, take care of its name serialization
+// avoiding bad request issues. For more info see net/http Request.Write()
+// implementation, especially cleanHost() function.
+func (d Dialer) Dial(ctx context.Context, urlstr string) (conn net.Conn, br *bufio.Reader, hs Handshake, err error) {
+ u, err := url.ParseRequestURI(urlstr)
+ if err != nil {
+ return nil, nil, hs, err
+ }
+
+ // Prepare context to dial with. Initially it is the same as original, but
+ // if d.Timeout is non-zero and points to time that is before ctx.Deadline,
+ // we use more shorter context for dial.
+ dialctx := ctx
+
+ var deadline time.Time
+ if t := d.Timeout; t != 0 {
+ deadline = time.Now().Add(t)
+ if d, ok := ctx.Deadline(); !ok || deadline.Before(d) {
+ var cancel context.CancelFunc
+ dialctx, cancel = context.WithDeadline(ctx, deadline)
+ defer cancel()
+ }
+ }
+ if conn, err = d.dial(dialctx, u); err != nil {
+ return conn, nil, hs, err
+ }
+ defer func() {
+ if err != nil {
+ conn.Close()
+ }
+ }()
+ if ctx == context.Background() {
+ // No need to start I/O interrupter goroutine which is not zero-cost.
+ conn.SetDeadline(deadline)
+ defer conn.SetDeadline(noDeadline)
+ } else {
+ // Context could be canceled or its deadline could be exceeded.
+ // Start the interrupter goroutine to handle context cancelation.
+ done := setupContextDeadliner(ctx, conn)
+ defer func() {
+ // Map Upgrade() error to a possible context expiration error. That
+ // is, even if Upgrade() err is nil, context could be already
+ // expired and connection be "poisoned" by SetDeadline() call.
+ // In that case we must not return ctx.Err() error.
+ done(&err)
+ }()
+ }
+
+ br, hs, err = d.Upgrade(conn, u)
+
+ return conn, br, hs, err
+}
+
+var (
+ // netEmptyDialer is a net.Dialer without options, used in Dialer.dial() if
+ // Dialer.NetDial is not provided.
+ netEmptyDialer net.Dialer
+ // tlsEmptyConfig is an empty tls.Config used as default one.
+ tlsEmptyConfig tls.Config
+)
+
+func tlsDefaultConfig() *tls.Config {
+ return &tlsEmptyConfig
+}
+
+func hostport(host, defaultPort string) (hostname, addr string) {
+ var (
+ colon = strings.LastIndexByte(host, ':')
+ bracket = strings.IndexByte(host, ']')
+ )
+ if colon > bracket {
+ return host[:colon], host
+ }
+ return host, host + defaultPort
+}
+
+func (d Dialer) dial(ctx context.Context, u *url.URL) (conn net.Conn, err error) {
+ dial := d.NetDial
+ if dial == nil {
+ dial = netEmptyDialer.DialContext
+ }
+ switch u.Scheme {
+ case "ws":
+ _, addr := hostport(u.Host, ":80")
+ conn, err = dial(ctx, "tcp", addr)
+ case "wss":
+ hostname, addr := hostport(u.Host, ":443")
+ conn, err = dial(ctx, "tcp", addr)
+ if err != nil {
+ return nil, err
+ }
+ tlsClient := d.TLSClient
+ if tlsClient == nil {
+ tlsClient = d.tlsClient
+ }
+ conn = tlsClient(conn, hostname)
+ default:
+ return nil, fmt.Errorf("unexpected websocket scheme: %q", u.Scheme)
+ }
+ if wrap := d.WrapConn; wrap != nil {
+ conn = wrap(conn)
+ }
+ return conn, err
+}
+
+func (d Dialer) tlsClient(conn net.Conn, hostname string) net.Conn {
+ config := d.TLSConfig
+ if config == nil {
+ config = tlsDefaultConfig()
+ }
+ if config.ServerName == "" {
+ config = tlsCloneConfig(config)
+ config.ServerName = hostname
+ }
+ // Do not make conn.Handshake() here because downstairs we will prepare
+ // i/o on this conn with proper context's timeout handling.
+ return tls.Client(conn, config)
+}
+
+var (
+ // This variables are set like in net/net.go.
+ // noDeadline is just zero value for readability.
+ noDeadline = time.Time{}
+ // aLongTimeAgo is a non-zero time, far in the past, used for immediate
+ // cancelation of dials.
+ aLongTimeAgo = time.Unix(42, 0)
+)
+
+// Upgrade writes an upgrade request to the given io.ReadWriter conn at given
+// url u and reads a response from it.
+//
+// It is a caller responsibility to manage I/O deadlines on conn.
+//
+// It returns handshake info and some bytes which could be written by the peer
+// right after response and be caught by us during buffered read.
+func (d Dialer) Upgrade(conn io.ReadWriter, u *url.URL) (br *bufio.Reader, hs Handshake, err error) {
+ // headerSeen constants helps to report whether or not some header was seen
+ // during reading request bytes.
+ const (
+ headerSeenUpgrade = 1 << iota
+ headerSeenConnection
+ headerSeenSecAccept
+
+ // headerSeenAll is the value that we expect to receive at the end of
+ // headers read/parse loop.
+ headerSeenAll = 0 |
+ headerSeenUpgrade |
+ headerSeenConnection |
+ headerSeenSecAccept
+ )
+
+ br = pbufio.GetReader(conn,
+ nonZero(d.ReadBufferSize, DefaultClientReadBufferSize),
+ )
+ bw := pbufio.GetWriter(conn,
+ nonZero(d.WriteBufferSize, DefaultClientWriteBufferSize),
+ )
+ defer func() {
+ pbufio.PutWriter(bw)
+ if br.Buffered() == 0 || err != nil {
+ // Server does not wrote additional bytes to the connection or
+ // error occurred. That is, no reason to return buffer.
+ pbufio.PutReader(br)
+ br = nil
+ }
+ }()
+
+ nonce := make([]byte, nonceSize)
+ initNonce(nonce)
+
+ httpWriteUpgradeRequest(bw, u, nonce, d.Protocols, d.Extensions, d.Header, d.Host)
+ if err := bw.Flush(); err != nil {
+ return br, hs, err
+ }
+
+ // Read HTTP status line like "HTTP/1.1 101 Switching Protocols".
+ sl, err := readLine(br)
+ if err != nil {
+ return br, hs, err
+ }
+ // Begin validation of the response.
+ // See https://tools.ietf.org/html/rfc6455#section-4.2.2
+ // Parse request line data like HTTP version, uri and method.
+ resp, err := httpParseResponseLine(sl)
+ if err != nil {
+ return br, hs, err
+ }
+ // Even if RFC says "1.1 or higher" without mentioning the part of the
+ // version, we apply it only to minor part.
+ if resp.major != 1 || resp.minor < 1 {
+ err = ErrHandshakeBadProtocol
+ return br, hs, err
+ }
+ if resp.status != http.StatusSwitchingProtocols {
+ err = StatusError(resp.status)
+ if onStatusError := d.OnStatusError; onStatusError != nil {
+ // Invoke callback with multireader of status-line bytes br.
+ onStatusError(resp.status, resp.reason,
+ io.MultiReader(
+ bytes.NewReader(sl),
+ strings.NewReader(crlf),
+ br,
+ ),
+ )
+ }
+ return br, hs, err
+ }
+ // If response status is 101 then we expect all technical headers to be
+ // valid. If not, then we stop processing response without giving user
+ // ability to read non-technical headers. That is, we do not distinguish
+ // technical errors (such as parsing error) and protocol errors.
+ var headerSeen byte
+ for {
+ line, e := readLine(br)
+ if e != nil {
+ err = e
+ return br, hs, err
+ }
+ if len(line) == 0 {
+ // Blank line, no more lines to read.
+ break
+ }
+
+ k, v, ok := httpParseHeaderLine(line)
+ if !ok {
+ err = ErrMalformedResponse
+ return br, hs, err
+ }
+
+ switch btsToString(k) {
+ case headerUpgradeCanonical:
+ headerSeen |= headerSeenUpgrade
+ if !bytes.Equal(v, specHeaderValueUpgrade) && !bytes.EqualFold(v, specHeaderValueUpgrade) {
+ err = ErrHandshakeBadUpgrade
+ return br, hs, err
+ }
+
+ case headerConnectionCanonical:
+ headerSeen |= headerSeenConnection
+ // Note that as RFC6455 says:
+ // > A |Connection| header field with value "Upgrade".
+ // That is, in server side, "Connection" header could contain
+ // multiple token. But in response it must contains exactly one.
+ if !bytes.Equal(v, specHeaderValueConnection) && !bytes.EqualFold(v, specHeaderValueConnection) {
+ err = ErrHandshakeBadConnection
+ return br, hs, err
+ }
+
+ case headerSecAcceptCanonical:
+ headerSeen |= headerSeenSecAccept
+ if !checkAcceptFromNonce(v, nonce) {
+ err = ErrHandshakeBadSecAccept
+ return br, hs, err
+ }
+
+ case headerSecProtocolCanonical:
+ // RFC6455 1.3:
+ // "The server selects one or none of the acceptable protocols
+ // and echoes that value in its handshake to indicate that it has
+ // selected that protocol."
+ for _, want := range d.Protocols {
+ if string(v) == want {
+ hs.Protocol = want
+ break
+ }
+ }
+ if hs.Protocol == "" {
+ // Server echoed subprotocol that is not present in client
+ // requested protocols.
+ err = ErrHandshakeBadSubProtocol
+ return br, hs, err
+ }
+
+ case headerSecExtensionsCanonical:
+ hs.Extensions, err = matchSelectedExtensions(v, d.Extensions, hs.Extensions)
+ if err != nil {
+ return br, hs, err
+ }
+
+ default:
+ if onHeader := d.OnHeader; onHeader != nil {
+ if e := onHeader(k, v); e != nil {
+ err = e
+ return br, hs, err
+ }
+ }
+ }
+ }
+ if err == nil && headerSeen != headerSeenAll {
+ switch {
+ case headerSeen&headerSeenUpgrade == 0:
+ err = ErrHandshakeBadUpgrade
+ case headerSeen&headerSeenConnection == 0:
+ err = ErrHandshakeBadConnection
+ case headerSeen&headerSeenSecAccept == 0:
+ err = ErrHandshakeBadSecAccept
+ default:
+ panic("unknown headers state")
+ }
+ }
+ return br, hs, err
+}
+
+// PutReader returns bufio.Reader instance to the inner reuse pool.
+// It is useful in rare cases, when Dialer.Dial() returns non-nil buffer which
+// contains unprocessed buffered data, that was sent by the server quickly
+// right after handshake.
+func PutReader(br *bufio.Reader) {
+ pbufio.PutReader(br)
+}
+
+// StatusError contains an unexpected status-line code from the server.
+type StatusError int
+
+func (s StatusError) Error() string {
+ return "unexpected HTTP response status: " + strconv.Itoa(int(s))
+}
+
+func isTimeoutError(err error) bool {
+ t, ok := err.(net.Error)
+ return ok && t.Timeout()
+}
+
+func matchSelectedExtensions(selected []byte, wanted, received []httphead.Option) ([]httphead.Option, error) {
+ if len(selected) == 0 {
+ return received, nil
+ }
+ var (
+ index int
+ option httphead.Option
+ err error
+ )
+ index = -1
+ match := func() (ok bool) {
+ for _, want := range wanted {
+ // A server accepts one or more extensions by including a
+ // |Sec-WebSocket-Extensions| header field containing one or more
+ // extensions that were requested by the client.
+ //
+ // The interpretation of any extension parameters, and what
+ // constitutes a valid response by a server to a requested set of
+ // parameters by a client, will be defined by each such extension.
+ if bytes.Equal(option.Name, want.Name) {
+ // Check parsed extension to be present in client
+ // requested extensions. We move matched extension
+ // from client list to avoid allocation of httphead.Option.Name,
+ // httphead.Option.Parameters have to be copied from the header
+ want.Parameters, _ = option.Parameters.Copy(make([]byte, option.Parameters.Size()))
+ received = append(received, want)
+ return true
+ }
+ }
+ return false
+ }
+ ok := httphead.ScanOptions(selected, func(i int, name, attr, val []byte) httphead.Control {
+ if i != index {
+ // Met next option.
+ index = i
+ if i != 0 && !match() {
+ // Server returned non-requested extension.
+ err = ErrHandshakeBadExtensions
+ return httphead.ControlBreak
+ }
+ option = httphead.Option{Name: name}
+ }
+ if attr != nil {
+ option.Parameters.Set(attr, val)
+ }
+ return httphead.ControlContinue
+ })
+ if !ok {
+ err = ErrMalformedResponse
+ return received, err
+ }
+ if !match() {
+ return received, ErrHandshakeBadExtensions
+ }
+ return received, err
+}
+
+// setupContextDeadliner is a helper function that starts connection I/O
+// interrupter goroutine.
+//
+// Started goroutine calls SetDeadline() with long time ago value when context
+// become expired to make any I/O operations failed. It returns done function
+// that stops started goroutine and maps error received from conn I/O methods
+// to possible context expiration error.
+//
+// In concern with possible SetDeadline() call inside interrupter goroutine,
+// caller passes pointer to its I/O error (even if it is nil) to done(&err).
+// That is, even if I/O error is nil, context could be already expired and
+// connection "poisoned" by SetDeadline() call. In that case done(&err) will
+// store at *err ctx.Err() result. If err is caused not by timeout, it will
+// leaved untouched.
+func setupContextDeadliner(ctx context.Context, conn net.Conn) (done func(*error)) {
+ var (
+ quit = make(chan struct{})
+ interrupt = make(chan error, 1)
+ )
+ go func() {
+ select {
+ case <-quit:
+ interrupt <- nil
+ case <-ctx.Done():
+ // Cancel i/o immediately.
+ conn.SetDeadline(aLongTimeAgo)
+ interrupt <- ctx.Err()
+ }
+ }()
+ return func(err *error) {
+ close(quit)
+ // If ctx.Err() is non-nil and the original err is net.Error with
+ // Timeout() == true, then it means that I/O was canceled by us by
+ // SetDeadline(aLongTimeAgo) call, or by somebody else previously
+ // by conn.SetDeadline(x).
+ //
+ // Even on race condition when both deadlines are expired
+ // (SetDeadline() made not by us and context's), we prefer ctx.Err() to
+ // be returned.
+ if ctxErr := <-interrupt; ctxErr != nil && (*err == nil || isTimeoutError(*err)) {
+ *err = ctxErr
+ }
+ }
+}
diff --git a/vendor/github.com/gobwas/ws/dialer_tls_go17.go b/vendor/github.com/gobwas/ws/dialer_tls_go17.go
new file mode 100644
index 0000000..b606e0a
--- /dev/null
+++ b/vendor/github.com/gobwas/ws/dialer_tls_go17.go
@@ -0,0 +1,35 @@
+// +build !go1.8
+
+package ws
+
+import "crypto/tls"
+
+func tlsCloneConfig(c *tls.Config) *tls.Config {
+ // NOTE: we copying SessionTicketsDisabled and SessionTicketKey here
+ // without calling inner c.initOnceServer somehow because we only could get
+ // here from the ws.Dialer code, which is obviously a client and makes
+ // tls.Client() when it gets new net.Conn.
+ return &tls.Config{
+ Rand: c.Rand,
+ Time: c.Time,
+ Certificates: c.Certificates,
+ NameToCertificate: c.NameToCertificate,
+ GetCertificate: c.GetCertificate,
+ RootCAs: c.RootCAs,
+ NextProtos: c.NextProtos,
+ ServerName: c.ServerName,
+ ClientAuth: c.ClientAuth,
+ ClientCAs: c.ClientCAs,
+ InsecureSkipVerify: c.InsecureSkipVerify,
+ CipherSuites: c.CipherSuites,
+ PreferServerCipherSuites: c.PreferServerCipherSuites,
+ SessionTicketsDisabled: c.SessionTicketsDisabled,
+ SessionTicketKey: c.SessionTicketKey,
+ ClientSessionCache: c.ClientSessionCache,
+ MinVersion: c.MinVersion,
+ MaxVersion: c.MaxVersion,
+ CurvePreferences: c.CurvePreferences,
+ DynamicRecordSizingDisabled: c.DynamicRecordSizingDisabled,
+ Renegotiation: c.Renegotiation,
+ }
+}
diff --git a/vendor/github.com/gobwas/ws/dialer_tls_go18.go b/vendor/github.com/gobwas/ws/dialer_tls_go18.go
new file mode 100644
index 0000000..5589ee5
--- /dev/null
+++ b/vendor/github.com/gobwas/ws/dialer_tls_go18.go
@@ -0,0 +1,10 @@
+//go:build go1.8
+// +build go1.8
+
+package ws
+
+import "crypto/tls"
+
+func tlsCloneConfig(c *tls.Config) *tls.Config {
+ return c.Clone()
+}
diff --git a/vendor/github.com/gobwas/ws/doc.go b/vendor/github.com/gobwas/ws/doc.go
new file mode 100644
index 0000000..0118ce2
--- /dev/null
+++ b/vendor/github.com/gobwas/ws/doc.go
@@ -0,0 +1,81 @@
+/*
+Package ws implements a client and server for the WebSocket protocol as
+specified in RFC 6455.
+
+The main purpose of this package is to provide simple low-level API for
+efficient work with protocol.
+
+Overview.
+
+Upgrade to WebSocket (or WebSocket handshake) can be done in two ways.
+
+The first way is to use `net/http` server:
+
+ http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
+ conn, _, _, err := ws.UpgradeHTTP(r, w)
+ })
+
+The second and much more efficient way is so-called "zero-copy upgrade". It
+avoids redundant allocations and copying of not used headers or other request
+data. User decides by himself which data should be copied.
+
+ ln, err := net.Listen("tcp", ":8080")
+ if err != nil {
+ // handle error
+ }
+
+ conn, err := ln.Accept()
+ if err != nil {
+ // handle error
+ }
+
+ handshake, err := ws.Upgrade(conn)
+ if err != nil {
+ // handle error
+ }
+
+For customization details see `ws.Upgrader` documentation.
+
+After WebSocket handshake you can work with connection in multiple ways.
+That is, `ws` does not force the only one way of how to work with WebSocket:
+
+ header, err := ws.ReadHeader(conn)
+ if err != nil {
+ // handle err
+ }
+
+ buf := make([]byte, header.Length)
+ _, err := io.ReadFull(conn, buf)
+ if err != nil {
+ // handle err
+ }
+
+ resp := ws.NewBinaryFrame([]byte("hello, world!"))
+ if err := ws.WriteFrame(conn, frame); err != nil {
+ // handle err
+ }
+
+As you can see, it stream friendly:
+
+ const N = 42
+
+ ws.WriteHeader(ws.Header{
+ Fin: true,
+ Length: N,
+ OpCode: ws.OpBinary,
+ })
+
+ io.CopyN(conn, rand.Reader, N)
+
+Or:
+
+ header, err := ws.ReadHeader(conn)
+ if err != nil {
+ // handle err
+ }
+
+ io.CopyN(ioutil.Discard, conn, header.Length)
+
+For more info see the documentation.
+*/
+package ws
diff --git a/vendor/github.com/gobwas/ws/errors.go b/vendor/github.com/gobwas/ws/errors.go
new file mode 100644
index 0000000..f5668b2
--- /dev/null
+++ b/vendor/github.com/gobwas/ws/errors.go
@@ -0,0 +1,59 @@
+package ws
+
+// RejectOption represents an option used to control the way connection is
+// rejected.
+type RejectOption func(*ConnectionRejectedError)
+
+// RejectionReason returns an option that makes connection to be rejected with
+// given reason.
+func RejectionReason(reason string) RejectOption {
+ return func(err *ConnectionRejectedError) {
+ err.reason = reason
+ }
+}
+
+// RejectionStatus returns an option that makes connection to be rejected with
+// given HTTP status code.
+func RejectionStatus(code int) RejectOption {
+ return func(err *ConnectionRejectedError) {
+ err.code = code
+ }
+}
+
+// RejectionHeader returns an option that makes connection to be rejected with
+// given HTTP headers.
+func RejectionHeader(h HandshakeHeader) RejectOption {
+ return func(err *ConnectionRejectedError) {
+ err.header = h
+ }
+}
+
+// RejectConnectionError constructs an error that could be used to control the
+// way handshake is rejected by Upgrader.
+func RejectConnectionError(options ...RejectOption) error {
+ err := new(ConnectionRejectedError)
+ for _, opt := range options {
+ opt(err)
+ }
+ return err
+}
+
+// ConnectionRejectedError represents a rejection of connection during
+// WebSocket handshake error.
+//
+// It can be returned by Upgrader's On* hooks to indicate that WebSocket
+// handshake should be rejected.
+type ConnectionRejectedError struct {
+ reason string
+ code int
+ header HandshakeHeader
+}
+
+// Error implements error interface.
+func (r *ConnectionRejectedError) Error() string {
+ return r.reason
+}
+
+func (r *ConnectionRejectedError) StatusCode() int {
+ return r.code
+}
diff --git a/vendor/github.com/gobwas/ws/frame.go b/vendor/github.com/gobwas/ws/frame.go
new file mode 100644
index 0000000..ae10144
--- /dev/null
+++ b/vendor/github.com/gobwas/ws/frame.go
@@ -0,0 +1,420 @@
+package ws
+
+import (
+ "bytes"
+ "encoding/binary"
+ "math/rand"
+)
+
+// Constants defined by specification.
+const (
+ // All control frames MUST have a payload length of 125 bytes or less and MUST NOT be fragmented.
+ MaxControlFramePayloadSize = 125
+)
+
+// OpCode represents operation code.
+type OpCode byte
+
+// Operation codes defined by specification.
+// See https://tools.ietf.org/html/rfc6455#section-5.2
+const (
+ OpContinuation OpCode = 0x0
+ OpText OpCode = 0x1
+ OpBinary OpCode = 0x2
+ OpClose OpCode = 0x8
+ OpPing OpCode = 0x9
+ OpPong OpCode = 0xa
+)
+
+// IsControl checks whether the c is control operation code.
+// See https://tools.ietf.org/html/rfc6455#section-5.5
+func (c OpCode) IsControl() bool {
+ // RFC6455: Control frames are identified by opcodes where
+ // the most significant bit of the opcode is 1.
+ //
+ // Note that OpCode is only 4 bit length.
+ return c&0x8 != 0
+}
+
+// IsData checks whether the c is data operation code.
+// See https://tools.ietf.org/html/rfc6455#section-5.6
+func (c OpCode) IsData() bool {
+ // RFC6455: Data frames (e.g., non-control frames) are identified by opcodes
+ // where the most significant bit of the opcode is 0.
+ //
+ // Note that OpCode is only 4 bit length.
+ return c&0x8 == 0
+}
+
+// IsReserved checks whether the c is reserved operation code.
+// See https://tools.ietf.org/html/rfc6455#section-5.2
+func (c OpCode) IsReserved() bool {
+ // RFC6455:
+ // %x3-7 are reserved for further non-control frames
+ // %xB-F are reserved for further control frames
+ return (0x3 <= c && c <= 0x7) || (0xb <= c && c <= 0xf)
+}
+
+// StatusCode represents the encoded reason for closure of websocket connection.
+//
+// There are few helper methods on StatusCode that helps to define a range in
+// which given code is lay in. accordingly to ranges defined in specification.
+//
+// See https://tools.ietf.org/html/rfc6455#section-7.4
+type StatusCode uint16
+
+// StatusCodeRange describes range of StatusCode values.
+type StatusCodeRange struct {
+ Min, Max StatusCode
+}
+
+// Status code ranges defined by specification.
+// See https://tools.ietf.org/html/rfc6455#section-7.4.2
+var (
+ StatusRangeNotInUse = StatusCodeRange{0, 999}
+ StatusRangeProtocol = StatusCodeRange{1000, 2999}
+ StatusRangeApplication = StatusCodeRange{3000, 3999}
+ StatusRangePrivate = StatusCodeRange{4000, 4999}
+)
+
+// Status codes defined by specification.
+// See https://tools.ietf.org/html/rfc6455#section-7.4.1
+const (
+ StatusNormalClosure StatusCode = 1000
+ StatusGoingAway StatusCode = 1001
+ StatusProtocolError StatusCode = 1002
+ StatusUnsupportedData StatusCode = 1003
+ StatusNoMeaningYet StatusCode = 1004
+ StatusInvalidFramePayloadData StatusCode = 1007
+ StatusPolicyViolation StatusCode = 1008
+ StatusMessageTooBig StatusCode = 1009
+ StatusMandatoryExt StatusCode = 1010
+ StatusInternalServerError StatusCode = 1011
+ StatusTLSHandshake StatusCode = 1015
+
+ // StatusAbnormalClosure is a special code designated for use in
+ // applications.
+ StatusAbnormalClosure StatusCode = 1006
+
+ // StatusNoStatusRcvd is a special code designated for use in applications.
+ StatusNoStatusRcvd StatusCode = 1005
+)
+
+// In reports whether the code is defined in given range.
+func (s StatusCode) In(r StatusCodeRange) bool {
+ return r.Min <= s && s <= r.Max
+}
+
+// Empty reports whether the code is empty.
+// Empty code has no any meaning neither app level codes nor other.
+// This method is useful just to check that code is golang default value 0.
+func (s StatusCode) Empty() bool {
+ return s == 0
+}
+
+// IsNotUsed reports whether the code is predefined in not used range.
+func (s StatusCode) IsNotUsed() bool {
+ return s.In(StatusRangeNotInUse)
+}
+
+// IsApplicationSpec reports whether the code should be defined by
+// application, framework or libraries specification.
+func (s StatusCode) IsApplicationSpec() bool {
+ return s.In(StatusRangeApplication)
+}
+
+// IsPrivateSpec reports whether the code should be defined privately.
+func (s StatusCode) IsPrivateSpec() bool {
+ return s.In(StatusRangePrivate)
+}
+
+// IsProtocolSpec reports whether the code should be defined by protocol specification.
+func (s StatusCode) IsProtocolSpec() bool {
+ return s.In(StatusRangeProtocol)
+}
+
+// IsProtocolDefined reports whether the code is already defined by protocol specification.
+func (s StatusCode) IsProtocolDefined() bool {
+ switch s {
+ case StatusNormalClosure,
+ StatusGoingAway,
+ StatusProtocolError,
+ StatusUnsupportedData,
+ StatusInvalidFramePayloadData,
+ StatusPolicyViolation,
+ StatusMessageTooBig,
+ StatusMandatoryExt,
+ StatusInternalServerError,
+ StatusNoStatusRcvd,
+ StatusAbnormalClosure,
+ StatusTLSHandshake:
+ return true
+ }
+ return false
+}
+
+// IsProtocolReserved reports whether the code is defined by protocol specification
+// to be reserved only for application usage purpose.
+func (s StatusCode) IsProtocolReserved() bool {
+ switch s {
+ // [RFC6455]: {1005,1006,1015} is a reserved value and MUST NOT be set as a status code in a
+ // Close control frame by an endpoint.
+ case StatusNoStatusRcvd, StatusAbnormalClosure, StatusTLSHandshake:
+ return true
+ default:
+ return false
+ }
+}
+
+// Compiled control frames for common use cases.
+// For construct-serialize optimizations.
+var (
+ CompiledPing = MustCompileFrame(NewPingFrame(nil))
+ CompiledPong = MustCompileFrame(NewPongFrame(nil))
+ CompiledClose = MustCompileFrame(NewCloseFrame(nil))
+
+ CompiledCloseNormalClosure = MustCompileFrame(closeFrameNormalClosure)
+ CompiledCloseGoingAway = MustCompileFrame(closeFrameGoingAway)
+ CompiledCloseProtocolError = MustCompileFrame(closeFrameProtocolError)
+ CompiledCloseUnsupportedData = MustCompileFrame(closeFrameUnsupportedData)
+ CompiledCloseNoMeaningYet = MustCompileFrame(closeFrameNoMeaningYet)
+ CompiledCloseInvalidFramePayloadData = MustCompileFrame(closeFrameInvalidFramePayloadData)
+ CompiledClosePolicyViolation = MustCompileFrame(closeFramePolicyViolation)
+ CompiledCloseMessageTooBig = MustCompileFrame(closeFrameMessageTooBig)
+ CompiledCloseMandatoryExt = MustCompileFrame(closeFrameMandatoryExt)
+ CompiledCloseInternalServerError = MustCompileFrame(closeFrameInternalServerError)
+ CompiledCloseTLSHandshake = MustCompileFrame(closeFrameTLSHandshake)
+)
+
+// Header represents websocket frame header.
+// See https://tools.ietf.org/html/rfc6455#section-5.2
+type Header struct {
+ Fin bool
+ Rsv byte
+ OpCode OpCode
+ Masked bool
+ Mask [4]byte
+ Length int64
+}
+
+// Rsv1 reports whether the header has first rsv bit set.
+func (h Header) Rsv1() bool { return h.Rsv&bit5 != 0 }
+
+// Rsv2 reports whether the header has second rsv bit set.
+func (h Header) Rsv2() bool { return h.Rsv&bit6 != 0 }
+
+// Rsv3 reports whether the header has third rsv bit set.
+func (h Header) Rsv3() bool { return h.Rsv&bit7 != 0 }
+
+// Rsv creates rsv byte representation from bits.
+func Rsv(r1, r2, r3 bool) (rsv byte) {
+ if r1 {
+ rsv |= bit5
+ }
+ if r2 {
+ rsv |= bit6
+ }
+ if r3 {
+ rsv |= bit7
+ }
+ return rsv
+}
+
+// RsvBits returns rsv bits from bytes representation.
+func RsvBits(rsv byte) (r1, r2, r3 bool) {
+ r1 = rsv&bit5 != 0
+ r2 = rsv&bit6 != 0
+ r3 = rsv&bit7 != 0
+ return r1, r2, r3
+}
+
+// Frame represents websocket frame.
+// See https://tools.ietf.org/html/rfc6455#section-5.2
+type Frame struct {
+ Header Header
+ Payload []byte
+}
+
+// NewFrame creates frame with given operation code,
+// flag of completeness and payload bytes.
+func NewFrame(op OpCode, fin bool, p []byte) Frame {
+ return Frame{
+ Header: Header{
+ Fin: fin,
+ OpCode: op,
+ Length: int64(len(p)),
+ },
+ Payload: p,
+ }
+}
+
+// NewTextFrame creates text frame with p as payload.
+// Note that p is not copied.
+func NewTextFrame(p []byte) Frame {
+ return NewFrame(OpText, true, p)
+}
+
+// NewBinaryFrame creates binary frame with p as payload.
+// Note that p is not copied.
+func NewBinaryFrame(p []byte) Frame {
+ return NewFrame(OpBinary, true, p)
+}
+
+// NewPingFrame creates ping frame with p as payload.
+// Note that p is not copied.
+// Note that p must have length of MaxControlFramePayloadSize bytes or less due
+// to RFC.
+func NewPingFrame(p []byte) Frame {
+ return NewFrame(OpPing, true, p)
+}
+
+// NewPongFrame creates pong frame with p as payload.
+// Note that p is not copied.
+// Note that p must have length of MaxControlFramePayloadSize bytes or less due
+// to RFC.
+func NewPongFrame(p []byte) Frame {
+ return NewFrame(OpPong, true, p)
+}
+
+// NewCloseFrame creates close frame with given close body.
+// Note that p is not copied.
+// Note that p must have length of MaxControlFramePayloadSize bytes or less due
+// to RFC.
+func NewCloseFrame(p []byte) Frame {
+ return NewFrame(OpClose, true, p)
+}
+
+// NewCloseFrameBody encodes a closure code and a reason into a binary
+// representation.
+//
+// It returns slice which is at most MaxControlFramePayloadSize bytes length.
+// If the reason is too big it will be cropped to fit the limit defined by the
+// spec.
+//
+// See https://tools.ietf.org/html/rfc6455#section-5.5
+func NewCloseFrameBody(code StatusCode, reason string) []byte {
+ n := min(2+len(reason), MaxControlFramePayloadSize)
+ p := make([]byte, n)
+
+ crop := min(MaxControlFramePayloadSize-2, len(reason))
+ PutCloseFrameBody(p, code, reason[:crop])
+
+ return p
+}
+
+// PutCloseFrameBody encodes code and reason into buf.
+//
+// It will panic if the buffer is too small to accommodate a code or a reason.
+//
+// PutCloseFrameBody does not check buffer to be RFC compliant, but note that
+// by RFC it must be at most MaxControlFramePayloadSize.
+func PutCloseFrameBody(p []byte, code StatusCode, reason string) {
+ _ = p[1+len(reason)]
+ binary.BigEndian.PutUint16(p, uint16(code))
+ copy(p[2:], reason)
+}
+
+// MaskFrame masks frame and returns frame with masked payload and Mask header's field set.
+// Note that it copies f payload to prevent collisions.
+// For less allocations you could use MaskFrameInPlace or construct frame manually.
+func MaskFrame(f Frame) Frame {
+ return MaskFrameWith(f, NewMask())
+}
+
+// MaskFrameWith masks frame with given mask and returns frame
+// with masked payload and Mask header's field set.
+// Note that it copies f payload to prevent collisions.
+// For less allocations you could use MaskFrameInPlaceWith or construct frame manually.
+func MaskFrameWith(f Frame, mask [4]byte) Frame {
+ // TODO(gobwas): check CopyCipher ws copy() Cipher().
+ p := make([]byte, len(f.Payload))
+ copy(p, f.Payload)
+ f.Payload = p
+ return MaskFrameInPlaceWith(f, mask)
+}
+
+// MaskFrameInPlace masks frame and returns frame with masked payload and Mask
+// header's field set.
+// Note that it applies xor cipher to f.Payload without copying, that is, it
+// modifies f.Payload inplace.
+func MaskFrameInPlace(f Frame) Frame {
+ return MaskFrameInPlaceWith(f, NewMask())
+}
+
+var zeroMask [4]byte
+
+// UnmaskFrame unmasks frame and returns frame with unmasked payload and Mask
+// header's field cleared.
+// Note that it copies f payload.
+func UnmaskFrame(f Frame) Frame {
+ p := make([]byte, len(f.Payload))
+ copy(p, f.Payload)
+ f.Payload = p
+ return UnmaskFrameInPlace(f)
+}
+
+// UnmaskFrameInPlace unmasks frame and returns frame with unmasked payload and
+// Mask header's field cleared.
+// Note that it applies xor cipher to f.Payload without copying, that is, it
+// modifies f.Payload inplace.
+func UnmaskFrameInPlace(f Frame) Frame {
+ Cipher(f.Payload, f.Header.Mask, 0)
+ f.Header.Masked = false
+ f.Header.Mask = zeroMask
+ return f
+}
+
+// MaskFrameInPlaceWith masks frame with given mask and returns frame
+// with masked payload and Mask header's field set.
+// Note that it applies xor cipher to f.Payload without copying, that is, it
+// modifies f.Payload inplace.
+func MaskFrameInPlaceWith(f Frame, m [4]byte) Frame {
+ f.Header.Masked = true
+ f.Header.Mask = m
+ Cipher(f.Payload, m, 0)
+ return f
+}
+
+// NewMask creates new random mask.
+func NewMask() (ret [4]byte) {
+ binary.BigEndian.PutUint32(ret[:], rand.Uint32())
+ return ret
+}
+
+// CompileFrame returns byte representation of given frame.
+// In terms of memory consumption it is useful to precompile static frames
+// which are often used.
+func CompileFrame(f Frame) (bts []byte, err error) {
+ buf := bytes.NewBuffer(make([]byte, 0, 16))
+ err = WriteFrame(buf, f)
+ bts = buf.Bytes()
+ return bts, err
+}
+
+// MustCompileFrame is like CompileFrame but panics if frame can not be
+// encoded.
+func MustCompileFrame(f Frame) []byte {
+ bts, err := CompileFrame(f)
+ if err != nil {
+ panic(err)
+ }
+ return bts
+}
+
+func makeCloseFrame(code StatusCode) Frame {
+ return NewCloseFrame(NewCloseFrameBody(code, ""))
+}
+
+var (
+ closeFrameNormalClosure = makeCloseFrame(StatusNormalClosure)
+ closeFrameGoingAway = makeCloseFrame(StatusGoingAway)
+ closeFrameProtocolError = makeCloseFrame(StatusProtocolError)
+ closeFrameUnsupportedData = makeCloseFrame(StatusUnsupportedData)
+ closeFrameNoMeaningYet = makeCloseFrame(StatusNoMeaningYet)
+ closeFrameInvalidFramePayloadData = makeCloseFrame(StatusInvalidFramePayloadData)
+ closeFramePolicyViolation = makeCloseFrame(StatusPolicyViolation)
+ closeFrameMessageTooBig = makeCloseFrame(StatusMessageTooBig)
+ closeFrameMandatoryExt = makeCloseFrame(StatusMandatoryExt)
+ closeFrameInternalServerError = makeCloseFrame(StatusInternalServerError)
+ closeFrameTLSHandshake = makeCloseFrame(StatusTLSHandshake)
+)
diff --git a/vendor/github.com/gobwas/ws/hijack_go119.go b/vendor/github.com/gobwas/ws/hijack_go119.go
new file mode 100644
index 0000000..6ac556c
--- /dev/null
+++ b/vendor/github.com/gobwas/ws/hijack_go119.go
@@ -0,0 +1,18 @@
+//go:build !go1.20
+// +build !go1.20
+
+package ws
+
+import (
+ "bufio"
+ "net"
+ "net/http"
+)
+
+func hijack(w http.ResponseWriter) (net.Conn, *bufio.ReadWriter, error) {
+ hj, ok := w.(http.Hijacker)
+ if ok {
+ return hj.Hijack()
+ }
+ return nil, nil, ErrNotHijacker
+}
diff --git a/vendor/github.com/gobwas/ws/hijack_go120.go b/vendor/github.com/gobwas/ws/hijack_go120.go
new file mode 100644
index 0000000..e67b439
--- /dev/null
+++ b/vendor/github.com/gobwas/ws/hijack_go120.go
@@ -0,0 +1,19 @@
+//go:build go1.20
+// +build go1.20
+
+package ws
+
+import (
+ "bufio"
+ "errors"
+ "net"
+ "net/http"
+)
+
+func hijack(w http.ResponseWriter) (net.Conn, *bufio.ReadWriter, error) {
+ conn, rw, err := http.NewResponseController(w).Hijack()
+ if errors.Is(err, http.ErrNotSupported) {
+ return nil, nil, ErrNotHijacker
+ }
+ return conn, rw, err
+}
diff --git a/vendor/github.com/gobwas/ws/http.go b/vendor/github.com/gobwas/ws/http.go
new file mode 100644
index 0000000..a3a682d
--- /dev/null
+++ b/vendor/github.com/gobwas/ws/http.go
@@ -0,0 +1,507 @@
+package ws
+
+import (
+ "bufio"
+ "bytes"
+ "io"
+ "net/http"
+ "net/url"
+ "strconv"
+
+ "github.com/gobwas/httphead"
+)
+
+const (
+ crlf = "\r\n"
+ colonAndSpace = ": "
+ commaAndSpace = ", "
+)
+
+const (
+ textHeadUpgrade = "HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\n"
+)
+
+var (
+ textHeadBadRequest = statusText(http.StatusBadRequest)
+ textHeadInternalServerError = statusText(http.StatusInternalServerError)
+ textHeadUpgradeRequired = statusText(http.StatusUpgradeRequired)
+
+ textTailErrHandshakeBadProtocol = errorText(ErrHandshakeBadProtocol)
+ textTailErrHandshakeBadMethod = errorText(ErrHandshakeBadMethod)
+ textTailErrHandshakeBadHost = errorText(ErrHandshakeBadHost)
+ textTailErrHandshakeBadUpgrade = errorText(ErrHandshakeBadUpgrade)
+ textTailErrHandshakeBadConnection = errorText(ErrHandshakeBadConnection)
+ textTailErrHandshakeBadSecAccept = errorText(ErrHandshakeBadSecAccept)
+ textTailErrHandshakeBadSecKey = errorText(ErrHandshakeBadSecKey)
+ textTailErrHandshakeBadSecVersion = errorText(ErrHandshakeBadSecVersion)
+ textTailErrUpgradeRequired = errorText(ErrHandshakeUpgradeRequired)
+)
+
+const (
+ // Every new header must be added to TestHeaderNames test.
+ headerHost = "Host"
+ headerUpgrade = "Upgrade"
+ headerConnection = "Connection"
+ headerSecVersion = "Sec-WebSocket-Version"
+ headerSecProtocol = "Sec-WebSocket-Protocol"
+ headerSecExtensions = "Sec-WebSocket-Extensions"
+ headerSecKey = "Sec-WebSocket-Key"
+ headerSecAccept = "Sec-WebSocket-Accept"
+
+ headerHostCanonical = headerHost
+ headerUpgradeCanonical = headerUpgrade
+ headerConnectionCanonical = headerConnection
+ headerSecVersionCanonical = "Sec-Websocket-Version"
+ headerSecProtocolCanonical = "Sec-Websocket-Protocol"
+ headerSecExtensionsCanonical = "Sec-Websocket-Extensions"
+ headerSecKeyCanonical = "Sec-Websocket-Key"
+ headerSecAcceptCanonical = "Sec-Websocket-Accept"
+)
+
+var (
+ specHeaderValueUpgrade = []byte("websocket")
+ specHeaderValueConnection = []byte("Upgrade")
+ specHeaderValueConnectionLower = []byte("upgrade")
+ specHeaderValueSecVersion = []byte("13")
+)
+
+var (
+ httpVersion1_0 = []byte("HTTP/1.0")
+ httpVersion1_1 = []byte("HTTP/1.1")
+ httpVersionPrefix = []byte("HTTP/")
+)
+
+type httpRequestLine struct {
+ method, uri []byte
+ major, minor int
+}
+
+type httpResponseLine struct {
+ major, minor int
+ status int
+ reason []byte
+}
+
+// httpParseRequestLine parses http request line like "GET / HTTP/1.0".
+func httpParseRequestLine(line []byte) (req httpRequestLine, err error) {
+ var proto []byte
+ req.method, req.uri, proto = bsplit3(line, ' ')
+
+ var ok bool
+ req.major, req.minor, ok = httpParseVersion(proto)
+ if !ok {
+ err = ErrMalformedRequest
+ }
+ return req, err
+}
+
+func httpParseResponseLine(line []byte) (resp httpResponseLine, err error) {
+ var (
+ proto []byte
+ status []byte
+ )
+ proto, status, resp.reason = bsplit3(line, ' ')
+
+ var ok bool
+ resp.major, resp.minor, ok = httpParseVersion(proto)
+ if !ok {
+ return resp, ErrMalformedResponse
+ }
+
+ var convErr error
+ resp.status, convErr = asciiToInt(status)
+ if convErr != nil {
+ return resp, ErrMalformedResponse
+ }
+
+ return resp, nil
+}
+
+// httpParseVersion parses major and minor version of HTTP protocol. It returns
+// parsed values and true if parse is ok.
+func httpParseVersion(bts []byte) (major, minor int, ok bool) {
+ switch {
+ case bytes.Equal(bts, httpVersion1_0):
+ return 1, 0, true
+ case bytes.Equal(bts, httpVersion1_1):
+ return 1, 1, true
+ case len(bts) < 8:
+ return 0, 0, false
+ case !bytes.Equal(bts[:5], httpVersionPrefix):
+ return 0, 0, false
+ }
+
+ bts = bts[5:]
+
+ dot := bytes.IndexByte(bts, '.')
+ if dot == -1 {
+ return 0, 0, false
+ }
+ var err error
+ major, err = asciiToInt(bts[:dot])
+ if err != nil {
+ return major, 0, false
+ }
+ minor, err = asciiToInt(bts[dot+1:])
+ if err != nil {
+ return major, minor, false
+ }
+
+ return major, minor, true
+}
+
+// httpParseHeaderLine parses HTTP header as key-value pair. It returns parsed
+// values and true if parse is ok.
+func httpParseHeaderLine(line []byte) (k, v []byte, ok bool) {
+ colon := bytes.IndexByte(line, ':')
+ if colon == -1 {
+ return nil, nil, false
+ }
+
+ k = btrim(line[:colon])
+ // TODO(gobwas): maybe use just lower here?
+ canonicalizeHeaderKey(k)
+
+ v = btrim(line[colon+1:])
+
+ return k, v, true
+}
+
+// httpGetHeader is the same as textproto.MIMEHeader.Get, except the thing,
+// that key is already canonical. This helps to increase performance.
+func httpGetHeader(h http.Header, key string) string {
+ if h == nil {
+ return ""
+ }
+ v := h[key]
+ if len(v) == 0 {
+ return ""
+ }
+ return v[0]
+}
+
+// The request MAY include a header field with the name
+// |Sec-WebSocket-Protocol|. If present, this value indicates one or more
+// comma-separated subprotocol the client wishes to speak, ordered by
+// preference. The elements that comprise this value MUST be non-empty strings
+// with characters in the range U+0021 to U+007E not including separator
+// characters as defined in [RFC2616] and MUST all be unique strings. The ABNF
+// for the value of this header field is 1#token, where the definitions of
+// constructs and rules are as given in [RFC2616].
+func strSelectProtocol(h string, check func(string) bool) (ret string, ok bool) {
+ ok = httphead.ScanTokens(strToBytes(h), func(v []byte) bool {
+ if check(btsToString(v)) {
+ ret = string(v)
+ return false
+ }
+ return true
+ })
+ return ret, ok
+}
+
+func btsSelectProtocol(h []byte, check func([]byte) bool) (ret string, ok bool) {
+ var selected []byte
+ ok = httphead.ScanTokens(h, func(v []byte) bool {
+ if check(v) {
+ selected = v
+ return false
+ }
+ return true
+ })
+ if ok && selected != nil {
+ return string(selected), true
+ }
+ return ret, ok
+}
+
+func btsSelectExtensions(h []byte, selected []httphead.Option, check func(httphead.Option) bool) ([]httphead.Option, bool) {
+ s := httphead.OptionSelector{
+ Flags: httphead.SelectCopy,
+ Check: check,
+ }
+ return s.Select(h, selected)
+}
+
+func negotiateMaybe(in httphead.Option, dest []httphead.Option, f func(httphead.Option) (httphead.Option, error)) ([]httphead.Option, error) {
+ if in.Size() == 0 {
+ return dest, nil
+ }
+ opt, err := f(in)
+ if err != nil {
+ return nil, err
+ }
+ if opt.Size() > 0 {
+ dest = append(dest, opt)
+ }
+ return dest, nil
+}
+
+func negotiateExtensions(
+ h []byte, dest []httphead.Option,
+ f func(httphead.Option) (httphead.Option, error),
+) (_ []httphead.Option, err error) {
+ index := -1
+ var current httphead.Option
+ ok := httphead.ScanOptions(h, func(i int, name, attr, val []byte) httphead.Control {
+ if i != index {
+ dest, err = negotiateMaybe(current, dest, f)
+ if err != nil {
+ return httphead.ControlBreak
+ }
+ index = i
+ current = httphead.Option{Name: name}
+ }
+ if attr != nil {
+ current.Parameters.Set(attr, val)
+ }
+ return httphead.ControlContinue
+ })
+ if !ok {
+ return nil, ErrMalformedRequest
+ }
+ return negotiateMaybe(current, dest, f)
+}
+
+func httpWriteHeader(bw *bufio.Writer, key, value string) {
+ httpWriteHeaderKey(bw, key)
+ bw.WriteString(value)
+ bw.WriteString(crlf)
+}
+
+func httpWriteHeaderBts(bw *bufio.Writer, key string, value []byte) {
+ httpWriteHeaderKey(bw, key)
+ bw.Write(value)
+ bw.WriteString(crlf)
+}
+
+func httpWriteHeaderKey(bw *bufio.Writer, key string) {
+ bw.WriteString(key)
+ bw.WriteString(colonAndSpace)
+}
+
+func httpWriteUpgradeRequest(
+ bw *bufio.Writer,
+ u *url.URL,
+ nonce []byte,
+ protocols []string,
+ extensions []httphead.Option,
+ header HandshakeHeader,
+ host string,
+) {
+ bw.WriteString("GET ")
+ bw.WriteString(u.RequestURI())
+ bw.WriteString(" HTTP/1.1\r\n")
+
+ if host == "" {
+ host = u.Host
+ }
+ httpWriteHeader(bw, headerHost, host)
+
+ httpWriteHeaderBts(bw, headerUpgrade, specHeaderValueUpgrade)
+ httpWriteHeaderBts(bw, headerConnection, specHeaderValueConnection)
+ httpWriteHeaderBts(bw, headerSecVersion, specHeaderValueSecVersion)
+
+ // NOTE: write nonce bytes as a string to prevent heap allocation –
+ // WriteString() copy given string into its inner buffer, unlike Write()
+ // which may write p directly to the underlying io.Writer – which in turn
+ // will lead to p escape.
+ httpWriteHeader(bw, headerSecKey, btsToString(nonce))
+
+ if len(protocols) > 0 {
+ httpWriteHeaderKey(bw, headerSecProtocol)
+ for i, p := range protocols {
+ if i > 0 {
+ bw.WriteString(commaAndSpace)
+ }
+ bw.WriteString(p)
+ }
+ bw.WriteString(crlf)
+ }
+
+ if len(extensions) > 0 {
+ httpWriteHeaderKey(bw, headerSecExtensions)
+ httphead.WriteOptions(bw, extensions)
+ bw.WriteString(crlf)
+ }
+
+ if header != nil {
+ header.WriteTo(bw)
+ }
+
+ bw.WriteString(crlf)
+}
+
+func httpWriteResponseUpgrade(bw *bufio.Writer, nonce []byte, hs Handshake, header HandshakeHeaderFunc) {
+ bw.WriteString(textHeadUpgrade)
+
+ httpWriteHeaderKey(bw, headerSecAccept)
+ writeAccept(bw, nonce)
+ bw.WriteString(crlf)
+
+ if hs.Protocol != "" {
+ httpWriteHeader(bw, headerSecProtocol, hs.Protocol)
+ }
+ if len(hs.Extensions) > 0 {
+ httpWriteHeaderKey(bw, headerSecExtensions)
+ httphead.WriteOptions(bw, hs.Extensions)
+ bw.WriteString(crlf)
+ }
+ if header != nil {
+ header(bw)
+ }
+
+ bw.WriteString(crlf)
+}
+
+func httpWriteResponseError(bw *bufio.Writer, err error, code int, header HandshakeHeaderFunc) {
+ switch code {
+ case http.StatusBadRequest:
+ bw.WriteString(textHeadBadRequest)
+ case http.StatusInternalServerError:
+ bw.WriteString(textHeadInternalServerError)
+ case http.StatusUpgradeRequired:
+ bw.WriteString(textHeadUpgradeRequired)
+ default:
+ writeStatusText(bw, code)
+ }
+
+ // Write custom headers.
+ if header != nil {
+ header(bw)
+ }
+
+ switch err {
+ case ErrHandshakeBadProtocol:
+ bw.WriteString(textTailErrHandshakeBadProtocol)
+ case ErrHandshakeBadMethod:
+ bw.WriteString(textTailErrHandshakeBadMethod)
+ case ErrHandshakeBadHost:
+ bw.WriteString(textTailErrHandshakeBadHost)
+ case ErrHandshakeBadUpgrade:
+ bw.WriteString(textTailErrHandshakeBadUpgrade)
+ case ErrHandshakeBadConnection:
+ bw.WriteString(textTailErrHandshakeBadConnection)
+ case ErrHandshakeBadSecAccept:
+ bw.WriteString(textTailErrHandshakeBadSecAccept)
+ case ErrHandshakeBadSecKey:
+ bw.WriteString(textTailErrHandshakeBadSecKey)
+ case ErrHandshakeBadSecVersion:
+ bw.WriteString(textTailErrHandshakeBadSecVersion)
+ case ErrHandshakeUpgradeRequired:
+ bw.WriteString(textTailErrUpgradeRequired)
+ case nil:
+ bw.WriteString(crlf)
+ default:
+ writeErrorText(bw, err)
+ }
+}
+
+func writeStatusText(bw *bufio.Writer, code int) {
+ bw.WriteString("HTTP/1.1 ")
+ bw.WriteString(strconv.Itoa(code))
+ bw.WriteByte(' ')
+ bw.WriteString(http.StatusText(code))
+ bw.WriteString(crlf)
+ bw.WriteString("Content-Type: text/plain; charset=utf-8")
+ bw.WriteString(crlf)
+}
+
+func writeErrorText(bw *bufio.Writer, err error) {
+ body := err.Error()
+ bw.WriteString("Content-Length: ")
+ bw.WriteString(strconv.Itoa(len(body)))
+ bw.WriteString(crlf)
+ bw.WriteString(crlf)
+ bw.WriteString(body)
+}
+
+// httpError is like the http.Error with WebSocket context exception.
+func httpError(w http.ResponseWriter, body string, code int) {
+ w.Header().Set("Content-Type", "text/plain; charset=utf-8")
+ w.Header().Set("Content-Length", strconv.Itoa(len(body)))
+ w.WriteHeader(code)
+ w.Write([]byte(body))
+}
+
+// statusText is a non-performant status text generator.
+// NOTE: Used only to generate constants.
+func statusText(code int) string {
+ var buf bytes.Buffer
+ bw := bufio.NewWriter(&buf)
+ writeStatusText(bw, code)
+ bw.Flush()
+ return buf.String()
+}
+
+// errorText is a non-performant error text generator.
+// NOTE: Used only to generate constants.
+func errorText(err error) string {
+ var buf bytes.Buffer
+ bw := bufio.NewWriter(&buf)
+ writeErrorText(bw, err)
+ bw.Flush()
+ return buf.String()
+}
+
+// HandshakeHeader is the interface that writes both upgrade request or
+// response headers into a given io.Writer.
+type HandshakeHeader interface {
+ io.WriterTo
+}
+
+// HandshakeHeaderString is an adapter to allow the use of headers represented
+// by ordinary string as HandshakeHeader.
+type HandshakeHeaderString string
+
+// WriteTo implements HandshakeHeader (and io.WriterTo) interface.
+func (s HandshakeHeaderString) WriteTo(w io.Writer) (int64, error) {
+ n, err := io.WriteString(w, string(s))
+ return int64(n), err
+}
+
+// HandshakeHeaderBytes is an adapter to allow the use of headers represented
+// by ordinary slice of bytes as HandshakeHeader.
+type HandshakeHeaderBytes []byte
+
+// WriteTo implements HandshakeHeader (and io.WriterTo) interface.
+func (b HandshakeHeaderBytes) WriteTo(w io.Writer) (int64, error) {
+ n, err := w.Write(b)
+ return int64(n), err
+}
+
+// HandshakeHeaderFunc is an adapter to allow the use of headers represented by
+// ordinary function as HandshakeHeader.
+type HandshakeHeaderFunc func(io.Writer) (int64, error)
+
+// WriteTo implements HandshakeHeader (and io.WriterTo) interface.
+func (f HandshakeHeaderFunc) WriteTo(w io.Writer) (int64, error) {
+ return f(w)
+}
+
+// HandshakeHeaderHTTP is an adapter to allow the use of http.Header as
+// HandshakeHeader.
+type HandshakeHeaderHTTP http.Header
+
+// WriteTo implements HandshakeHeader (and io.WriterTo) interface.
+func (h HandshakeHeaderHTTP) WriteTo(w io.Writer) (int64, error) {
+ wr := writer{w: w}
+ err := http.Header(h).Write(&wr)
+ return wr.n, err
+}
+
+type writer struct {
+ n int64
+ w io.Writer
+}
+
+func (w *writer) WriteString(s string) (int, error) {
+ n, err := io.WriteString(w.w, s)
+ w.n += int64(n)
+ return n, err
+}
+
+func (w *writer) Write(p []byte) (int, error) {
+ n, err := w.w.Write(p)
+ w.n += int64(n)
+ return n, err
+}
diff --git a/vendor/github.com/gobwas/ws/nonce.go b/vendor/github.com/gobwas/ws/nonce.go
new file mode 100644
index 0000000..7b0edd9
--- /dev/null
+++ b/vendor/github.com/gobwas/ws/nonce.go
@@ -0,0 +1,78 @@
+package ws
+
+import (
+ "bufio"
+ "bytes"
+ "crypto/sha1"
+ "encoding/base64"
+ "fmt"
+ "math/rand"
+)
+
+const (
+ // RFC6455: The value of this header field MUST be a nonce consisting of a
+ // randomly selected 16-byte value that has been base64-encoded (see
+ // Section 4 of [RFC4648]). The nonce MUST be selected randomly for each
+ // connection.
+ nonceKeySize = 16
+ nonceSize = 24 // base64.StdEncoding.EncodedLen(nonceKeySize)
+
+ // RFC6455: The value of this header field is constructed by concatenating
+ // /key/, defined above in step 4 in Section 4.2.2, with the string
+ // "258EAFA5- E914-47DA-95CA-C5AB0DC85B11", taking the SHA-1 hash of this
+ // concatenated value to obtain a 20-byte value and base64- encoding (see
+ // Section 4 of [RFC4648]) this 20-byte hash.
+ acceptSize = 28 // base64.StdEncoding.EncodedLen(sha1.Size)
+)
+
+// initNonce fills given slice with random base64-encoded nonce bytes.
+func initNonce(dst []byte) {
+ // NOTE: bts does not escape.
+ bts := make([]byte, nonceKeySize)
+ if _, err := rand.Read(bts); err != nil {
+ panic(fmt.Sprintf("rand read error: %s", err))
+ }
+ base64.StdEncoding.Encode(dst, bts)
+}
+
+// checkAcceptFromNonce reports whether given accept bytes are valid for given
+// nonce bytes.
+func checkAcceptFromNonce(accept, nonce []byte) bool {
+ if len(accept) != acceptSize {
+ return false
+ }
+ // NOTE: expect does not escape.
+ expect := make([]byte, acceptSize)
+ initAcceptFromNonce(expect, nonce)
+ return bytes.Equal(expect, accept)
+}
+
+// initAcceptFromNonce fills given slice with accept bytes generated from given
+// nonce bytes. Given buffer should be exactly acceptSize bytes.
+func initAcceptFromNonce(accept, nonce []byte) {
+ const magic = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
+
+ if len(accept) != acceptSize {
+ panic("accept buffer is invalid")
+ }
+ if len(nonce) != nonceSize {
+ panic("nonce is invalid")
+ }
+
+ p := make([]byte, nonceSize+len(magic))
+ copy(p[:nonceSize], nonce)
+ copy(p[nonceSize:], magic)
+
+ sum := sha1.Sum(p)
+ base64.StdEncoding.Encode(accept, sum[:])
+}
+
+func writeAccept(bw *bufio.Writer, nonce []byte) (int, error) {
+ accept := make([]byte, acceptSize)
+ initAcceptFromNonce(accept, nonce)
+ // NOTE: write accept bytes as a string to prevent heap allocation –
+ // WriteString() copy given string into its inner buffer, unlike Write()
+ // which may write p directly to the underlying io.Writer – which in turn
+ // will lead to p escape.
+ return bw.WriteString(btsToString(accept))
+}
diff --git a/vendor/github.com/gobwas/ws/read.go b/vendor/github.com/gobwas/ws/read.go
new file mode 100644
index 0000000..1771816
--- /dev/null
+++ b/vendor/github.com/gobwas/ws/read.go
@@ -0,0 +1,147 @@
+package ws
+
+import (
+ "encoding/binary"
+ "fmt"
+ "io"
+)
+
+// Errors used by frame reader.
+var (
+ ErrHeaderLengthMSB = fmt.Errorf("header error: the most significant bit must be 0")
+ ErrHeaderLengthUnexpected = fmt.Errorf("header error: unexpected payload length bits")
+)
+
+// ReadHeader reads a frame header from r.
+func ReadHeader(r io.Reader) (h Header, err error) {
+ // Make slice of bytes with capacity 12 that could hold any header.
+ //
+ // The maximum header size is 14, but due to the 2 hop reads,
+ // after first hop that reads first 2 constant bytes, we could reuse 2 bytes.
+ // So 14 - 2 = 12.
+ bts := make([]byte, 2, MaxHeaderSize-2)
+
+ // Prepare to hold first 2 bytes to choose size of next read.
+ _, err = io.ReadFull(r, bts)
+ if err != nil {
+ return h, err
+ }
+
+ h.Fin = bts[0]&bit0 != 0
+ h.Rsv = (bts[0] & 0x70) >> 4
+ h.OpCode = OpCode(bts[0] & 0x0f)
+
+ var extra int
+
+ if bts[1]&bit0 != 0 {
+ h.Masked = true
+ extra += 4
+ }
+
+ length := bts[1] & 0x7f
+ switch {
+ case length < 126:
+ h.Length = int64(length)
+
+ case length == 126:
+ extra += 2
+
+ case length == 127:
+ extra += 8
+
+ default:
+ err = ErrHeaderLengthUnexpected
+ return h, err
+ }
+
+ if extra == 0 {
+ return h, err
+ }
+
+ // Increase len of bts to extra bytes need to read.
+ // Overwrite first 2 bytes that was read before.
+ bts = bts[:extra]
+ _, err = io.ReadFull(r, bts)
+ if err != nil {
+ return h, err
+ }
+
+ switch {
+ case length == 126:
+ h.Length = int64(binary.BigEndian.Uint16(bts[:2]))
+ bts = bts[2:]
+
+ case length == 127:
+ if bts[0]&0x80 != 0 {
+ err = ErrHeaderLengthMSB
+ return h, err
+ }
+ h.Length = int64(binary.BigEndian.Uint64(bts[:8]))
+ bts = bts[8:]
+ }
+
+ if h.Masked {
+ copy(h.Mask[:], bts)
+ }
+
+ return h, nil
+}
+
+// ReadFrame reads a frame from r.
+// It is not designed for high optimized use case cause it makes allocation
+// for frame.Header.Length size inside to read frame payload into.
+//
+// Note that ReadFrame does not unmask payload.
+func ReadFrame(r io.Reader) (f Frame, err error) {
+ f.Header, err = ReadHeader(r)
+ if err != nil {
+ return f, err
+ }
+
+ if f.Header.Length > 0 {
+ // int(f.Header.Length) is safe here cause we have
+ // checked it for overflow above in ReadHeader.
+ f.Payload = make([]byte, int(f.Header.Length))
+ _, err = io.ReadFull(r, f.Payload)
+ }
+
+ return f, err
+}
+
+// MustReadFrame is like ReadFrame but panics if frame can not be read.
+func MustReadFrame(r io.Reader) Frame {
+ f, err := ReadFrame(r)
+ if err != nil {
+ panic(err)
+ }
+ return f
+}
+
+// ParseCloseFrameData parses close frame status code and closure reason if any provided.
+// If there is no status code in the payload
+// the empty status code is returned (code.Empty()) with empty string as a reason.
+func ParseCloseFrameData(payload []byte) (code StatusCode, reason string) {
+ if len(payload) < 2 {
+ // We returning empty StatusCode here, preventing the situation
+ // when endpoint really sent code 1005 and we should return ProtocolError on that.
+ //
+ // In other words, we ignoring this rule [RFC6455:7.1.5]:
+ // If this Close control frame contains no status code, _The WebSocket
+ // Connection Close Code_ is considered to be 1005.
+ return code, reason
+ }
+ code = StatusCode(binary.BigEndian.Uint16(payload))
+ reason = string(payload[2:])
+ return code, reason
+}
+
+// ParseCloseFrameDataUnsafe is like ParseCloseFrameData except the thing
+// that it does not copies payload bytes into reason, but prepares unsafe cast.
+func ParseCloseFrameDataUnsafe(payload []byte) (code StatusCode, reason string) {
+ if len(payload) < 2 {
+ return code, reason
+ }
+ code = StatusCode(binary.BigEndian.Uint16(payload))
+ reason = btsToString(payload[2:])
+ return code, reason
+}
diff --git a/vendor/github.com/gobwas/ws/server.go b/vendor/github.com/gobwas/ws/server.go
new file mode 100644
index 0000000..863bb22
--- /dev/null
+++ b/vendor/github.com/gobwas/ws/server.go
@@ -0,0 +1,658 @@
+package ws
+
+import (
+ "bufio"
+ "bytes"
+ "fmt"
+ "io"
+ "net"
+ "net/http"
+ "strings"
+ "time"
+
+ "github.com/gobwas/httphead"
+ "github.com/gobwas/pool/pbufio"
+)
+
+// Constants used by ConnUpgrader.
+const (
+ DefaultServerReadBufferSize = 4096
+ DefaultServerWriteBufferSize = 512
+)
+
+// Errors used by both client and server when preparing WebSocket handshake.
+var (
+ ErrHandshakeBadProtocol = RejectConnectionError(
+ RejectionStatus(http.StatusHTTPVersionNotSupported),
+ RejectionReason("handshake error: bad HTTP protocol version"),
+ )
+ ErrHandshakeBadMethod = RejectConnectionError(
+ RejectionStatus(http.StatusMethodNotAllowed),
+ RejectionReason("handshake error: bad HTTP request method"),
+ )
+ ErrHandshakeBadHost = RejectConnectionError(
+ RejectionStatus(http.StatusBadRequest),
+ RejectionReason(fmt.Sprintf("handshake error: bad %q header", headerHost)),
+ )
+ ErrHandshakeBadUpgrade = RejectConnectionError(
+ RejectionStatus(http.StatusBadRequest),
+ RejectionReason(fmt.Sprintf("handshake error: bad %q header", headerUpgrade)),
+ )
+ ErrHandshakeBadConnection = RejectConnectionError(
+ RejectionStatus(http.StatusBadRequest),
+ RejectionReason(fmt.Sprintf("handshake error: bad %q header", headerConnection)),
+ )
+ ErrHandshakeBadSecAccept = RejectConnectionError(
+ RejectionStatus(http.StatusBadRequest),
+ RejectionReason(fmt.Sprintf("handshake error: bad %q header", headerSecAccept)),
+ )
+ ErrHandshakeBadSecKey = RejectConnectionError(
+ RejectionStatus(http.StatusBadRequest),
+ RejectionReason(fmt.Sprintf("handshake error: bad %q header", headerSecKey)),
+ )
+ ErrHandshakeBadSecVersion = RejectConnectionError(
+ RejectionStatus(http.StatusBadRequest),
+ RejectionReason(fmt.Sprintf("handshake error: bad %q header", headerSecVersion)),
+ )
+)
+
+// ErrMalformedResponse is returned by Dialer to indicate that server response
+// can not be parsed.
+var ErrMalformedResponse = fmt.Errorf("malformed HTTP response")
+
+// ErrMalformedRequest is returned when HTTP request can not be parsed.
+var ErrMalformedRequest = RejectConnectionError(
+ RejectionStatus(http.StatusBadRequest),
+ RejectionReason("malformed HTTP request"),
+)
+
+// ErrHandshakeUpgradeRequired is returned by Upgrader to indicate that
+// connection is rejected because given WebSocket version is malformed.
+//
+// According to RFC6455:
+// If this version does not match a version understood by the server, the
+// server MUST abort the WebSocket handshake described in this section and
+// instead send an appropriate HTTP error code (such as 426 Upgrade Required)
+// and a |Sec-WebSocket-Version| header field indicating the version(s) the
+// server is capable of understanding.
+var ErrHandshakeUpgradeRequired = RejectConnectionError(
+ RejectionStatus(http.StatusUpgradeRequired),
+ RejectionHeader(HandshakeHeaderString(headerSecVersion+": 13\r\n")),
+ RejectionReason(fmt.Sprintf("handshake error: bad %q header", headerSecVersion)),
+)
+
+// ErrNotHijacker is an error returned when http.ResponseWriter does not
+// implement http.Hijacker interface.
+var ErrNotHijacker = RejectConnectionError(
+ RejectionStatus(http.StatusInternalServerError),
+ RejectionReason("given http.ResponseWriter is not a http.Hijacker"),
+)
+
+// DefaultHTTPUpgrader is an HTTPUpgrader that holds no options and is used by
+// UpgradeHTTP function.
+var DefaultHTTPUpgrader HTTPUpgrader
+
+// UpgradeHTTP is like HTTPUpgrader{}.Upgrade().
+func UpgradeHTTP(r *http.Request, w http.ResponseWriter) (net.Conn, *bufio.ReadWriter, Handshake, error) {
+ return DefaultHTTPUpgrader.Upgrade(r, w)
+}
+
+// DefaultUpgrader is an Upgrader that holds no options and is used by Upgrade
+// function.
+var DefaultUpgrader Upgrader
+
+// Upgrade is like Upgrader{}.Upgrade().
+func Upgrade(conn io.ReadWriter) (Handshake, error) {
+ return DefaultUpgrader.Upgrade(conn)
+}
+
+// HTTPUpgrader contains options for upgrading connection to websocket from
+// net/http Handler arguments.
+type HTTPUpgrader struct {
+ // Timeout is the maximum amount of time an Upgrade() will spent while
+ // writing handshake response.
+ //
+ // The default is no timeout.
+ Timeout time.Duration
+
+ // Header is an optional http.Header mapping that could be used to
+ // write additional headers to the handshake response.
+ //
+ // Note that if present, it will be written in any result of handshake.
+ Header http.Header
+
+ // Protocol is the select function that is used to select subprotocol from
+ // list requested by client. If this field is set, then the first matched
+ // protocol is sent to a client as negotiated.
+ Protocol func(string) bool
+
+ // Extension is the select function that is used to select extensions from
+ // list requested by client. If this field is set, then the all matched
+ // extensions are sent to a client as negotiated.
+ //
+ // Deprecated: use Negotiate instead.
+ Extension func(httphead.Option) bool
+
+ // Negotiate is the callback that is used to negotiate extensions from
+ // the client's offer. If this field is set, then the returned non-zero
+ // extensions are sent to the client as accepted extensions in the
+ // response.
+ //
+ // The argument is only valid until the Negotiate callback returns.
+ //
+ // If returned error is non-nil then connection is rejected and response is
+ // sent with appropriate HTTP error code and body set to error message.
+ //
+ // RejectConnectionError could be used to get more control on response.
+ Negotiate func(httphead.Option) (httphead.Option, error)
+}
+
+// Upgrade upgrades http connection to the websocket connection.
+//
+// It hijacks net.Conn from w and returns received net.Conn and
+// bufio.ReadWriter. On successful handshake it returns Handshake struct
+// describing handshake info.
+func (u HTTPUpgrader) Upgrade(r *http.Request, w http.ResponseWriter) (conn net.Conn, rw *bufio.ReadWriter, hs Handshake, err error) {
+ // Hijack connection first to get the ability to write rejection errors the
+ // same way as in Upgrader.
+ conn, rw, err = hijack(w)
+ if err != nil {
+ httpError(w, err.Error(), http.StatusInternalServerError)
+ return conn, rw, hs, err
+ }
+
+ // See https://tools.ietf.org/html/rfc6455#section-4.1
+ // The method of the request MUST be GET, and the HTTP version MUST be at least 1.1.
+ var nonce string
+ if r.Method != http.MethodGet {
+ err = ErrHandshakeBadMethod
+ } else if r.ProtoMajor < 1 || (r.ProtoMajor == 1 && r.ProtoMinor < 1) {
+ err = ErrHandshakeBadProtocol
+ } else if r.Host == "" {
+ err = ErrHandshakeBadHost
+ } else if u := httpGetHeader(r.Header, headerUpgradeCanonical); u != "websocket" && !strings.EqualFold(u, "websocket") {
+ err = ErrHandshakeBadUpgrade
+ } else if c := httpGetHeader(r.Header, headerConnectionCanonical); c != "Upgrade" && !strHasToken(c, "upgrade") {
+ err = ErrHandshakeBadConnection
+ } else if nonce = httpGetHeader(r.Header, headerSecKeyCanonical); len(nonce) != nonceSize {
+ err = ErrHandshakeBadSecKey
+ } else if v := httpGetHeader(r.Header, headerSecVersionCanonical); v != "13" {
+ // According to RFC6455:
+ //
+ // If this version does not match a version understood by the server,
+ // the server MUST abort the WebSocket handshake described in this
+ // section and instead send an appropriate HTTP error code (such as 426
+ // Upgrade Required) and a |Sec-WebSocket-Version| header field
+ // indicating the version(s) the server is capable of understanding.
+ //
+ // So we branching here cause empty or not present version does not
+ // meet the ABNF rules of RFC6455:
+ //
+ // version = DIGIT | (NZDIGIT DIGIT) |
+ // ("1" DIGIT DIGIT) | ("2" DIGIT DIGIT)
+ // ; Limited to 0-255 range, with no leading zeros
+ //
+ // That is, if version is really invalid – we sent 426 status, if it
+ // not present or empty – it is 400.
+ if v != "" {
+ err = ErrHandshakeUpgradeRequired
+ } else {
+ err = ErrHandshakeBadSecVersion
+ }
+ }
+ if check := u.Protocol; err == nil && check != nil {
+ ps := r.Header[headerSecProtocolCanonical]
+ for i := 0; i < len(ps) && err == nil && hs.Protocol == ""; i++ {
+ var ok bool
+ hs.Protocol, ok = strSelectProtocol(ps[i], check)
+ if !ok {
+ err = ErrMalformedRequest
+ }
+ }
+ }
+ if f := u.Negotiate; err == nil && f != nil {
+ for _, h := range r.Header[headerSecExtensionsCanonical] {
+ hs.Extensions, err = negotiateExtensions(strToBytes(h), hs.Extensions, f)
+ if err != nil {
+ break
+ }
+ }
+ }
+ // DEPRECATED path.
+ if check := u.Extension; err == nil && check != nil && u.Negotiate == nil {
+ xs := r.Header[headerSecExtensionsCanonical]
+ for i := 0; i < len(xs) && err == nil; i++ {
+ var ok bool
+ hs.Extensions, ok = btsSelectExtensions(strToBytes(xs[i]), hs.Extensions, check)
+ if !ok {
+ err = ErrMalformedRequest
+ }
+ }
+ }
+
+ // Clear deadlines set by server.
+ conn.SetDeadline(noDeadline)
+ if t := u.Timeout; t != 0 {
+ conn.SetWriteDeadline(time.Now().Add(t))
+ defer conn.SetWriteDeadline(noDeadline)
+ }
+
+ var header handshakeHeader
+ if h := u.Header; h != nil {
+ header[0] = HandshakeHeaderHTTP(h)
+ }
+ if err == nil {
+ httpWriteResponseUpgrade(rw.Writer, strToBytes(nonce), hs, header.WriteTo)
+ err = rw.Writer.Flush()
+ } else {
+ var code int
+ if rej, ok := err.(*ConnectionRejectedError); ok {
+ code = rej.code
+ header[1] = rej.header
+ }
+ if code == 0 {
+ code = http.StatusInternalServerError
+ }
+ httpWriteResponseError(rw.Writer, err, code, header.WriteTo)
+ // Do not store Flush() error to not override already existing one.
+ _ = rw.Writer.Flush()
+ }
+ return conn, rw, hs, err
+}
+
+// Upgrader contains options for upgrading connection to websocket.
+type Upgrader struct {
+ // ReadBufferSize and WriteBufferSize is an I/O buffer sizes.
+ // They used to read and write http data while upgrading to WebSocket.
+ // Allocated buffers are pooled with sync.Pool to avoid extra allocations.
+ //
+ // If a size is zero then default value is used.
+ //
+ // Usually it is useful to set read buffer size bigger than write buffer
+ // size because incoming request could contain long header values, such as
+ // Cookie. Response, in other way, could be big only if user write multiple
+ // custom headers. Usually response takes less than 256 bytes.
+ ReadBufferSize, WriteBufferSize int
+
+ // Protocol is a select function that is used to select subprotocol
+ // from list requested by client. If this field is set, then the first matched
+ // protocol is sent to a client as negotiated.
+ //
+ // The argument is only valid until the callback returns.
+ Protocol func([]byte) bool
+
+ // ProtocolCustrom allow user to parse Sec-WebSocket-Protocol header manually.
+ // Note that returned bytes must be valid until Upgrade returns.
+ // If ProtocolCustom is set, it used instead of Protocol function.
+ ProtocolCustom func([]byte) (string, bool)
+
+ // Extension is a select function that is used to select extensions
+ // from list requested by client. If this field is set, then the all matched
+ // extensions are sent to a client as negotiated.
+ //
+ // Note that Extension may be called multiple times and implementations
+ // must track uniqueness of accepted extensions manually.
+ //
+ // The argument is only valid until the callback returns.
+ //
+ // According to the RFC6455 order of extensions passed by a client is
+ // significant. That is, returning true from this function means that no
+ // other extension with the same name should be checked because server
+ // accepted the most preferable extension right now:
+ // "Note that the order of extensions is significant. Any interactions between
+ // multiple extensions MAY be defined in the documents defining the extensions.
+ // In the absence of such definitions, the interpretation is that the header
+ // fields listed by the client in its request represent a preference of the
+ // header fields it wishes to use, with the first options listed being most
+ // preferable."
+ //
+ // Deprecated: use Negotiate instead.
+ Extension func(httphead.Option) bool
+
+ // ExtensionCustom allow user to parse Sec-WebSocket-Extensions header
+ // manually.
+ //
+ // If ExtensionCustom() decides to accept received extension, it must
+ // append appropriate option to the given slice of httphead.Option.
+ // It returns results of append() to the given slice and a flag that
+ // reports whether given header value is wellformed or not.
+ //
+ // Note that ExtensionCustom may be called multiple times and
+ // implementations must track uniqueness of accepted extensions manually.
+ //
+ // Note that returned options should be valid until Upgrade returns.
+ // If ExtensionCustom is set, it used instead of Extension function.
+ ExtensionCustom func([]byte, []httphead.Option) ([]httphead.Option, bool)
+
+ // Negotiate is the callback that is used to negotiate extensions from
+ // the client's offer. If this field is set, then the returned non-zero
+ // extensions are sent to the client as accepted extensions in the
+ // response.
+ //
+ // The argument is only valid until the Negotiate callback returns.
+ //
+ // If returned error is non-nil then connection is rejected and response is
+ // sent with appropriate HTTP error code and body set to error message.
+ //
+ // RejectConnectionError could be used to get more control on response.
+ Negotiate func(httphead.Option) (httphead.Option, error)
+
+ // Header is an optional HandshakeHeader instance that could be used to
+ // write additional headers to the handshake response.
+ //
+ // It used instead of any key-value mappings to avoid allocations in user
+ // land.
+ //
+ // Note that if present, it will be written in any result of handshake.
+ Header HandshakeHeader
+
+ // OnRequest is a callback that will be called after request line
+ // successful parsing.
+ //
+ // The arguments are only valid until the callback returns.
+ //
+ // If returned error is non-nil then connection is rejected and response is
+ // sent with appropriate HTTP error code and body set to error message.
+ //
+ // RejectConnectionError could be used to get more control on response.
+ OnRequest func(uri []byte) error
+
+ // OnHost is a callback that will be called after "Host" header successful
+ // parsing.
+ //
+ // It is separated from OnHeader callback because the Host header must be
+ // present in each request since HTTP/1.1. Thus Host header is non-optional
+ // and required for every WebSocket handshake.
+ //
+ // The arguments are only valid until the callback returns.
+ //
+ // If returned error is non-nil then connection is rejected and response is
+ // sent with appropriate HTTP error code and body set to error message.
+ //
+ // RejectConnectionError could be used to get more control on response.
+ OnHost func(host []byte) error
+
+ // OnHeader is a callback that will be called after successful parsing of
+ // header, that is not used during WebSocket handshake procedure. That is,
+ // it will be called with non-websocket headers, which could be relevant
+ // for application-level logic.
+ //
+ // The arguments are only valid until the callback returns.
+ //
+ // If returned error is non-nil then connection is rejected and response is
+ // sent with appropriate HTTP error code and body set to error message.
+ //
+ // RejectConnectionError could be used to get more control on response.
+ OnHeader func(key, value []byte) error
+
+ // OnBeforeUpgrade is a callback that will be called before sending
+ // successful upgrade response.
+ //
+ // Setting OnBeforeUpgrade allows user to make final application-level
+ // checks and decide whether this connection is allowed to successfully
+ // upgrade to WebSocket.
+ //
+ // It must return non-nil either HandshakeHeader or error and never both.
+ //
+ // If returned error is non-nil then connection is rejected and response is
+ // sent with appropriate HTTP error code and body set to error message.
+ //
+ // RejectConnectionError could be used to get more control on response.
+ OnBeforeUpgrade func() (header HandshakeHeader, err error)
+}
+
+// Upgrade zero-copy upgrades connection to WebSocket. It interprets given conn
+// as connection with incoming HTTP Upgrade request.
+//
+// It is a caller responsibility to manage i/o timeouts on conn.
+//
+// Non-nil error means that request for the WebSocket upgrade is invalid or
+// malformed and usually connection should be closed.
+// Even when error is non-nil Upgrade will write appropriate response into
+// connection in compliance with RFC.
+func (u Upgrader) Upgrade(conn io.ReadWriter) (hs Handshake, err error) {
+ // headerSeen constants helps to report whether or not some header was seen
+ // during reading request bytes.
+ const (
+ headerSeenHost = 1 << iota
+ headerSeenUpgrade
+ headerSeenConnection
+ headerSeenSecVersion
+ headerSeenSecKey
+
+ // headerSeenAll is the value that we expect to receive at the end of
+ // headers read/parse loop.
+ headerSeenAll = 0 |
+ headerSeenHost |
+ headerSeenUpgrade |
+ headerSeenConnection |
+ headerSeenSecVersion |
+ headerSeenSecKey
+ )
+
+ // Prepare I/O buffers.
+ // TODO(gobwas): make it configurable.
+ br := pbufio.GetReader(conn,
+ nonZero(u.ReadBufferSize, DefaultServerReadBufferSize),
+ )
+ bw := pbufio.GetWriter(conn,
+ nonZero(u.WriteBufferSize, DefaultServerWriteBufferSize),
+ )
+ defer func() {
+ pbufio.PutReader(br)
+ pbufio.PutWriter(bw)
+ }()
+
+ // Read HTTP request line like "GET /ws HTTP/1.1".
+ rl, err := readLine(br)
+ if err != nil {
+ return hs, err
+ }
+ // Parse request line data like HTTP version, uri and method.
+ req, err := httpParseRequestLine(rl)
+ if err != nil {
+ return hs, err
+ }
+
+ // Prepare stack-based handshake header list.
+ header := handshakeHeader{
+ 0: u.Header,
+ }
+
+ // Parse and check HTTP request.
+ // As RFC6455 says:
+ // The client's opening handshake consists of the following parts. If the
+ // server, while reading the handshake, finds that the client did not
+ // send a handshake that matches the description below (note that as per
+ // [RFC2616], the order of the header fields is not important), including
+ // but not limited to any violations of the ABNF grammar specified for
+ // the components of the handshake, the server MUST stop processing the
+ // client's handshake and return an HTTP response with an appropriate
+ // error code (such as 400 Bad Request).
+ //
+ // See https://tools.ietf.org/html/rfc6455#section-4.2.1
+
+ // An HTTP/1.1 or higher GET request, including a "Request-URI".
+ //
+ // Even if RFC says "1.1 or higher" without mentioning the part of the
+ // version, we apply it only to minor part.
+ switch {
+ case req.major != 1 || req.minor < 1:
+ // Abort processing the whole request because we do not even know how
+ // to actually parse it.
+ err = ErrHandshakeBadProtocol
+
+ case btsToString(req.method) != http.MethodGet:
+ err = ErrHandshakeBadMethod
+
+ default:
+ if onRequest := u.OnRequest; onRequest != nil {
+ err = onRequest(req.uri)
+ }
+ }
+ // Start headers read/parse loop.
+ var (
+ // headerSeen reports which header was seen by setting corresponding
+ // bit on.
+ headerSeen byte
+
+ nonce = make([]byte, nonceSize)
+ )
+ for err == nil {
+ line, e := readLine(br)
+ if e != nil {
+ return hs, e
+ }
+ if len(line) == 0 {
+ // Blank line, no more lines to read.
+ break
+ }
+
+ k, v, ok := httpParseHeaderLine(line)
+ if !ok {
+ err = ErrMalformedRequest
+ break
+ }
+
+ switch btsToString(k) {
+ case headerHostCanonical:
+ headerSeen |= headerSeenHost
+ if onHost := u.OnHost; onHost != nil {
+ err = onHost(v)
+ }
+
+ case headerUpgradeCanonical:
+ headerSeen |= headerSeenUpgrade
+ if !bytes.Equal(v, specHeaderValueUpgrade) && !bytes.EqualFold(v, specHeaderValueUpgrade) {
+ err = ErrHandshakeBadUpgrade
+ }
+
+ case headerConnectionCanonical:
+ headerSeen |= headerSeenConnection
+ if !bytes.Equal(v, specHeaderValueConnection) && !btsHasToken(v, specHeaderValueConnectionLower) {
+ err = ErrHandshakeBadConnection
+ }
+
+ case headerSecVersionCanonical:
+ headerSeen |= headerSeenSecVersion
+ if !bytes.Equal(v, specHeaderValueSecVersion) {
+ err = ErrHandshakeUpgradeRequired
+ }
+
+ case headerSecKeyCanonical:
+ headerSeen |= headerSeenSecKey
+ if len(v) != nonceSize {
+ err = ErrHandshakeBadSecKey
+ } else {
+ copy(nonce, v)
+ }
+
+ case headerSecProtocolCanonical:
+ if custom, check := u.ProtocolCustom, u.Protocol; hs.Protocol == "" && (custom != nil || check != nil) {
+ var ok bool
+ if custom != nil {
+ hs.Protocol, ok = custom(v)
+ } else {
+ hs.Protocol, ok = btsSelectProtocol(v, check)
+ }
+ if !ok {
+ err = ErrMalformedRequest
+ }
+ }
+
+ case headerSecExtensionsCanonical:
+ if f := u.Negotiate; err == nil && f != nil {
+ hs.Extensions, err = negotiateExtensions(v, hs.Extensions, f)
+ }
+ // DEPRECATED path.
+ if custom, check := u.ExtensionCustom, u.Extension; u.Negotiate == nil && (custom != nil || check != nil) {
+ var ok bool
+ if custom != nil {
+ hs.Extensions, ok = custom(v, hs.Extensions)
+ } else {
+ hs.Extensions, ok = btsSelectExtensions(v, hs.Extensions, check)
+ }
+ if !ok {
+ err = ErrMalformedRequest
+ }
+ }
+
+ default:
+ if onHeader := u.OnHeader; onHeader != nil {
+ err = onHeader(k, v)
+ }
+ }
+ }
+ switch {
+ case err == nil && headerSeen != headerSeenAll:
+ switch {
+ case headerSeen&headerSeenHost == 0:
+ // As RFC2616 says:
+ // A client MUST include a Host header field in all HTTP/1.1
+ // request messages. If the requested URI does not include an
+ // Internet host name for the service being requested, then the
+ // Host header field MUST be given with an empty value. An
+ // HTTP/1.1 proxy MUST ensure that any request message it
+ // forwards does contain an appropriate Host header field that
+ // identifies the service being requested by the proxy. All
+ // Internet-based HTTP/1.1 servers MUST respond with a 400 (Bad
+ // Request) status code to any HTTP/1.1 request message which
+ // lacks a Host header field.
+ err = ErrHandshakeBadHost
+ case headerSeen&headerSeenUpgrade == 0:
+ err = ErrHandshakeBadUpgrade
+ case headerSeen&headerSeenConnection == 0:
+ err = ErrHandshakeBadConnection
+ case headerSeen&headerSeenSecVersion == 0:
+ // In case of empty or not present version we do not send 426 status,
+ // because it does not meet the ABNF rules of RFC6455:
+ //
+ // version = DIGIT | (NZDIGIT DIGIT) |
+ // ("1" DIGIT DIGIT) | ("2" DIGIT DIGIT)
+ // ; Limited to 0-255 range, with no leading zeros
+ //
+ // That is, if version is really invalid – we sent 426 status as above, if it
+ // not present – it is 400.
+ err = ErrHandshakeBadSecVersion
+ case headerSeen&headerSeenSecKey == 0:
+ err = ErrHandshakeBadSecKey
+ default:
+ panic("unknown headers state")
+ }
+
+ case err == nil && u.OnBeforeUpgrade != nil:
+ header[1], err = u.OnBeforeUpgrade()
+ }
+ if err != nil {
+ var code int
+ if rej, ok := err.(*ConnectionRejectedError); ok {
+ code = rej.code
+ header[1] = rej.header
+ }
+ if code == 0 {
+ code = http.StatusInternalServerError
+ }
+ httpWriteResponseError(bw, err, code, header.WriteTo)
+ // Do not store Flush() error to not override already existing one.
+ _ = bw.Flush()
+ return hs, err
+ }
+
+ httpWriteResponseUpgrade(bw, nonce, hs, header.WriteTo)
+ err = bw.Flush()
+
+ return hs, err
+}
+
+type handshakeHeader [2]HandshakeHeader
+
+func (hs handshakeHeader) WriteTo(w io.Writer) (n int64, err error) {
+ for i := 0; i < len(hs) && err == nil; i++ {
+ if h := hs[i]; h != nil {
+ var m int64
+ m, err = h.WriteTo(w)
+ n += m
+ }
+ }
+ return n, err
+}
diff --git a/vendor/github.com/gobwas/ws/util.go b/vendor/github.com/gobwas/ws/util.go
new file mode 100644
index 0000000..1dd5aa6
--- /dev/null
+++ b/vendor/github.com/gobwas/ws/util.go
@@ -0,0 +1,199 @@
+package ws
+
+import (
+ "bufio"
+ "bytes"
+ "fmt"
+
+ "github.com/gobwas/httphead"
+)
+
+// SelectFromSlice creates accept function that could be used as Protocol/Extension
+// select during upgrade.
+func SelectFromSlice(accept []string) func(string) bool {
+ if len(accept) > 16 {
+ mp := make(map[string]struct{}, len(accept))
+ for _, p := range accept {
+ mp[p] = struct{}{}
+ }
+ return func(p string) bool {
+ _, ok := mp[p]
+ return ok
+ }
+ }
+ return func(p string) bool {
+ for _, ok := range accept {
+ if p == ok {
+ return true
+ }
+ }
+ return false
+ }
+}
+
+// SelectEqual creates accept function that could be used as Protocol/Extension
+// select during upgrade.
+func SelectEqual(v string) func(string) bool {
+ return func(p string) bool {
+ return v == p
+ }
+}
+
+// asciiToInt converts bytes to int.
+func asciiToInt(bts []byte) (ret int, err error) {
+ // ASCII numbers all start with the high-order bits 0011.
+ // If you see that, and the next bits are 0-9 (0000 - 1001) you can grab those
+ // bits and interpret them directly as an integer.
+ var n int
+ if n = len(bts); n < 1 {
+ return 0, fmt.Errorf("converting empty bytes to int")
+ }
+ for i := 0; i < n; i++ {
+ if bts[i]&0xf0 != 0x30 {
+ return 0, fmt.Errorf("%s is not a numeric character", string(bts[i]))
+ }
+ ret += int(bts[i]&0xf) * pow(10, n-i-1)
+ }
+ return ret, nil
+}
+
+// pow for integers implementation.
+// See Donald Knuth, The Art of Computer Programming, Volume 2, Section 4.6.3.
+func pow(a, b int) int {
+ p := 1
+ for b > 0 {
+ if b&1 != 0 {
+ p *= a
+ }
+ b >>= 1
+ a *= a
+ }
+ return p
+}
+
+func bsplit3(bts []byte, sep byte) (b1, b2, b3 []byte) {
+ a := bytes.IndexByte(bts, sep)
+ b := bytes.IndexByte(bts[a+1:], sep)
+ if a == -1 || b == -1 {
+ return bts, nil, nil
+ }
+ b += a + 1
+ return bts[:a], bts[a+1 : b], bts[b+1:]
+}
+
+func btrim(bts []byte) []byte {
+ var i, j int
+ for i = 0; i < len(bts) && (bts[i] == ' ' || bts[i] == '\t'); {
+ i++
+ }
+ for j = len(bts); j > i && (bts[j-1] == ' ' || bts[j-1] == '\t'); {
+ j--
+ }
+ return bts[i:j]
+}
+
+func strHasToken(header, token string) (has bool) {
+ return btsHasToken(strToBytes(header), strToBytes(token))
+}
+
+func btsHasToken(header, token []byte) (has bool) {
+ httphead.ScanTokens(header, func(v []byte) bool {
+ has = bytes.EqualFold(v, token)
+ return !has
+ })
+ return has
+}
+
+const (
+ toLower = 'a' - 'A' // for use with OR.
+ toUpper = ^byte(toLower) // for use with AND.
+ toLower8 = uint64(toLower) |
+ uint64(toLower)<<8 |
+ uint64(toLower)<<16 |
+ uint64(toLower)<<24 |
+ uint64(toLower)<<32 |
+ uint64(toLower)<<40 |
+ uint64(toLower)<<48 |
+ uint64(toLower)<<56
+)
+
+// Algorithm below is like standard textproto/CanonicalMIMEHeaderKey, except
+// that it operates with slice of bytes and modifies it inplace without copying.
+func canonicalizeHeaderKey(k []byte) {
+ upper := true
+ for i, c := range k {
+ if upper && 'a' <= c && c <= 'z' {
+ k[i] &= toUpper
+ } else if !upper && 'A' <= c && c <= 'Z' {
+ k[i] |= toLower
+ }
+ upper = c == '-'
+ }
+}
+
+// readLine reads line from br. It reads until '\n' and returns bytes without
+// '\n' or '\r\n' at the end.
+// It returns err if and only if line does not end in '\n'. Note that read
+// bytes returned in any case of error.
+//
+// It is much like the textproto/Reader.ReadLine() except the thing that it
+// returns raw bytes, instead of string. That is, it avoids copying bytes read
+// from br.
+//
+// textproto/Reader.ReadLineBytes() is also makes copy of resulting bytes to be
+// safe with future I/O operations on br.
+//
+// We could control I/O operations on br and do not need to make additional
+// copy for safety.
+//
+// NOTE: it may return copied flag to notify that returned buffer is safe to
+// use.
+func readLine(br *bufio.Reader) ([]byte, error) {
+ var line []byte
+ for {
+ bts, err := br.ReadSlice('\n')
+ if err == bufio.ErrBufferFull {
+ // Copy bytes because next read will discard them.
+ line = append(line, bts...)
+ continue
+ }
+
+ // Avoid copy of single read.
+ if line == nil {
+ line = bts
+ } else {
+ line = append(line, bts...)
+ }
+
+ if err != nil {
+ return line, err
+ }
+
+ // Size of line is at least 1.
+ // In other case bufio.ReadSlice() returns error.
+ n := len(line)
+
+ // Cut '\n' or '\r\n'.
+ if n > 1 && line[n-2] == '\r' {
+ line = line[:n-2]
+ } else {
+ line = line[:n-1]
+ }
+
+ return line, nil
+ }
+}
+
+func min(a, b int) int {
+ if a < b {
+ return a
+ }
+ return b
+}
+
+func nonZero(a, b int) int {
+ if a != 0 {
+ return a
+ }
+ return b
+}
diff --git a/vendor/github.com/gobwas/ws/util_purego.go b/vendor/github.com/gobwas/ws/util_purego.go
new file mode 100644
index 0000000..449b3fd
--- /dev/null
+++ b/vendor/github.com/gobwas/ws/util_purego.go
@@ -0,0 +1,12 @@
+//go:build purego
+// +build purego
+
+package ws
+
+func strToBytes(str string) (bts []byte) {
+ return []byte(str)
+}
+
+func btsToString(bts []byte) (str string) {
+ return string(bts)
+}
diff --git a/vendor/github.com/gobwas/ws/util_unsafe.go b/vendor/github.com/gobwas/ws/util_unsafe.go
new file mode 100644
index 0000000..b732297
--- /dev/null
+++ b/vendor/github.com/gobwas/ws/util_unsafe.go
@@ -0,0 +1,22 @@
+//go:build !purego
+// +build !purego
+
+package ws
+
+import (
+ "reflect"
+ "unsafe"
+)
+
+func strToBytes(str string) (bts []byte) {
+ s := (*reflect.StringHeader)(unsafe.Pointer(&str))
+ b := (*reflect.SliceHeader)(unsafe.Pointer(&bts))
+ b.Data = s.Data
+ b.Len = s.Len
+ b.Cap = s.Len
+ return bts
+}
+
+func btsToString(bts []byte) (str string) {
+ return *(*string)(unsafe.Pointer(&bts))
+}
diff --git a/vendor/github.com/gobwas/ws/write.go b/vendor/github.com/gobwas/ws/write.go
new file mode 100644
index 0000000..94557c6
--- /dev/null
+++ b/vendor/github.com/gobwas/ws/write.go
@@ -0,0 +1,104 @@
+package ws
+
+import (
+ "encoding/binary"
+ "io"
+)
+
+// Header size length bounds in bytes.
+const (
+ MaxHeaderSize = 14
+ MinHeaderSize = 2
+)
+
+const (
+ bit0 = 0x80
+ bit1 = 0x40
+ bit2 = 0x20
+ bit3 = 0x10
+ bit4 = 0x08
+ bit5 = 0x04
+ bit6 = 0x02
+ bit7 = 0x01
+
+ len7 = int64(125)
+ len16 = int64(^(uint16(0)))
+ len64 = int64(^(uint64(0)) >> 1)
+)
+
+// HeaderSize returns number of bytes that are needed to encode given header.
+// It returns -1 if header is malformed.
+func HeaderSize(h Header) (n int) {
+ switch {
+ case h.Length < 126:
+ n = 2
+ case h.Length <= len16:
+ n = 4
+ case h.Length <= len64:
+ n = 10
+ default:
+ return -1
+ }
+ if h.Masked {
+ n += len(h.Mask)
+ }
+ return n
+}
+
+// WriteHeader writes header binary representation into w.
+func WriteHeader(w io.Writer, h Header) error {
+ // Make slice of bytes with capacity 14 that could hold any header.
+ bts := make([]byte, MaxHeaderSize)
+
+ if h.Fin {
+ bts[0] |= bit0
+ }
+ bts[0] |= h.Rsv << 4
+ bts[0] |= byte(h.OpCode)
+
+ var n int
+ switch {
+ case h.Length <= len7:
+ bts[1] = byte(h.Length)
+ n = 2
+
+ case h.Length <= len16:
+ bts[1] = 126
+ binary.BigEndian.PutUint16(bts[2:4], uint16(h.Length))
+ n = 4
+
+ case h.Length <= len64:
+ bts[1] = 127
+ binary.BigEndian.PutUint64(bts[2:10], uint64(h.Length))
+ n = 10
+
+ default:
+ return ErrHeaderLengthUnexpected
+ }
+
+ if h.Masked {
+ bts[1] |= bit0
+ n += copy(bts[n:], h.Mask[:])
+ }
+
+ _, err := w.Write(bts[:n])
+
+ return err
+}
+
+// WriteFrame writes frame binary representation into w.
+func WriteFrame(w io.Writer, f Frame) error {
+ err := WriteHeader(w, f.Header)
+ if err != nil {
+ return err
+ }
+ _, err = w.Write(f.Payload)
+ return err
+}
+
+// MustWriteFrame is like WriteFrame but panics if frame can not be read.
+func MustWriteFrame(w io.Writer, f Frame) {
+ if err := WriteFrame(w, f); err != nil {
+ panic(err)
+ }
+}
diff --git a/vendor/github.com/gobwas/ws/wsflate/cbuf.go b/vendor/github.com/gobwas/ws/wsflate/cbuf.go
new file mode 100644
index 0000000..5e2c445
--- /dev/null
+++ b/vendor/github.com/gobwas/ws/wsflate/cbuf.go
@@ -0,0 +1,134 @@
+package wsflate
+
+import (
+ "io"
+)
+
+// cbuf is a tiny proxy-buffer that writes all but 4 last bytes to the
+// destination.
+type cbuf struct {
+ buf [4]byte
+ n int
+ dst io.Writer
+ err error
+}
+
+// Write implements io.Writer interface.
+func (c *cbuf) Write(p []byte) (int, error) {
+ if c.err != nil {
+ return 0, c.err
+ }
+ head, tail := c.split(p)
+ n := c.n + len(tail)
+ if n > len(c.buf) {
+ x := n - len(c.buf)
+ c.flush(c.buf[:x])
+ copy(c.buf[:], c.buf[x:])
+ c.n -= x
+ }
+ if len(head) > 0 {
+ c.flush(head)
+ }
+ copy(c.buf[c.n:], tail)
+ c.n = min(c.n+len(tail), len(c.buf))
+ return len(p), c.err
+}
+
+func (c *cbuf) flush(p []byte) {
+ if c.err == nil {
+ _, c.err = c.dst.Write(p)
+ }
+}
+
+func (c *cbuf) split(p []byte) (head, tail []byte) {
+ if n := len(p); n > len(c.buf) {
+ x := n - len(c.buf)
+ head = p[:x]
+ tail = p[x:]
+ return head, tail
+ }
+ return nil, p
+}
+
+func (c *cbuf) reset(dst io.Writer) {
+ c.n = 0
+ c.err = nil
+ c.buf = [4]byte{0, 0, 0, 0}
+ c.dst = dst
+}
+
+type suffixedReader struct {
+ r io.Reader
+ pos int // position in the suffix.
+ suffix [9]byte
+
+ rx struct{ io.Reader }
+}
+
+func (r *suffixedReader) iface() io.Reader {
+ if _, ok := r.r.(io.ByteReader); ok {
+ // If source io.Reader implements io.ByteReader, return full set of
+ // methods from suffixedReader struct (Read() and ReadByte()).
+ // This actually is an optimization needed for those Decompressor
+ // implementations (such as default flate.Reader) which do check if
+ // given source is already "buffered" by checking if source implements
+ // io.ByteReader. So without this checks we will always result in
+ // double-buffering for default decompressors.
+ return r
+ }
+ // Source io.Reader doesn't support io.ByteReader, so we should cut off the
+ // ReadByte() method from suffixedReader struct. We use r.srx field to
+ // avoid allocations.
+ r.rx.Reader = r
+ return &r.rx
+}
+
+func (r *suffixedReader) Read(p []byte) (n int, err error) {
+ if r.r != nil {
+ n, err = r.r.Read(p)
+ if err == io.EOF {
+ err = nil
+ r.r = nil
+ }
+ return n, err
+ }
+ if r.pos >= len(r.suffix) {
+ return 0, io.EOF
+ }
+ n = copy(p, r.suffix[r.pos:])
+ r.pos += n
+ return n, nil
+}
+
+func (r *suffixedReader) ReadByte() (b byte, err error) {
+ if r.r != nil {
+ br, ok := r.r.(io.ByteReader)
+ if !ok {
+ panic("wsflate: internal error: incorrect use of suffixedReader")
+ }
+ b, err = br.ReadByte()
+ if err == io.EOF {
+ err = nil
+ r.r = nil
+ }
+ return b, err
+ }
+ if r.pos >= len(r.suffix) {
+ return 0, io.EOF
+ }
+ b = r.suffix[r.pos]
+ r.pos++
+ return b, nil
+}
+
+func (r *suffixedReader) reset(src io.Reader) {
+ r.r = src
+ r.pos = 0
+}
+
+func min(a, b int) int {
+ if a < b {
+ return a
+ }
+ return b
+}
diff --git a/vendor/github.com/gobwas/ws/wsflate/extension.go b/vendor/github.com/gobwas/ws/wsflate/extension.go
new file mode 100644
index 0000000..c8d9934
--- /dev/null
+++ b/vendor/github.com/gobwas/ws/wsflate/extension.go
@@ -0,0 +1,208 @@
+package wsflate
+
+import (
+ "bytes"
+
+ "github.com/gobwas/httphead"
+ "github.com/gobwas/ws"
+)
+
+// Extension contains logic of compression extension parameters negotiation
+// made during HTTP WebSocket handshake.
+// It might be reused between different upgrades (but not concurrently) with
+// Reset() being called after each.
+type Extension struct {
+ // Parameters is specification of extension parameters server is going to
+ // accept.
+ Parameters Parameters
+
+ accepted bool
+ params Parameters
+}
+
+// Negotiate parses given HTTP header option and returns (if any) header option
+// which describes accepted parameters.
+//
+// It may return zero option (i.e. one which Size() returns 0) alongside with
+// nil error.
+func (n *Extension) Negotiate(opt httphead.Option) (accept httphead.Option, err error) {
+ if !bytes.Equal(opt.Name, ExtensionNameBytes) {
+ return accept, nil
+ }
+ if n.accepted {
+ // Negotiate might be called multiple times during upgrade.
+ // We stick to first one accepted extension since they must be passed
+ // in ordered by preference.
+ return accept, nil
+ }
+
+ want := n.Parameters
+
+ // NOTE: Parse() resets params inside, so no worries.
+ if err := n.params.Parse(opt); err != nil {
+ return accept, err
+ }
+ {
+ offer := n.params.ServerMaxWindowBits
+ want := want.ServerMaxWindowBits
+ if offer > want {
+ // A server declines an extension negotiation offer
+ // with this parameter if the server doesn't support
+ // it.
+ return accept, nil
+ }
+ }
+ {
+ // If a received extension negotiation offer has the
+ // "client_max_window_bits" extension parameter, the server MAY
+ // include the "client_max_window_bits" extension parameter in the
+ // corresponding extension negotiation response to the offer.
+ offer := n.params.ClientMaxWindowBits
+ want := want.ClientMaxWindowBits
+ if want > offer {
+ return accept, nil
+ }
+ }
+ {
+ offer := n.params.ServerNoContextTakeover
+ want := want.ServerNoContextTakeover
+ if offer && !want {
+ return accept, nil
+ }
+ }
+
+ n.accepted = true
+
+ return want.Option(), nil
+}
+
+// Accepted returns parameters parsed during last negotiation and a flag that
+// reports whether they were accepted.
+func (n *Extension) Accepted() (_ Parameters, accepted bool) {
+ return n.params, n.accepted
+}
+
+// Reset resets extension for further reuse.
+func (n *Extension) Reset() {
+ n.accepted = false
+ n.params = Parameters{}
+}
+
+var ErrUnexpectedCompressionBit = ws.ProtocolError(
+ "control frame or non-first fragment of data contains compression bit set",
+)
+
+// UnsetBit clears the Per-Message Compression bit in header h and returns its
+// modified copy. It reports whether compression bit was set in header h.
+// It returns non-nil error if compression bit has unexpected value.
+//
+// This function's main purpose is to be compatible with "Framing" section of
+// the Compression Extensions for WebSocket RFC. If you don't need to work with
+// chains of extensions then IsCompressed() could be enough to check if
+// message is compressed.
+// See https://tools.ietf.org/html/rfc7692#section-6.2
+func UnsetBit(h ws.Header) (_ ws.Header, wasSet bool, err error) {
+ var s MessageState
+ h, err = s.UnsetBits(h)
+ return h, s.IsCompressed(), err
+}
+
+// SetBit sets the Per-Message Compression bit in header h and returns its
+// modified copy.
+// It returns non-nil error if compression bit has unexpected value.
+func SetBit(h ws.Header) (_ ws.Header, err error) {
+ var s MessageState
+ s.SetCompressed(true)
+ return s.SetBits(h)
+}
+
+// IsCompressed reports whether the Per-Message Compression bit is set in
+// header h.
+// It returns non-nil error if compression bit has unexpected value.
+//
+// If you need to be fully compatible with Compression Extensions for WebSocket
+// RFC and work with chains of extensions, take a look at the UnsetBit()
+// instead. That is, IsCompressed() is a shortcut for UnsetBit() with reduced
+// number of return values.
+func IsCompressed(h ws.Header) (bool, error) {
+ _, isSet, err := UnsetBit(h)
+ return isSet, err
+}
+
+// MessageState holds message compression state.
+//
+// It is consulted during SetBits(h) call to make a decision whether we must
+// set the Per-Message Compression bit for given header h argument.
+// It is updated during UnsetBits(h) to reflect compression state of a message
+// represented by header h argument.
+// It can also be consulted/updated directly by calling
+// IsCompressed()/SetCompressed().
+//
+// In general MessageState should be used when there is no direct access to
+// connection to read frame from, but it is still needed to know if message
+// being read is compressed. For other cases SetBit() and UnsetBit() should be
+// used instead.
+//
+// NOTE: the compression state is updated during UnsetBits(h) only when header
+// h argument represents data (text or binary) frame.
+type MessageState struct {
+ compressed bool
+}
+
+// SetCompressed marks message as "compressed" or "uncompressed".
+// See https://tools.ietf.org/html/rfc7692#section-6
+func (s *MessageState) SetCompressed(v bool) {
+ s.compressed = v
+}
+
+// IsCompressed reports whether message is "compressed".
+// See https://tools.ietf.org/html/rfc7692#section-6
+func (s *MessageState) IsCompressed() bool {
+ return s.compressed
+}
+
+// UnsetBits changes RSV bits of the given frame header h as if compression
+// extension was negotiated. It returns modified copy of h and error if header
+// is malformed from the RFC perspective.
+func (s *MessageState) UnsetBits(h ws.Header) (ws.Header, error) {
+ r1, r2, r3 := ws.RsvBits(h.Rsv)
+ switch {
+ case h.OpCode.IsData() && h.OpCode != ws.OpContinuation:
+ h.Rsv = ws.Rsv(false, r2, r3)
+ s.SetCompressed(r1)
+ return h, nil
+
+ case r1:
+ // An endpoint MUST NOT set the "Per-Message Compressed"
+ // bit of control frames and non-first fragments of a data
+ // message. An endpoint receiving such a frame MUST _Fail
+ // the WebSocket Connection_.
+ return h, ErrUnexpectedCompressionBit
+
+ default:
+ // NOTE: do not change the state of s.compressed since UnsetBits()
+ // might also be called for (intermediate) control frames.
+ return h, nil
+ }
+}
+
+// SetBits changes RSV bits of the frame header h which is being send as if
+// compression extension was negotiated. It returns modified copy of h and
+// error if header is malformed from the RFC perspective.
+func (s *MessageState) SetBits(h ws.Header) (ws.Header, error) {
+ r1, r2, r3 := ws.RsvBits(h.Rsv)
+ if r1 {
+ return h, ErrUnexpectedCompressionBit
+ }
+ if !h.OpCode.IsData() || h.OpCode == ws.OpContinuation {
+ // An endpoint MUST NOT set the "Per-Message Compressed"
+ // bit of control frames and non-first fragments of a data
+ // message. An endpoint receiving such a frame MUST _Fail
+ // the WebSocket Connection_.
+ return h, nil
+ }
+ if s.IsCompressed() {
+ h.Rsv = ws.Rsv(true, r2, r3)
+ }
+ return h, nil
+}
diff --git a/vendor/github.com/gobwas/ws/wsflate/helper.go b/vendor/github.com/gobwas/ws/wsflate/helper.go
new file mode 100644
index 0000000..eae94d7
--- /dev/null
+++ b/vendor/github.com/gobwas/ws/wsflate/helper.go
@@ -0,0 +1,195 @@
+package wsflate
+
+import (
+ "bytes"
+ "compress/flate"
+ "fmt"
+ "io"
+
+ "github.com/gobwas/ws"
+)
+
+// DefaultHelper is a default helper instance holding standard library's
+// `compress/flate` compressor and decompressor under the hood.
+//
+// Note that use of DefaultHelper methods assumes that DefaultParameters were
+// used for extension negotiation during WebSocket handshake.
+var DefaultHelper = Helper{
+ Compressor: func(w io.Writer) Compressor {
+ // No error can be returned here as NewWriter() doc says.
+ f, _ := flate.NewWriter(w, 9)
+ return f
+ },
+ Decompressor: func(r io.Reader) Decompressor {
+ return flate.NewReader(r)
+ },
+}
+
+// DefaultParameters holds deflate extension parameters which are assumed by
+// DefaultHelper to be used during WebSocket handshake.
+var DefaultParameters = Parameters{
+ ServerNoContextTakeover: true,
+ ClientNoContextTakeover: true,
+}
+
+// CompressFrame is a shortcut for DefaultHelper.CompressFrame().
+//
+// Note that use of DefaultHelper methods assumes that DefaultParameters were
+// used for extension negotiation during WebSocket handshake.
+func CompressFrame(f ws.Frame) (ws.Frame, error) {
+ return DefaultHelper.CompressFrame(f)
+}
+
+// CompressFrameBuffer is a shortcut for DefaultHelper.CompressFrameBuffer().
+//
+// Note that use of DefaultHelper methods assumes that DefaultParameters were
+// used for extension negotiation during WebSocket handshake.
+func CompressFrameBuffer(buf Buffer, f ws.Frame) (ws.Frame, error) {
+ return DefaultHelper.CompressFrameBuffer(buf, f)
+}
+
+// DecompressFrame is a shortcut for DefaultHelper.DecompressFrame().
+//
+// Note that use of DefaultHelper methods assumes that DefaultParameters were
+// used for extension negotiation during WebSocket handshake.
+func DecompressFrame(f ws.Frame) (ws.Frame, error) {
+ return DefaultHelper.DecompressFrame(f)
+}
+
+// DecompressFrameBuffer is a shortcut for
+// DefaultHelper.DecompressFrameBuffer().
+//
+// Note that use of DefaultHelper methods assumes that DefaultParameters were
+// used for extension negotiation during WebSocket handshake.
+func DecompressFrameBuffer(buf Buffer, f ws.Frame) (ws.Frame, error) {
+ return DefaultHelper.DecompressFrameBuffer(buf, f)
+}
+
+// Helper is a helper struct that holds common code for compression and
+// decompression bytes or WebSocket frames.
+//
+// Its purpose is to reduce boilerplate code in WebSocket applications.
+type Helper struct {
+ Compressor func(w io.Writer) Compressor
+ Decompressor func(r io.Reader) Decompressor
+}
+
+// Buffer is an interface representing some bytes buffering object.
+type Buffer interface {
+ io.Writer
+ Bytes() []byte
+}
+
+// CompressFrame returns compressed version of a frame.
+// Note that it does memory allocations internally. To control those
+// allocations consider using CompressFrameBuffer().
+func (h *Helper) CompressFrame(in ws.Frame) (f ws.Frame, err error) {
+ var buf bytes.Buffer
+ return h.CompressFrameBuffer(&buf, in)
+}
+
+// DecompressFrame returns decompressed version of a frame.
+// Note that it does memory allocations internally. To control those
+// allocations consider using DecompressFrameBuffer().
+func (h *Helper) DecompressFrame(in ws.Frame) (f ws.Frame, err error) {
+ var buf bytes.Buffer
+ return h.DecompressFrameBuffer(&buf, in)
+}
+
+// CompressFrameBuffer compresses a frame using given buffer.
+// Returned frame's payload holds bytes returned by buf.Bytes().
+func (h *Helper) CompressFrameBuffer(buf Buffer, f ws.Frame) (ws.Frame, error) {
+ if !f.Header.Fin {
+ return f, fmt.Errorf("wsflate: fragmented messages are not allowed")
+ }
+ if err := h.CompressTo(buf, f.Payload); err != nil {
+ return f, err
+ }
+ var err error
+ f.Payload = buf.Bytes()
+ f.Header.Length = int64(len(f.Payload))
+ f.Header, err = SetBit(f.Header)
+ if err != nil {
+ return f, err
+ }
+ return f, nil
+}
+
+// DecompressFrameBuffer decompresses a frame using given buffer.
+// Returned frame's payload holds bytes returned by buf.Bytes().
+func (h *Helper) DecompressFrameBuffer(buf Buffer, f ws.Frame) (ws.Frame, error) {
+ if !f.Header.Fin {
+ return f, fmt.Errorf(
+ "wsflate: fragmented messages are not supported by helper",
+ )
+ }
+ var (
+ compressed bool
+ err error
+ )
+ f.Header, compressed, err = UnsetBit(f.Header)
+ if err != nil {
+ return f, err
+ }
+ if !compressed {
+ return f, nil
+ }
+ if err := h.DecompressTo(buf, f.Payload); err != nil {
+ return f, err
+ }
+
+ f.Payload = buf.Bytes()
+ f.Header.Length = int64(len(f.Payload))
+
+ return f, nil
+}
+
+// Compress compresses given bytes.
+// Note that it does memory allocations internally. To control those
+// allocations consider using CompressTo().
+func (h *Helper) Compress(p []byte) ([]byte, error) {
+ var buf bytes.Buffer
+ if err := h.CompressTo(&buf, p); err != nil {
+ return nil, err
+ }
+ return buf.Bytes(), nil
+}
+
+// Decompress decompresses given bytes.
+// Note that it does memory allocations internally. To control those
+// allocations consider using DecompressTo().
+func (h *Helper) Decompress(p []byte) ([]byte, error) {
+ var buf bytes.Buffer
+ if err := h.DecompressTo(&buf, p); err != nil {
+ return nil, err
+ }
+ return buf.Bytes(), nil
+}
+
+// CompressTo compresses bytes into given buffer.
+func (h *Helper) CompressTo(w io.Writer, p []byte) (err error) {
+ c := NewWriter(w, h.Compressor)
+ if _, err = c.Write(p); err != nil {
+ return err
+ }
+ if err := c.Flush(); err != nil {
+ return err
+ }
+ if err := c.Close(); err != nil {
+ return err
+ }
+ return nil
+}
+
+// DecompressTo decompresses bytes into given buffer.
+// Returned bytes are bytes returned by buf.Bytes().
+func (h *Helper) DecompressTo(w io.Writer, p []byte) (err error) {
+ fr := NewReader(bytes.NewReader(p), h.Decompressor)
+ if _, err = io.Copy(w, fr); err != nil {
+ return err
+ }
+ if err := fr.Close(); err != nil {
+ return err
+ }
+ return nil
+}
diff --git a/vendor/github.com/gobwas/ws/wsflate/parameters.go b/vendor/github.com/gobwas/ws/wsflate/parameters.go
new file mode 100644
index 0000000..3f2691c
--- /dev/null
+++ b/vendor/github.com/gobwas/ws/wsflate/parameters.go
@@ -0,0 +1,197 @@
+package wsflate
+
+import (
+ "fmt"
+ "strconv"
+
+ "github.com/gobwas/httphead"
+)
+
+const (
+ ExtensionName = "permessage-deflate"
+
+ serverNoContextTakeover = "server_no_context_takeover"
+ clientNoContextTakeover = "client_no_context_takeover"
+ serverMaxWindowBits = "server_max_window_bits"
+ clientMaxWindowBits = "client_max_window_bits"
+)
+
+var (
+ ExtensionNameBytes = []byte(ExtensionName)
+
+ serverNoContextTakeoverBytes = []byte(serverNoContextTakeover)
+ clientNoContextTakeoverBytes = []byte(clientNoContextTakeover)
+ serverMaxWindowBitsBytes = []byte(serverMaxWindowBits)
+ clientMaxWindowBitsBytes = []byte(clientMaxWindowBits)
+)
+
+var windowBits [8][]byte
+
+func init() {
+ for i := range windowBits {
+ windowBits[i] = []byte(strconv.Itoa(i + 8))
+ }
+}
+
+// Parameters contains compression extension options.
+type Parameters struct {
+ ServerNoContextTakeover bool
+ ClientNoContextTakeover bool
+ ServerMaxWindowBits WindowBits
+ ClientMaxWindowBits WindowBits
+}
+
+// WindowBits specifies window size accordingly to RFC.
+// Use its Bytes() method to obtain actual size of window in bytes.
+type WindowBits byte
+
+// Defined reports whether window bits were specified.
+func (b WindowBits) Defined() bool {
+ return b > 0
+}
+
+// Bytes returns window size in number of bytes.
+func (b WindowBits) Bytes() int {
+ return 1 << uint(b)
+}
+
+const (
+ MaxLZ77WindowSize = 32768 // 2^15
+)
+
+// Parse reads parameters from given HTTP header option accordingly to RFC.
+//
+// It returns non-nil error at least in these cases:
+// - The negotiation offer contains an extension parameter not defined for
+// use in an offer/response.
+// - The negotiation offer/response contains an extension parameter with an
+// invalid value.
+// - The negotiation offer/response contains multiple extension parameters
+// with the same name.
+func (p *Parameters) Parse(opt httphead.Option) (err error) {
+ const (
+ clientMaxWindowBitsSeen = 1 << iota
+ serverMaxWindowBitsSeen
+ clientNoContextTakeoverSeen
+ serverNoContextTakeoverSeen
+ )
+
+ // Reset to not mix parsed data from previous Parse() calls.
+ *p = Parameters{}
+
+ var seen byte
+ opt.Parameters.ForEach(func(key, val []byte) (ok bool) {
+ switch string(key) {
+ case clientMaxWindowBits:
+ if len(val) == 0 {
+ p.ClientMaxWindowBits = 1
+ return true
+ }
+ if seen&clientMaxWindowBitsSeen != 0 {
+ err = paramError("duplicate", key, val)
+ return false
+ }
+ seen |= clientMaxWindowBitsSeen
+ if p.ClientMaxWindowBits, ok = bitsFromASCII(val); !ok {
+ err = paramError("invalid", key, val)
+ return false
+ }
+
+ case serverMaxWindowBits:
+ if len(val) == 0 {
+ err = paramError("invalid", key, val)
+ return false
+ }
+ if seen&serverMaxWindowBitsSeen != 0 {
+ err = paramError("duplicate", key, val)
+ return false
+ }
+ seen |= serverMaxWindowBitsSeen
+ if p.ServerMaxWindowBits, ok = bitsFromASCII(val); !ok {
+ err = paramError("invalid", key, val)
+ return false
+ }
+
+ case clientNoContextTakeover:
+ if len(val) > 0 {
+ err = paramError("invalid", key, val)
+ return false
+ }
+ if seen&clientNoContextTakeoverSeen != 0 {
+ err = paramError("duplicate", key, val)
+ return false
+ }
+ seen |= clientNoContextTakeoverSeen
+ p.ClientNoContextTakeover = true
+
+ case serverNoContextTakeover:
+ if len(val) > 0 {
+ err = paramError("invalid", key, val)
+ return false
+ }
+ if seen&serverNoContextTakeoverSeen != 0 {
+ err = paramError("duplicate", key, val)
+ return false
+ }
+ seen |= serverNoContextTakeoverSeen
+ p.ServerNoContextTakeover = true
+
+ default:
+ err = paramError("unexpected", key, val)
+ return false
+ }
+ return true
+ })
+ return err
+}
+
+// Option encodes parameters into HTTP header option.
+func (p Parameters) Option() httphead.Option {
+ opt := httphead.Option{
+ Name: ExtensionNameBytes,
+ }
+ setBool(&opt, serverNoContextTakeoverBytes, p.ServerNoContextTakeover)
+ setBool(&opt, clientNoContextTakeoverBytes, p.ClientNoContextTakeover)
+ setBits(&opt, serverMaxWindowBitsBytes, p.ServerMaxWindowBits)
+ setBits(&opt, clientMaxWindowBitsBytes, p.ClientMaxWindowBits)
+ return opt
+}
+
+func isValidBits(x int) bool {
+ return 8 <= x && x <= 15
+}
+
+func bitsFromASCII(p []byte) (WindowBits, bool) {
+ n, ok := httphead.IntFromASCII(p)
+ if !ok || !isValidBits(n) {
+ return 0, false
+ }
+ return WindowBits(n), true
+}
+
+func setBits(opt *httphead.Option, name []byte, bits WindowBits) {
+ if bits == 0 {
+ return
+ }
+ if bits == 1 {
+ opt.Parameters.Set(name, nil)
+ return
+ }
+ if !isValidBits(int(bits)) {
+ panic(fmt.Sprintf("wsflate: invalid bits value: %d", bits))
+ }
+ opt.Parameters.Set(name, windowBits[bits-8])
+}
+
+func setBool(opt *httphead.Option, name []byte, flag bool) {
+ if flag {
+ opt.Parameters.Set(name, nil)
+ }
+}
+
+func paramError(reason string, key, val []byte) error {
+ return fmt.Errorf(
+ "wsflate: %s extension parameter %q: %q",
+ reason, key, val,
+ )
+}
diff --git a/vendor/github.com/gobwas/ws/wsflate/reader.go b/vendor/github.com/gobwas/ws/wsflate/reader.go
new file mode 100644
index 0000000..8f0f660
--- /dev/null
+++ b/vendor/github.com/gobwas/ws/wsflate/reader.go
@@ -0,0 +1,84 @@
+package wsflate
+
+import (
+ "io"
+)
+
+// Decompressor is an interface holding deflate decompression implementation.
+type Decompressor interface {
+ io.Reader
+}
+
+// ReadResetter is an optional interface that Decompressor can implement.
+type ReadResetter interface {
+ Reset(io.Reader)
+}
+
+// Reader implements decompression from an io.Reader object using Decompressor.
+// Essentially Reader is a thin wrapper around Decompressor interface to meet
+// PMCE specs.
+//
+// After all data has been written client should call Flush() method.
+// If any error occurs after reading from Reader, all subsequent calls to
+// Read() or Close() will return the error.
+//
+// Reader might be reused for different io.Reader objects after its Reset()
+// method has been called.
+type Reader struct {
+ src io.Reader
+ ctor func(io.Reader) Decompressor
+ d Decompressor
+ sr suffixedReader
+ err error
+}
+
+// NewReader returns a new Reader.
+func NewReader(r io.Reader, ctor func(io.Reader) Decompressor) *Reader {
+ ret := &Reader{
+ src: r,
+ ctor: ctor,
+ sr: suffixedReader{
+ suffix: compressionReadTail,
+ },
+ }
+ ret.Reset(r)
+ return ret
+}
+
+// Reset resets Reader to decompress data from src.
+func (r *Reader) Reset(src io.Reader) {
+ r.err = nil
+ r.src = src
+ r.sr.reset(src)
+
+ if x, ok := r.d.(ReadResetter); ok {
+ x.Reset(r.sr.iface())
+ } else {
+ r.d = r.ctor(r.sr.iface())
+ }
+}
+
+// Read implements io.Reader.
+func (r *Reader) Read(p []byte) (n int, err error) {
+ if r.err != nil {
+ return 0, r.err
+ }
+ return r.d.Read(p)
+}
+
+// Close closes Reader and a Decompressor instance used under the hood (if it
+// implements io.Closer interface).
+func (r *Reader) Close() error {
+ if r.err != nil {
+ return r.err
+ }
+ if c, ok := r.d.(io.Closer); ok {
+ r.err = c.Close()
+ }
+ return r.err
+}
+
+// Err returns an error happened during any operation.
+func (r *Reader) Err() error {
+ return r.err
+}
diff --git a/vendor/github.com/gobwas/ws/wsflate/writer.go b/vendor/github.com/gobwas/ws/wsflate/writer.go
new file mode 100644
index 0000000..0342ccb
--- /dev/null
+++ b/vendor/github.com/gobwas/ws/wsflate/writer.go
@@ -0,0 +1,129 @@
+package wsflate
+
+import (
+ "fmt"
+ "io"
+)
+
+var (
+ compressionTail = [4]byte{
+ 0, 0, 0xff, 0xff,
+ }
+ compressionReadTail = [9]byte{
+ 0, 0, 0xff, 0xff,
+ 1,
+ 0, 0, 0xff, 0xff,
+ }
+)
+
+// Compressor is an interface holding deflate compression implementation.
+type Compressor interface {
+ io.Writer
+ Flush() error
+}
+
+// WriteResetter is an optional interface that Compressor can implement.
+type WriteResetter interface {
+ Reset(io.Writer)
+}
+
+// Writer implements compression for an io.Writer object using Compressor.
+// Essentially Writer is a thin wrapper around Compressor interface to meet
+// PMCE specs.
+//
+// After all data has been written client should call Flush() method.
+// If any error occurs after writing to or flushing a Writer, all subsequent
+// calls to Write(), Flush() or Close() will return the error.
+//
+// Writer might be reused for different io.Writer objects after its Reset()
+// method has been called.
+type Writer struct {
+ // NOTE: Writer uses compressor constructor function instead of field to
+ // reach these goals:
+ // 1. To shrink Compressor interface and make it easier to be implemented.
+ // 2. If used as a field (and argument to the NewWriter()), Compressor object
+ // will probably be initialized twice - first time to pass into Writer, and
+ // second time during Writer initialization (which does Reset() internally).
+ // 3. To get rid of wrappers if Reset() would be a part of Compressor.
+ // E.g. non conformant implementations would have to provide it somehow,
+ // probably making a wrapper with the same constructor function.
+ // 4. To make Reader and Writer API the same. That is, there is no Reset()
+ // method for flate.Reader already, so we need to provide it as a wrapper
+ // (see point #3), or drop the Reader.Reset() method.
+ dest io.Writer
+ ctor func(io.Writer) Compressor
+ c Compressor
+ cbuf cbuf
+ err error
+}
+
+// NewWriter returns a new Writer.
+func NewWriter(w io.Writer, ctor func(io.Writer) Compressor) *Writer {
+ // NOTE: NewWriter() is chosen against structure with exported fields here
+ // due its Reset() method, which in case of structure, would change
+ // exported field.
+ ret := &Writer{
+ dest: w,
+ ctor: ctor,
+ }
+ ret.Reset(w)
+ return ret
+}
+
+// Reset resets Writer to compress data into dest.
+// Any not flushed data will be lost.
+func (w *Writer) Reset(dest io.Writer) {
+ w.err = nil
+ w.cbuf.reset(dest)
+ if x, ok := w.c.(WriteResetter); ok {
+ x.Reset(&w.cbuf)
+ } else {
+ w.c = w.ctor(&w.cbuf)
+ }
+}
+
+// Write implements io.Writer.
+func (w *Writer) Write(p []byte) (n int, err error) {
+ if w.err != nil {
+ return 0, w.err
+ }
+ n, w.err = w.c.Write(p)
+ return n, w.err
+}
+
+// Flush writes any pending data into w.Dest.
+func (w *Writer) Flush() error {
+ if w.err != nil {
+ return w.err
+ }
+ w.err = w.c.Flush()
+ w.checkTail()
+ return w.err
+}
+
+// Close closes Writer and a Compressor instance used under the hood (if it
+// implements io.Closer interface).
+func (w *Writer) Close() error {
+ if w.err != nil {
+ return w.err
+ }
+ if c, ok := w.c.(io.Closer); ok {
+ w.err = c.Close()
+ }
+ w.checkTail()
+ return w.err
+}
+
+// Err returns an error happened during any operation.
+func (w *Writer) Err() error {
+ return w.err
+}
+
+func (w *Writer) checkTail() {
+ if w.err == nil && w.cbuf.buf != compressionTail {
+ w.err = fmt.Errorf(
+ "wsflate: bad compressor: unexpected stream tail: %#x vs %#x",
+ w.cbuf.buf, compressionTail,
+ )
+ }
+}
diff --git a/vendor/github.com/gobwas/ws/wsutil/cipher.go b/vendor/github.com/gobwas/ws/wsutil/cipher.go
new file mode 100644
index 0000000..bc25064
--- /dev/null
+++ b/vendor/github.com/gobwas/ws/wsutil/cipher.go
@@ -0,0 +1,72 @@
+package wsutil
+
+import (
+ "io"
+
+ "github.com/gobwas/pool/pbytes"
+ "github.com/gobwas/ws"
+)
+
+// CipherReader implements io.Reader that applies xor-cipher to the bytes read
+// from source.
+// It could help to unmask WebSocket frame payload on the fly.
+type CipherReader struct {
+ r io.Reader
+ mask [4]byte
+ pos int
+}
+
+// NewCipherReader creates xor-cipher reader from r with given mask.
+func NewCipherReader(r io.Reader, mask [4]byte) *CipherReader {
+ return &CipherReader{r, mask, 0}
+}
+
+// Reset resets CipherReader to read from r with given mask.
+func (c *CipherReader) Reset(r io.Reader, mask [4]byte) {
+ c.r = r
+ c.mask = mask
+ c.pos = 0
+}
+
+// Read implements io.Reader interface. It applies mask given during
+// initialization to every read byte.
+func (c *CipherReader) Read(p []byte) (n int, err error) {
+ n, err = c.r.Read(p)
+ ws.Cipher(p[:n], c.mask, c.pos)
+ c.pos += n
+ return n, err
+}
+
+// CipherWriter implements io.Writer that applies xor-cipher to the bytes
+// written to the destination writer. It does not modify the original bytes.
+type CipherWriter struct {
+ w io.Writer
+ mask [4]byte
+ pos int
+}
+
+// NewCipherWriter creates xor-cipher writer to w with given mask.
+func NewCipherWriter(w io.Writer, mask [4]byte) *CipherWriter {
+ return &CipherWriter{w, mask, 0}
+}
+
+// Reset reset CipherWriter to write to w with given mask.
+func (c *CipherWriter) Reset(w io.Writer, mask [4]byte) {
+ c.w = w
+ c.mask = mask
+ c.pos = 0
+}
+
+// Write implements io.Writer interface. It applies masking during
+// initialization to every sent byte. It does not modify original slice.
+func (c *CipherWriter) Write(p []byte) (n int, err error) {
+ cp := pbytes.GetLen(len(p))
+ defer pbytes.Put(cp)
+
+ copy(cp, p)
+ ws.Cipher(cp, c.mask, c.pos)
+ n, err = c.w.Write(cp)
+ c.pos += n
+
+ return n, err
+}
diff --git a/vendor/github.com/gobwas/ws/wsutil/dialer.go b/vendor/github.com/gobwas/ws/wsutil/dialer.go
new file mode 100644
index 0000000..4f8788f
--- /dev/null
+++ b/vendor/github.com/gobwas/ws/wsutil/dialer.go
@@ -0,0 +1,147 @@
+package wsutil
+
+import (
+ "bufio"
+ "bytes"
+ "context"
+ "io"
+ "io/ioutil"
+ "net"
+ "net/http"
+
+ "github.com/gobwas/ws"
+)
+
+// DebugDialer is a wrapper around ws.Dialer. It tracks i/o of WebSocket
+// handshake. That is, it gives ability to receive copied HTTP request and
+// response bytes that made inside Dialer.Dial().
+//
+// Note that it must not be used in production applications that requires
+// Dial() to be efficient.
+type DebugDialer struct {
+ // Dialer contains WebSocket connection establishment options.
+ Dialer ws.Dialer
+
+ // OnRequest and OnResponse are the callbacks that will be called with the
+ // HTTP request and response respectively.
+ OnRequest, OnResponse func([]byte)
+}
+
+// Dial connects to the url host and upgrades connection to WebSocket. It makes
+// it by calling d.Dialer.Dial().
+func (d *DebugDialer) Dial(ctx context.Context, urlstr string) (conn net.Conn, br *bufio.Reader, hs ws.Handshake, err error) {
+ // Need to copy Dialer to prevent original object mutation.
+ dialer := d.Dialer
+ var (
+ reqBuf bytes.Buffer
+ resBuf bytes.Buffer
+
+ resContentLength int64
+ )
+ userWrap := dialer.WrapConn
+ dialer.WrapConn = func(c net.Conn) net.Conn {
+ if userWrap != nil {
+ c = userWrap(c)
+ }
+
+ // Save the pointer to the raw connection.
+ conn = c
+
+ var (
+ r io.Reader = conn
+ w io.Writer = conn
+ )
+ if d.OnResponse != nil {
+ r = &prefetchResponseReader{
+ source: conn,
+ buffer: &resBuf,
+ contentLength: &resContentLength,
+ }
+ }
+ if d.OnRequest != nil {
+ w = io.MultiWriter(conn, &reqBuf)
+ }
+ return rwConn{conn, r, w}
+ }
+
+ _, br, hs, err = dialer.Dial(ctx, urlstr)
+
+ if onRequest := d.OnRequest; onRequest != nil {
+ onRequest(reqBuf.Bytes())
+ }
+ if onResponse := d.OnResponse; onResponse != nil {
+ // We must split response inside buffered bytes from other received
+ // bytes from server.
+ p := resBuf.Bytes()
+ n := bytes.Index(p, headEnd)
+ h := n + len(headEnd) // Head end index.
+ n = h + int(resContentLength) // Body end index.
+
+ onResponse(p[:n])
+
+ if br != nil {
+ // If br is non-nil, then it mean two things. First is that
+ // handshake is OK and server has sent additional bytes – probably
+ // immediate sent frames (or weird but possible response body).
+ // Second, the bad one, is that br buffer's source is now rwConn
+ // instance from above WrapConn call. It is incorrect, so we must
+ // fix it.
+ var r io.Reader = conn
+ if len(p) > h {
+ // Buffer contains more than just HTTP headers bytes.
+ r = io.MultiReader(
+ bytes.NewReader(p[h:]),
+ conn,
+ )
+ }
+ br.Reset(r)
+ // Must make br.Buffered() to be non-zero.
+ br.Peek(len(p[h:]))
+ }
+ }
+
+ return conn, br, hs, err
+}
+
+type rwConn struct {
+ net.Conn
+
+ r io.Reader
+ w io.Writer
+}
+
+func (rwc rwConn) Read(p []byte) (int, error) {
+ return rwc.r.Read(p)
+}
+
+func (rwc rwConn) Write(p []byte) (int, error) {
+ return rwc.w.Write(p)
+}
+
+var headEnd = []byte("\r\n\r\n")
+
+type prefetchResponseReader struct {
+ source io.Reader // Original connection source.
+ reader io.Reader // Wrapped reader used to read from by clients.
+ buffer *bytes.Buffer
+
+ contentLength *int64
+}
+
+func (r *prefetchResponseReader) Read(p []byte) (int, error) {
+ if r.reader == nil {
+ resp, err := http.ReadResponse(bufio.NewReader(
+ io.TeeReader(r.source, r.buffer),
+ ), nil)
+ if err == nil {
+ *r.contentLength, _ = io.Copy(ioutil.Discard, resp.Body)
+ resp.Body.Close()
+ }
+ bts := r.buffer.Bytes()
+ r.reader = io.MultiReader(
+ bytes.NewReader(bts),
+ r.source,
+ )
+ }
+ return r.reader.Read(p)
+}
diff --git a/vendor/github.com/gobwas/ws/wsutil/extenstion.go b/vendor/github.com/gobwas/ws/wsutil/extenstion.go
new file mode 100644
index 0000000..6e1ebbf
--- /dev/null
+++ b/vendor/github.com/gobwas/ws/wsutil/extenstion.go
@@ -0,0 +1,31 @@
+package wsutil
+
+import "github.com/gobwas/ws"
+
+// RecvExtension is an interface for clearing fragment header RSV bits.
+type RecvExtension interface {
+ UnsetBits(ws.Header) (ws.Header, error)
+}
+
+// RecvExtensionFunc is an adapter to allow the use of ordinary functions as
+// RecvExtension.
+type RecvExtensionFunc func(ws.Header) (ws.Header, error)
+
+// BitsRecv implements RecvExtension.
+func (fn RecvExtensionFunc) UnsetBits(h ws.Header) (ws.Header, error) {
+ return fn(h)
+}
+
+// SendExtension is an interface for setting fragment header RSV bits.
+type SendExtension interface {
+ SetBits(ws.Header) (ws.Header, error)
+}
+
+// SendExtensionFunc is an adapter to allow the use of ordinary functions as
+// SendExtension.
+type SendExtensionFunc func(ws.Header) (ws.Header, error)
+
+// BitsSend implements SendExtension.
+func (fn SendExtensionFunc) SetBits(h ws.Header) (ws.Header, error) {
+ return fn(h)
+}
diff --git a/vendor/github.com/gobwas/ws/wsutil/handler.go b/vendor/github.com/gobwas/ws/wsutil/handler.go
new file mode 100644
index 0000000..44fd360
--- /dev/null
+++ b/vendor/github.com/gobwas/ws/wsutil/handler.go
@@ -0,0 +1,219 @@
+package wsutil
+
+import (
+ "errors"
+ "io"
+ "io/ioutil"
+ "strconv"
+
+ "github.com/gobwas/pool/pbytes"
+ "github.com/gobwas/ws"
+)
+
+// ClosedError returned when peer has closed the connection with appropriate
+// code and a textual reason.
+type ClosedError struct {
+ Code ws.StatusCode
+ Reason string
+}
+
+// Error implements error interface.
+func (err ClosedError) Error() string {
+ return "ws closed: " + strconv.FormatUint(uint64(err.Code), 10) + " " + err.Reason
+}
+
+// ControlHandler contains logic of handling control frames.
+//
+// The intentional way to use it is to read the next frame header from the
+// connection, optionally check its validity via ws.CheckHeader() and if it is
+// not a ws.OpText of ws.OpBinary (or ws.OpContinuation) – pass it to Handle()
+// method.
+//
+// That is, passed header should be checked to get rid of unexpected errors.
+//
+// The Handle() method will read out all control frame payload (if any) and
+// write necessary bytes as a rfc compatible response.
+type ControlHandler struct {
+ Src io.Reader
+ Dst io.Writer
+ State ws.State
+
+ // DisableSrcCiphering disables unmasking payload data read from Src.
+ // It is useful when wsutil.Reader is used or when frame payload already
+ // pulled and ciphered out from the connection (and introduced by
+ // bytes.Reader, for example).
+ DisableSrcCiphering bool
+}
+
+// ErrNotControlFrame is returned by ControlHandler to indicate that given
+// header could not be handled.
+var ErrNotControlFrame = errors.New("not a control frame")
+
+// Handle handles control frames regarding to the c.State and writes responses
+// to the c.Dst when needed.
+//
+// It returns ErrNotControlFrame when given header is not of ws.OpClose,
+// ws.OpPing or ws.OpPong operation code.
+func (c ControlHandler) Handle(h ws.Header) error {
+ switch h.OpCode {
+ case ws.OpPing:
+ return c.HandlePing(h)
+ case ws.OpPong:
+ return c.HandlePong(h)
+ case ws.OpClose:
+ return c.HandleClose(h)
+ }
+ return ErrNotControlFrame
+}
+
+// HandlePing handles ping frame and writes specification compatible response
+// to the c.Dst.
+func (c ControlHandler) HandlePing(h ws.Header) error {
+ if h.Length == 0 {
+ // The most common case when ping is empty.
+ // Note that when sending masked frame the mask for empty payload is
+ // just four zero bytes.
+ return ws.WriteHeader(c.Dst, ws.Header{
+ Fin: true,
+ OpCode: ws.OpPong,
+ Masked: c.State.ClientSide(),
+ })
+ }
+
+ // In other way reply with Pong frame with copied payload.
+ p := pbytes.GetLen(int(h.Length) + ws.HeaderSize(ws.Header{
+ Length: h.Length,
+ Masked: c.State.ClientSide(),
+ }))
+ defer pbytes.Put(p)
+
+ // Deal with ciphering i/o:
+ // Masking key is used to mask the "Payload data" defined in the same
+ // section as frame-payload-data, which includes "Extension data" and
+ // "Application data".
+ //
+ // See https://tools.ietf.org/html/rfc6455#section-5.3
+ //
+ // NOTE: We prefer ControlWriter with preallocated buffer to
+ // ws.WriteHeader because it performs one syscall instead of two.
+ w := NewControlWriterBuffer(c.Dst, c.State, ws.OpPong, p)
+ r := c.Src
+ if c.State.ServerSide() && !c.DisableSrcCiphering {
+ r = NewCipherReader(r, h.Mask)
+ }
+
+ _, err := io.Copy(w, r)
+ if err == nil {
+ err = w.Flush()
+ }
+
+ return err
+}
+
+// HandlePong handles pong frame by discarding it.
+func (c ControlHandler) HandlePong(h ws.Header) error {
+ if h.Length == 0 {
+ return nil
+ }
+
+ buf := pbytes.GetLen(int(h.Length))
+ defer pbytes.Put(buf)
+
+ // Discard pong message according to the RFC6455:
+ // A Pong frame MAY be sent unsolicited. This serves as a
+ // unidirectional heartbeat. A response to an unsolicited Pong frame
+ // is not expected.
+ _, err := io.CopyBuffer(ioutil.Discard, c.Src, buf)
+
+ return err
+}
+
+// HandleClose handles close frame, makes protocol validity checks and writes
+// specification compatible response to the c.Dst.
+func (c ControlHandler) HandleClose(h ws.Header) error {
+ if h.Length == 0 {
+ err := ws.WriteHeader(c.Dst, ws.Header{
+ Fin: true,
+ OpCode: ws.OpClose,
+ Masked: c.State.ClientSide(),
+ })
+ if err != nil {
+ return err
+ }
+
+ // Due to RFC, we should interpret the code as no status code
+ // received:
+ // If this Close control frame contains no status code, _The WebSocket
+ // Connection Close Code_ is considered to be 1005.
+ //
+ // See https://tools.ietf.org/html/rfc6455#section-7.1.5
+ return ClosedError{
+ Code: ws.StatusNoStatusRcvd,
+ }
+ }
+
+ // Prepare bytes both for reading reason and sending response.
+ p := pbytes.GetLen(int(h.Length) + ws.HeaderSize(ws.Header{
+ Length: h.Length,
+ Masked: c.State.ClientSide(),
+ }))
+ defer pbytes.Put(p)
+
+ // Get the subslice to read the frame payload out.
+ subp := p[:h.Length]
+
+ r := c.Src
+ if c.State.ServerSide() && !c.DisableSrcCiphering {
+ r = NewCipherReader(r, h.Mask)
+ }
+ if _, err := io.ReadFull(r, subp); err != nil {
+ return err
+ }
+
+ code, reason := ws.ParseCloseFrameData(subp)
+ if err := ws.CheckCloseFrameData(code, reason); err != nil {
+ // Here we could not use the prepared bytes because there is no
+ // guarantee that it may fit our protocol error closure code and a
+ // reason.
+ c.closeWithProtocolError(err)
+ return err
+ }
+
+ // Deal with ciphering i/o:
+ // Masking key is used to mask the "Payload data" defined in the same
+ // section as frame-payload-data, which includes "Extension data" and
+ // "Application data".
+ //
+ // See https://tools.ietf.org/html/rfc6455#section-5.3
+ //
+ // NOTE: We prefer ControlWriter with preallocated buffer to
+ // ws.WriteHeader because it performs one syscall instead of two.
+ w := NewControlWriterBuffer(c.Dst, c.State, ws.OpClose, p)
+
+ // RFC6455#5.5.1:
+ // If an endpoint receives a Close frame and did not previously
+ // send a Close frame, the endpoint MUST send a Close frame in
+ // response. (When sending a Close frame in response, the endpoint
+ // typically echoes the status code it received.)
+ _, err := w.Write(p[:2])
+ if err != nil {
+ return err
+ }
+ if err := w.Flush(); err != nil {
+ return err
+ }
+ return ClosedError{
+ Code: code,
+ Reason: reason,
+ }
+}
+
+func (c ControlHandler) closeWithProtocolError(reason error) error {
+ f := ws.NewCloseFrame(ws.NewCloseFrameBody(
+ ws.StatusProtocolError, reason.Error(),
+ ))
+ if c.State.ClientSide() {
+ ws.MaskFrameInPlace(f)
+ }
+ return ws.WriteFrame(c.Dst, f)
+}
diff --git a/vendor/github.com/gobwas/ws/wsutil/helper.go b/vendor/github.com/gobwas/ws/wsutil/helper.go
new file mode 100644
index 0000000..231760b
--- /dev/null
+++ b/vendor/github.com/gobwas/ws/wsutil/helper.go
@@ -0,0 +1,279 @@
+package wsutil
+
+import (
+ "bytes"
+ "io"
+ "io/ioutil"
+
+ "github.com/gobwas/ws"
+)
+
+// Message represents a message from peer, that could be presented in one or
+// more frames. That is, it contains payload of all message fragments and
+// operation code of initial frame for this message.
+type Message struct {
+ OpCode ws.OpCode
+ Payload []byte
+}
+
+// ReadMessage is a helper function that reads next message from r. It appends
+// received message(s) to the third argument and returns the result of it and
+// an error if some failure happened. That is, it probably could receive more
+// than one message when peer sending fragmented message in multiple frames and
+// want to send some control frame between fragments. Then returned slice will
+// contain those control frames at first, and then result of gluing fragments.
+//
+// TODO(gobwas): add DefaultReader with buffer size options.
+func ReadMessage(r io.Reader, s ws.State, m []Message) ([]Message, error) {
+ rd := Reader{
+ Source: r,
+ State: s,
+ CheckUTF8: true,
+ OnIntermediate: func(hdr ws.Header, src io.Reader) error {
+ bts, err := ioutil.ReadAll(src)
+ if err != nil {
+ return err
+ }
+ m = append(m, Message{hdr.OpCode, bts})
+ return nil
+ },
+ }
+ h, err := rd.NextFrame()
+ if err != nil {
+ return m, err
+ }
+ var p []byte
+ if h.Fin {
+ // No more frames will be read. Use fixed sized buffer to read payload.
+ p = make([]byte, h.Length)
+ // It is not possible to receive io.EOF here because Reader does not
+ // return EOF if frame payload was successfully fetched.
+ // Thus we consistent here with io.Reader behavior.
+ _, err = io.ReadFull(&rd, p)
+ } else {
+ // Frame is fragmented, thus use ioutil.ReadAll behavior.
+ var buf bytes.Buffer
+ _, err = buf.ReadFrom(&rd)
+ p = buf.Bytes()
+ }
+ if err != nil {
+ return m, err
+ }
+ return append(m, Message{h.OpCode, p}), nil
+}
+
+// ReadClientMessage reads next message from r, considering that caller
+// represents server side.
+// It is a shortcut for ReadMessage(r, ws.StateServerSide, m).
+func ReadClientMessage(r io.Reader, m []Message) ([]Message, error) {
+ return ReadMessage(r, ws.StateServerSide, m)
+}
+
+// ReadServerMessage reads next message from r, considering that caller
+// represents client side.
+// It is a shortcut for ReadMessage(r, ws.StateClientSide, m).
+func ReadServerMessage(r io.Reader, m []Message) ([]Message, error) {
+ return ReadMessage(r, ws.StateClientSide, m)
+}
+
+// ReadData is a helper function that reads next data (non-control) message
+// from rw.
+// It takes care on handling all control frames. It will write response on
+// control frames to the write part of rw. It blocks until some data frame
+// will be received.
+//
+// Note this may handle and write control frames into the writer part of a
+// given io.ReadWriter.
+func ReadData(rw io.ReadWriter, s ws.State) ([]byte, ws.OpCode, error) {
+ return readData(rw, s, ws.OpText|ws.OpBinary)
+}
+
+// ReadClientData reads next data message from rw, considering that caller
+// represents server side. It is a shortcut for ReadData(rw, ws.StateServerSide).
+//
+// Note this may handle and write control frames into the writer part of a
+// given io.ReadWriter.
+func ReadClientData(rw io.ReadWriter) ([]byte, ws.OpCode, error) {
+ return ReadData(rw, ws.StateServerSide)
+}
+
+// ReadClientText reads next text message from rw, considering that caller
+// represents server side. It is a shortcut for ReadData(rw, ws.StateServerSide).
+// It discards received binary messages.
+//
+// Note this may handle and write control frames into the writer part of a
+// given io.ReadWriter.
+func ReadClientText(rw io.ReadWriter) ([]byte, error) {
+ p, _, err := readData(rw, ws.StateServerSide, ws.OpText)
+ return p, err
+}
+
+// ReadClientBinary reads next binary message from rw, considering that caller
+// represents server side. It is a shortcut for ReadData(rw, ws.StateServerSide).
+// It discards received text messages.
+//
+// Note this may handle and write control frames into the writer part of a given
+// io.ReadWriter.
+func ReadClientBinary(rw io.ReadWriter) ([]byte, error) {
+ p, _, err := readData(rw, ws.StateServerSide, ws.OpBinary)
+ return p, err
+}
+
+// ReadServerData reads next data message from rw, considering that caller
+// represents client side. It is a shortcut for ReadData(rw, ws.StateClientSide).
+//
+// Note this may handle and write control frames into the writer part of a
+// given io.ReadWriter.
+func ReadServerData(rw io.ReadWriter) ([]byte, ws.OpCode, error) {
+ return ReadData(rw, ws.StateClientSide)
+}
+
+// ReadServerText reads next text message from rw, considering that caller
+// represents client side. It is a shortcut for ReadData(rw, ws.StateClientSide).
+// It discards received binary messages.
+//
+// Note this may handle and write control frames into the writer part of a given
+// io.ReadWriter.
+func ReadServerText(rw io.ReadWriter) ([]byte, error) {
+ p, _, err := readData(rw, ws.StateClientSide, ws.OpText)
+ return p, err
+}
+
+// ReadServerBinary reads next binary message from rw, considering that caller
+// represents client side. It is a shortcut for ReadData(rw, ws.StateClientSide).
+// It discards received text messages.
+//
+// Note this may handle and write control frames into the writer part of a
+// given io.ReadWriter.
+func ReadServerBinary(rw io.ReadWriter) ([]byte, error) {
+ p, _, err := readData(rw, ws.StateClientSide, ws.OpBinary)
+ return p, err
+}
+
+// WriteMessage is a helper function that writes message to the w. It
+// constructs single frame with given operation code and payload.
+// It uses given state to prepare side-dependent things, like cipher
+// payload bytes from client to server. It will not mutate p bytes if
+// cipher must be made.
+//
+// If you want to write message in fragmented frames, use Writer instead.
+func WriteMessage(w io.Writer, s ws.State, op ws.OpCode, p []byte) error {
+ return writeFrame(w, s, op, true, p)
+}
+
+// WriteServerMessage writes message to w, considering that caller
+// represents server side.
+func WriteServerMessage(w io.Writer, op ws.OpCode, p []byte) error {
+ return WriteMessage(w, ws.StateServerSide, op, p)
+}
+
+// WriteServerText is the same as WriteServerMessage with
+// ws.OpText.
+func WriteServerText(w io.Writer, p []byte) error {
+ return WriteServerMessage(w, ws.OpText, p)
+}
+
+// WriteServerBinary is the same as WriteServerMessage with
+// ws.OpBinary.
+func WriteServerBinary(w io.Writer, p []byte) error {
+ return WriteServerMessage(w, ws.OpBinary, p)
+}
+
+// WriteClientMessage writes message to w, considering that caller
+// represents client side.
+func WriteClientMessage(w io.Writer, op ws.OpCode, p []byte) error {
+ return WriteMessage(w, ws.StateClientSide, op, p)
+}
+
+// WriteClientText is the same as WriteClientMessage with
+// ws.OpText.
+func WriteClientText(w io.Writer, p []byte) error {
+ return WriteClientMessage(w, ws.OpText, p)
+}
+
+// WriteClientBinary is the same as WriteClientMessage with
+// ws.OpBinary.
+func WriteClientBinary(w io.Writer, p []byte) error {
+ return WriteClientMessage(w, ws.OpBinary, p)
+}
+
+// HandleClientControlMessage handles control frame from conn and writes
+// response when needed.
+//
+// It considers that caller represents server side.
+func HandleClientControlMessage(conn io.Writer, msg Message) error {
+ return HandleControlMessage(conn, ws.StateServerSide, msg)
+}
+
+// HandleServerControlMessage handles control frame from conn and writes
+// response when needed.
+//
+// It considers that caller represents client side.
+func HandleServerControlMessage(conn io.Writer, msg Message) error {
+ return HandleControlMessage(conn, ws.StateClientSide, msg)
+}
+
+// HandleControlMessage handles message which was read by ReadMessage()
+// functions.
+//
+// That is, it is expected, that payload is already unmasked and frame header
+// were checked by ws.CheckHeader() call.
+func HandleControlMessage(conn io.Writer, state ws.State, msg Message) error {
+ return (ControlHandler{
+ DisableSrcCiphering: true,
+ Src: bytes.NewReader(msg.Payload),
+ Dst: conn,
+ State: state,
+ }).Handle(ws.Header{
+ Length: int64(len(msg.Payload)),
+ OpCode: msg.OpCode,
+ Fin: true,
+ Masked: state.ServerSide(),
+ })
+}
+
+// ControlFrameHandler returns FrameHandlerFunc for handling control frames.
+// For more info see ControlHandler docs.
+func ControlFrameHandler(w io.Writer, state ws.State) FrameHandlerFunc {
+ return func(h ws.Header, r io.Reader) error {
+ return (ControlHandler{
+ DisableSrcCiphering: true,
+ Src: r,
+ Dst: w,
+ State: state,
+ }).Handle(h)
+ }
+}
+
+func readData(rw io.ReadWriter, s ws.State, want ws.OpCode) ([]byte, ws.OpCode, error) {
+ controlHandler := ControlFrameHandler(rw, s)
+ rd := Reader{
+ Source: rw,
+ State: s,
+ CheckUTF8: true,
+ SkipHeaderCheck: false,
+ OnIntermediate: controlHandler,
+ }
+ for {
+ hdr, err := rd.NextFrame()
+ if err != nil {
+ return nil, 0, err
+ }
+ if hdr.OpCode.IsControl() {
+ if err := controlHandler(hdr, &rd); err != nil {
+ return nil, 0, err
+ }
+ continue
+ }
+ if hdr.OpCode&want == 0 {
+ if err := rd.Discard(); err != nil {
+ return nil, 0, err
+ }
+ continue
+ }
+
+ bts, err := ioutil.ReadAll(&rd)
+
+ return bts, hdr.OpCode, err
+ }
+}
diff --git a/vendor/github.com/gobwas/ws/wsutil/reader.go b/vendor/github.com/gobwas/ws/wsutil/reader.go
new file mode 100644
index 0000000..f2710af
--- /dev/null
+++ b/vendor/github.com/gobwas/ws/wsutil/reader.go
@@ -0,0 +1,373 @@
+package wsutil
+
+import (
+ "encoding/binary"
+ "errors"
+ "io"
+ "io/ioutil"
+
+ "github.com/gobwas/ws"
+)
+
+// ErrNoFrameAdvance means that Reader's Read() method was called without
+// preceding NextFrame() call.
+var ErrNoFrameAdvance = errors.New("no frame advance")
+
+// ErrFrameTooLarge indicates that a message of length higher than
+// MaxFrameSize was being read.
+var ErrFrameTooLarge = errors.New("frame too large")
+
+// FrameHandlerFunc handles parsed frame header and its body represented by
+// io.Reader.
+//
+// Note that reader represents already unmasked body.
+type FrameHandlerFunc func(ws.Header, io.Reader) error
+
+// Reader is a wrapper around source io.Reader which represents WebSocket
+// connection. It contains options for reading messages from source.
+//
+// Reader implements io.Reader, which Read() method reads payload of incoming
+// WebSocket frames. It also takes care on fragmented frames and possibly
+// intermediate control frames between them.
+//
+// Note that Reader's methods are not goroutine safe.
+type Reader struct {
+ Source io.Reader
+ State ws.State
+
+ // SkipHeaderCheck disables checking header bits to be RFC6455 compliant.
+ SkipHeaderCheck bool
+
+ // CheckUTF8 enables UTF-8 checks for text frames payload. If incoming
+ // bytes are not valid UTF-8 sequence, ErrInvalidUTF8 returned.
+ CheckUTF8 bool
+
+ // Extensions is a list of negotiated extensions for reader Source.
+ // It is used to meet the specs and clear appropriate bits in fragment
+ // header RSV segment.
+ Extensions []RecvExtension
+
+ // MaxFrameSize controls the maximum frame size in bytes
+ // that can be read. A message exceeding that size will return
+ // a ErrFrameTooLarge to the application.
+ //
+ // Not setting this field means there is no limit.
+ MaxFrameSize int64
+
+ OnContinuation FrameHandlerFunc
+ OnIntermediate FrameHandlerFunc
+
+ opCode ws.OpCode // Used to store message op code on fragmentation.
+ frame io.Reader // Used to as frame reader.
+ raw io.LimitedReader // Used to discard frames without cipher.
+ utf8 UTF8Reader // Used to check UTF8 sequences if CheckUTF8 is true.
+ tmp [ws.MaxHeaderSize - 2]byte // Used for reading headers.
+ cr *CipherReader // Used by NextFrame() to unmask frame payload.
+}
+
+// NewReader creates new frame reader that reads from r keeping given state to
+// make some protocol validity checks when it needed.
+func NewReader(r io.Reader, s ws.State) *Reader {
+ return &Reader{
+ Source: r,
+ State: s,
+ }
+}
+
+// NewClientSideReader is a helper function that calls NewReader with r and
+// ws.StateClientSide.
+func NewClientSideReader(r io.Reader) *Reader {
+ return NewReader(r, ws.StateClientSide)
+}
+
+// NewServerSideReader is a helper function that calls NewReader with r and
+// ws.StateServerSide.
+func NewServerSideReader(r io.Reader) *Reader {
+ return NewReader(r, ws.StateServerSide)
+}
+
+// Read implements io.Reader. It reads the next message payload into p.
+// It takes care on fragmented messages.
+//
+// The error is io.EOF only if all of message bytes were read.
+// If an io.EOF happens during reading some but not all the message bytes
+// Read() returns io.ErrUnexpectedEOF.
+//
+// The error is ErrNoFrameAdvance if no NextFrame() call was made before
+// reading next message bytes.
+func (r *Reader) Read(p []byte) (n int, err error) {
+ if r.frame == nil {
+ if !r.fragmented() {
+ // Every new Read() must be preceded by NextFrame() call.
+ return 0, ErrNoFrameAdvance
+ }
+ // Read next continuation or intermediate control frame.
+ _, err := r.NextFrame()
+ if err != nil {
+ return 0, err
+ }
+ if r.frame == nil {
+ // We handled intermediate control and now got nothing to read.
+ return 0, nil
+ }
+ }
+
+ n, err = r.frame.Read(p)
+ if err != nil && err != io.EOF {
+ return n, err
+ }
+ if err == nil && r.raw.N != 0 {
+ return n, nil
+ }
+
+ // EOF condition (either err is io.EOF or r.raw.N is zero).
+ switch {
+ case r.raw.N != 0:
+ err = io.ErrUnexpectedEOF
+
+ case r.fragmented():
+ err = nil
+ r.resetFragment()
+
+ case r.CheckUTF8 && !r.utf8.Valid():
+ // NOTE: check utf8 only when full message received, since partial
+ // reads may be invalid.
+ n = r.utf8.Accepted()
+ err = ErrInvalidUTF8
+
+ default:
+ r.reset()
+ err = io.EOF
+ }
+
+ return n, err
+}
+
+// Discard discards current message unread bytes.
+// It discards all frames of fragmented message.
+func (r *Reader) Discard() (err error) {
+ for {
+ _, err = io.Copy(ioutil.Discard, &r.raw)
+ if err != nil {
+ break
+ }
+ if !r.fragmented() {
+ break
+ }
+ if _, err = r.NextFrame(); err != nil {
+ break
+ }
+ }
+ r.reset()
+ return err
+}
+
+// NextFrame prepares r to read next message. It returns received frame header
+// and non-nil error on failure.
+//
+// Note that next NextFrame() call must be done after receiving or discarding
+// all current message bytes.
+func (r *Reader) NextFrame() (hdr ws.Header, err error) {
+ hdr, err = r.readHeader(r.Source)
+ if err == io.EOF && r.fragmented() {
+ // If we are in fragmented state EOF means that is was totally
+ // unexpected.
+ //
+ // NOTE: This is necessary to prevent callers such that
+ // ioutil.ReadAll to receive some amount of bytes without an error.
+ // ReadAll() ignores an io.EOF error, thus caller may think that
+ // whole message fetched, but actually only part of it.
+ err = io.ErrUnexpectedEOF
+ }
+ if err == nil && !r.SkipHeaderCheck {
+ err = ws.CheckHeader(hdr, r.State)
+ }
+ if err != nil {
+ return hdr, err
+ }
+
+ if n := r.MaxFrameSize; n > 0 && hdr.Length > n {
+ return hdr, ErrFrameTooLarge
+ }
+
+ // Save raw reader to use it on discarding frame without ciphering and
+ // other streaming checks.
+ r.raw = io.LimitedReader{
+ R: r.Source,
+ N: hdr.Length,
+ }
+
+ frame := io.Reader(&r.raw)
+ if hdr.Masked {
+ if r.cr == nil {
+ r.cr = NewCipherReader(frame, hdr.Mask)
+ } else {
+ r.cr.Reset(frame, hdr.Mask)
+ }
+ frame = r.cr
+ }
+
+ for _, x := range r.Extensions {
+ hdr, err = x.UnsetBits(hdr)
+ if err != nil {
+ return hdr, err
+ }
+ }
+
+ if r.fragmented() {
+ if hdr.OpCode.IsControl() {
+ if cb := r.OnIntermediate; cb != nil {
+ err = cb(hdr, frame)
+ }
+ if err == nil {
+ // Ensure that src is empty.
+ _, err = io.Copy(ioutil.Discard, &r.raw)
+ }
+ return hdr, err
+ }
+ } else {
+ r.opCode = hdr.OpCode
+ }
+ if r.CheckUTF8 && (hdr.OpCode == ws.OpText || (r.fragmented() && r.opCode == ws.OpText)) {
+ r.utf8.Source = frame
+ frame = &r.utf8
+ }
+
+ // Save reader with ciphering and other streaming checks.
+ r.frame = frame
+
+ if hdr.OpCode == ws.OpContinuation {
+ if cb := r.OnContinuation; cb != nil {
+ err = cb(hdr, frame)
+ }
+ }
+
+ if hdr.Fin {
+ r.State = r.State.Clear(ws.StateFragmented)
+ } else {
+ r.State = r.State.Set(ws.StateFragmented)
+ }
+
+ return hdr, err
+}
+
+func (r *Reader) fragmented() bool {
+ return r.State.Fragmented()
+}
+
+func (r *Reader) resetFragment() {
+ r.raw = io.LimitedReader{}
+ r.frame = nil
+ // Reset source of the UTF8Reader, but not the state.
+ r.utf8.Source = nil
+}
+
+func (r *Reader) reset() {
+ r.raw = io.LimitedReader{}
+ r.frame = nil
+ r.utf8 = UTF8Reader{}
+ r.opCode = 0
+}
+
+// readHeader reads a frame header from in.
+func (r *Reader) readHeader(in io.Reader) (h ws.Header, err error) {
+ // Make slice of bytes with capacity 12 that could hold any header.
+ //
+ // The maximum header size is 14, but due to the 2 hop reads,
+ // after first hop that reads first 2 constant bytes, we could reuse 2 bytes.
+ // So 14 - 2 = 12.
+ bts := r.tmp[:2]
+
+ // Prepare to hold first 2 bytes to choose size of next read.
+ _, err = io.ReadFull(in, bts)
+ if err != nil {
+ return h, err
+ }
+ const bit0 = 0x80
+
+ h.Fin = bts[0]&bit0 != 0
+ h.Rsv = (bts[0] & 0x70) >> 4
+ h.OpCode = ws.OpCode(bts[0] & 0x0f)
+
+ var extra int
+
+ if bts[1]&bit0 != 0 {
+ h.Masked = true
+ extra += 4
+ }
+
+ length := bts[1] & 0x7f
+ switch {
+ case length < 126:
+ h.Length = int64(length)
+
+ case length == 126:
+ extra += 2
+
+ case length == 127:
+ extra += 8
+
+ default:
+ err = ws.ErrHeaderLengthUnexpected
+ return h, err
+ }
+
+ if extra == 0 {
+ return h, err
+ }
+
+ // Increase len of bts to extra bytes need to read.
+ // Overwrite first 2 bytes that was read before.
+ bts = bts[:extra]
+ _, err = io.ReadFull(in, bts)
+ if err != nil {
+ return h, err
+ }
+
+ switch {
+ case length == 126:
+ h.Length = int64(binary.BigEndian.Uint16(bts[:2]))
+ bts = bts[2:]
+
+ case length == 127:
+ if bts[0]&0x80 != 0 {
+ err = ws.ErrHeaderLengthMSB
+ return h, err
+ }
+ h.Length = int64(binary.BigEndian.Uint64(bts[:8]))
+ bts = bts[8:]
+ }
+
+ if h.Masked {
+ copy(h.Mask[:], bts)
+ }
+
+ return h, nil
+}
+
+// NextReader prepares next message read from r. It returns header that
+// describes the message and io.Reader to read message's payload. It returns
+// non-nil error when it is not possible to read message's initial frame.
+//
+// Note that next NextReader() on the same r should be done after reading all
+// bytes from previously returned io.Reader. For more performant way to discard
+// message use Reader and its Discard() method.
+//
+// Note that it will not handle any "intermediate" frames, that possibly could
+// be received between text/binary continuation frames. That is, if peer sent
+// text/binary frame with fin flag "false", then it could send ping frame, and
+// eventually remaining part of text/binary frame with fin "true" – with
+// NextReader() the ping frame will be dropped without any notice. To handle
+// this rare, but possible situation (and if you do not know exactly which
+// frames peer could send), you could use Reader with OnIntermediate field set.
+func NextReader(r io.Reader, s ws.State) (ws.Header, io.Reader, error) {
+ rd := &Reader{
+ Source: r,
+ State: s,
+ }
+ header, err := rd.NextFrame()
+ if err != nil {
+ return header, nil, err
+ }
+ return header, rd, nil
+}
diff --git a/vendor/github.com/gobwas/ws/wsutil/upgrader.go b/vendor/github.com/gobwas/ws/wsutil/upgrader.go
new file mode 100644
index 0000000..2ed351e
--- /dev/null
+++ b/vendor/github.com/gobwas/ws/wsutil/upgrader.go
@@ -0,0 +1,68 @@
+package wsutil
+
+import (
+ "bufio"
+ "bytes"
+ "io"
+ "io/ioutil"
+ "net/http"
+
+ "github.com/gobwas/ws"
+)
+
+// DebugUpgrader is a wrapper around ws.Upgrader. It tracks I/O of a
+// WebSocket handshake.
+//
+// Note that it must not be used in production applications that requires
+// Upgrade() to be efficient.
+type DebugUpgrader struct {
+ // Upgrader contains upgrade to WebSocket options.
+ Upgrader ws.Upgrader
+
+ // OnRequest and OnResponse are the callbacks that will be called with the
+ // HTTP request and response respectively.
+ OnRequest, OnResponse func([]byte)
+}
+
+// Upgrade calls Upgrade() on underlying ws.Upgrader and tracks I/O on conn.
+func (d *DebugUpgrader) Upgrade(conn io.ReadWriter) (hs ws.Handshake, err error) {
+ var (
+ // Take the Reader and Writer parts from conn to be probably replaced
+ // below.
+ r io.Reader = conn
+ w io.Writer = conn
+ )
+ if onRequest := d.OnRequest; onRequest != nil {
+ var buf bytes.Buffer
+ // First, we must read the entire request.
+ req, err := http.ReadRequest(bufio.NewReader(
+ io.TeeReader(conn, &buf),
+ ))
+ if err == nil {
+ // Fulfill the buffer with the response body.
+ io.Copy(ioutil.Discard, req.Body)
+ req.Body.Close()
+ }
+ onRequest(buf.Bytes())
+
+ r = io.MultiReader(
+ &buf, conn,
+ )
+ }
+
+ if onResponse := d.OnResponse; onResponse != nil {
+ var buf bytes.Buffer
+ // Intercept the response stream written by the Upgrade().
+ w = io.MultiWriter(
+ conn, &buf,
+ )
+ defer func() {
+ onResponse(buf.Bytes())
+ }()
+ }
+
+ return d.Upgrader.Upgrade(struct {
+ io.Reader
+ io.Writer
+ }{r, w})
+}
diff --git a/vendor/github.com/gobwas/ws/wsutil/utf8.go b/vendor/github.com/gobwas/ws/wsutil/utf8.go
new file mode 100644
index 0000000..b8dc726
--- /dev/null
+++ b/vendor/github.com/gobwas/ws/wsutil/utf8.go
@@ -0,0 +1,140 @@
+package wsutil
+
+import (
+ "fmt"
+ "io"
+)
+
+// ErrInvalidUTF8 is returned by UTF8 reader on invalid utf8 sequence.
+var ErrInvalidUTF8 = fmt.Errorf("invalid utf8")
+
+// UTF8Reader implements io.Reader that calculates utf8 validity state after
+// every read byte from Source.
+//
+// Note that in some cases client must call r.Valid() after all bytes are read
+// to ensure that all of them are valid utf8 sequences. That is, some io helper
+// functions such io.ReadAtLeast or io.ReadFull could discard the error
+// information returned by the reader when they receive all of requested bytes.
+// For example, the last read sequence is invalid and UTF8Reader returns number
+// of bytes read and an error. But helper function decides to discard received
+// error due to all requested bytes are completely read from the source.
+//
+// Another possible case is when some valid sequence become split by the read
+// bound. Then UTF8Reader can not make decision about validity of the last
+// sequence cause it is not fully read yet. And if the read stops, Valid() will
+// return false, even if Read() by itself dit not.
+type UTF8Reader struct {
+ Source io.Reader
+
+ accepted int
+
+ state uint32
+ codep uint32
+}
+
+// NewUTF8Reader creates utf8 reader that reads from r.
+func NewUTF8Reader(r io.Reader) *UTF8Reader {
+ return &UTF8Reader{
+ Source: r,
+ }
+}
+
+// Reset resets utf8 reader to read from r.
+func (u *UTF8Reader) Reset(r io.Reader) {
+ u.Source = r
+ u.state = 0
+ u.codep = 0
+}
+
+// Read implements io.Reader.
+func (u *UTF8Reader) Read(p []byte) (n int, err error) {
+ n, err = u.Source.Read(p)
+
+ accepted := 0
+ s, c := u.state, u.codep
+ for i := 0; i < n; i++ {
+ c, s = decode(s, c, p[i])
+ if s == utf8Reject {
+ u.state = s
+ return accepted, ErrInvalidUTF8
+ }
+ if s == utf8Accept {
+ accepted = i + 1
+ }
+ }
+ u.state, u.codep = s, c
+ u.accepted = accepted
+
+ return n, err
+}
+
+// Valid checks current reader state. It returns true if all read bytes are
+// valid UTF-8 sequences, and false if not.
+func (u *UTF8Reader) Valid() bool {
+ return u.state == utf8Accept
+}
+
+// Accepted returns number of valid bytes in last Read().
+func (u *UTF8Reader) Accepted() int {
+ return u.accepted
+}
+
+// Below is port of UTF-8 decoder from http://bjoern.hoehrmann.de/utf-8/decoder/dfa/
+//
+// Copyright (c) 2008-2009 Bjoern Hoehrmann
+//
+// 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.
+
+const (
+ utf8Accept = 0
+ utf8Reject = 12
+)
+
+var utf8d = [...]byte{
+ // The first part of the table maps bytes to character classes that
+ // to reduce the size of the transition table and create bitmasks.
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 8, 8, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 10, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 3, 3, 11, 6, 6, 6, 5, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+
+ // The second part is a transition table that maps a combination
+ // of a state of the automaton and a character class to a state.
+ 0, 12, 24, 36, 60, 96, 84, 12, 12, 12, 48, 72, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+ 12, 0, 12, 12, 12, 12, 12, 0, 12, 0, 12, 12, 12, 24, 12, 12, 12, 12, 12, 24, 12, 24, 12, 12,
+ 12, 12, 12, 12, 12, 12, 12, 24, 12, 12, 12, 12, 12, 24, 12, 12, 12, 12, 12, 12, 12, 24, 12, 12,
+ 12, 12, 12, 12, 12, 12, 12, 36, 12, 36, 12, 12, 12, 36, 12, 12, 12, 12, 12, 36, 12, 36, 12, 12,
+ 12, 36, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+}
+
+func decode(state, codep uint32, b byte) (uint32, uint32) {
+ t := uint32(utf8d[b])
+
+ if state != utf8Accept {
+ codep = (uint32(b) & 0x3f) | (codep << 6)
+ } else {
+ codep = (0xff >> t) & uint32(b)
+ }
+
+ return codep, uint32(utf8d[256+state+t])
+}
diff --git a/vendor/github.com/gobwas/ws/wsutil/writer.go b/vendor/github.com/gobwas/ws/wsutil/writer.go
new file mode 100644
index 0000000..6a837cf
--- /dev/null
+++ b/vendor/github.com/gobwas/ws/wsutil/writer.go
@@ -0,0 +1,599 @@
+package wsutil
+
+import (
+ "fmt"
+ "io"
+
+ "github.com/gobwas/pool"
+ "github.com/gobwas/pool/pbytes"
+ "github.com/gobwas/ws"
+)
+
+// DefaultWriteBuffer contains size of Writer's default buffer. It used by
+// Writer constructor functions.
+var DefaultWriteBuffer = 4096
+
+var (
+ // ErrNotEmpty is returned by Writer.WriteThrough() to indicate that buffer is
+ // not empty and write through could not be done. That is, caller should call
+ // Writer.FlushFragment() to make buffer empty.
+ ErrNotEmpty = fmt.Errorf("writer not empty")
+
+ // ErrControlOverflow is returned by ControlWriter.Write() to indicate that
+ // no more data could be written to the underlying io.Writer because
+ // MaxControlFramePayloadSize limit is reached.
+ ErrControlOverflow = fmt.Errorf("control frame payload overflow")
+)
+
+// Constants which are represent frame length ranges.
+const (
+ len7 = int64(125) // 126 and 127 are reserved values
+ len16 = int64(^uint16(0))
+ len64 = int64((^uint64(0)) >> 1)
+)
+
+// ControlWriter is a wrapper around Writer that contains some guards for
+// buffered writes of control frames.
+type ControlWriter struct {
+ w *Writer
+ limit int
+ n int
+}
+
+// NewControlWriter contains ControlWriter with Writer inside whose buffer size
+// is at most ws.MaxControlFramePayloadSize + ws.MaxHeaderSize.
+func NewControlWriter(dest io.Writer, state ws.State, op ws.OpCode) *ControlWriter {
+ return &ControlWriter{
+ w: NewWriterSize(dest, state, op, ws.MaxControlFramePayloadSize),
+ limit: ws.MaxControlFramePayloadSize,
+ }
+}
+
+// NewControlWriterBuffer returns a new ControlWriter with buf as a buffer.
+//
+// Note that it reserves x bytes of buf for header data, where x could be
+// ws.MinHeaderSize or ws.MinHeaderSize+4 (depending on state). At most
+// (ws.MaxControlFramePayloadSize + x) bytes of buf will be used.
+//
+// It panics if len(buf) <= ws.MinHeaderSize + x.
+func NewControlWriterBuffer(dest io.Writer, state ws.State, op ws.OpCode, buf []byte) *ControlWriter {
+ max := ws.MaxControlFramePayloadSize + headerSize(state, ws.MaxControlFramePayloadSize)
+ if len(buf) > max {
+ buf = buf[:max]
+ }
+
+ w := NewWriterBuffer(dest, state, op, buf)
+
+ return &ControlWriter{
+ w: w,
+ limit: len(w.buf),
+ }
+}
+
+// Write implements io.Writer. It writes to the underlying Writer until it
+// returns error or until ControlWriter write limit will be exceeded.
+func (c *ControlWriter) Write(p []byte) (n int, err error) {
+ if c.n+len(p) > c.limit {
+ return 0, ErrControlOverflow
+ }
+ return c.w.Write(p)
+}
+
+// Flush flushes all buffered data to the underlying io.Writer.
+func (c *ControlWriter) Flush() error {
+ return c.w.Flush()
+}
+
+var writers = pool.New(128, 65536)
+
+// GetWriter tries to reuse Writer getting it from the pool.
+//
+// This function is intended for memory consumption optimizations, because
+// NewWriter*() functions make allocations for inner buffer.
+//
+// Note the it ceils n to the power of two.
+//
+// If you have your own bytes buffer pool you could use NewWriterBuffer to use
+// pooled bytes in writer.
+func GetWriter(dest io.Writer, state ws.State, op ws.OpCode, n int) *Writer {
+ x, m := writers.Get(n)
+ if x != nil {
+ w := x.(*Writer)
+ w.Reset(dest, state, op)
+ return w
+ }
+ // NOTE: we use m instead of n, because m is an attempt to reuse w of such
+ // size in the future.
+ return NewWriterBufferSize(dest, state, op, m)
+}
+
+// PutWriter puts w for future reuse by GetWriter().
+func PutWriter(w *Writer) {
+ w.Reset(nil, 0, 0)
+ writers.Put(w, w.Size())
+}
+
+// Writer contains logic of buffering output data into a WebSocket fragments.
+// It is much the same as bufio.Writer, except the thing that it works with
+// WebSocket frames, not the raw data.
+//
+// Writer writes frames with specified OpCode.
+// It uses ws.State to decide whether the output frames must be masked.
+//
+// Note that it does not check control frame size or other RFC rules.
+// That is, it must be used with special care to write control frames without
+// violation of RFC. You could use ControlWriter that wraps Writer and contains
+// some guards for writing control frames.
+//
+// If an error occurs writing to a Writer, no more data will be accepted and
+// all subsequent writes will return the error.
+//
+// After all data has been written, the client should call the Flush() method
+// to guarantee all data has been forwarded to the underlying io.Writer.
+type Writer struct {
+ // dest specifies a destination of buffer flushes.
+ dest io.Writer
+
+ // op specifies the WebSocket operation code used in flushed frames.
+ op ws.OpCode
+
+ // state specifies the state of the Writer.
+ state ws.State
+
+ // extensions is a list of negotiated extensions for writer Dest.
+ // It is used to meet the specs and set appropriate bits in fragment
+ // header RSV segment.
+ extensions []SendExtension
+
+ // noFlush reports whether buffer must grow instead of being flushed.
+ noFlush bool
+
+ // Raw representation of the buffer, including reserved header bytes.
+ raw []byte
+
+ // Writeable part of buffer, without reserved header bytes.
+ // Resetting this to nil will not result in reallocation if raw is not nil.
+ // And vice versa: if buf is not nil, then Writer is assumed as ready and
+ // initialized.
+ buf []byte
+
+ // Buffered bytes counter.
+ n int
+
+ dirty bool
+ fseq int
+ err error
+}
+
+// NewWriter returns a new Writer whose buffer has the DefaultWriteBuffer size.
+func NewWriter(dest io.Writer, state ws.State, op ws.OpCode) *Writer {
+ return NewWriterBufferSize(dest, state, op, 0)
+}
+
+// NewWriterSize returns a new Writer whose buffer size is at most n + ws.MaxHeaderSize.
+// That is, output frames payload length could be up to n, except the case when
+// Write() is called on empty Writer with len(p) > n.
+//
+// If n <= 0 then the default buffer size is used as Writer's buffer size.
+func NewWriterSize(dest io.Writer, state ws.State, op ws.OpCode, n int) *Writer {
+ if n > 0 {
+ n += headerSize(state, n)
+ }
+ return NewWriterBufferSize(dest, state, op, n)
+}
+
+// NewWriterBufferSize returns a new Writer whose buffer size is equal to n.
+// If n <= ws.MinHeaderSize then the default buffer size is used.
+//
+// Note that Writer will reserve x bytes for header data, where x is in range
+// [ws.MinHeaderSize,ws.MaxHeaderSize]. That is, frames flushed by Writer
+// will not have payload length equal to n, except the case when Write() is
+// called on empty Writer with len(p) > n.
+func NewWriterBufferSize(dest io.Writer, state ws.State, op ws.OpCode, n int) *Writer {
+ if n <= ws.MinHeaderSize {
+ n = DefaultWriteBuffer
+ }
+ return NewWriterBuffer(dest, state, op, make([]byte, n))
+}
+
+// NewWriterBuffer returns a new Writer with buf as a buffer.
+//
+// Note that it reserves x bytes of buf for header data, where x is in range
+// [ws.MinHeaderSize,ws.MaxHeaderSize] (depending on state and buf size).
+//
+// You could use ws.HeaderSize() to calculate number of bytes needed to store
+// header data.
+//
+// It panics if len(buf) is too small to fit header and payload data.
+func NewWriterBuffer(dest io.Writer, state ws.State, op ws.OpCode, buf []byte) *Writer {
+ w := &Writer{
+ dest: dest,
+ state: state,
+ op: op,
+ raw: buf,
+ }
+ w.initBuf()
+ return w
+}
+
+func (w *Writer) initBuf() {
+ offset := reserve(w.state, len(w.raw))
+ if len(w.raw) <= offset {
+ panic("wsutil: writer buffer is too small")
+ }
+ w.buf = w.raw[offset:]
+}
+
+// Reset resets Writer as it was created by New() methods.
+// Note that Reset does reset extensions and other options was set after
+// Writer initialization.
+func (w *Writer) Reset(dest io.Writer, state ws.State, op ws.OpCode) {
+ w.dest = dest
+ w.state = state
+ w.op = op
+
+ w.initBuf()
+
+ w.n = 0
+ w.dirty = false
+ w.fseq = 0
+ w.extensions = w.extensions[:0]
+ w.noFlush = false
+}
+
+// ResetOp is an quick version of Reset().
+// ResetOp does reset unwritten fragments and does not reset results of
+// SetExtensions() or DisableFlush() methods.
+func (w *Writer) ResetOp(op ws.OpCode) {
+ w.op = op
+ w.n = 0
+ w.dirty = false
+ w.fseq = 0
+}
+
+// SetExtensions adds xs as extensions to be used during writes.
+func (w *Writer) SetExtensions(xs ...SendExtension) {
+ w.extensions = xs
+}
+
+// DisableFlush denies Writer to write fragments.
+func (w *Writer) DisableFlush() {
+ w.noFlush = true
+}
+
+// Size returns the size of the underlying buffer in bytes (not including
+// WebSocket header bytes).
+func (w *Writer) Size() int {
+ return len(w.buf)
+}
+
+// Available returns how many bytes are unused in the buffer.
+func (w *Writer) Available() int {
+ return len(w.buf) - w.n
+}
+
+// Buffered returns the number of bytes that have been written into the current
+// buffer.
+func (w *Writer) Buffered() int {
+ return w.n
+}
+
+// Write implements io.Writer.
+//
+// Note that even if the Writer was created to have N-sized buffer, Write()
+// with payload of N bytes will not fit into that buffer. Writer reserves some
+// space to fit WebSocket header data.
+func (w *Writer) Write(p []byte) (n int, err error) {
+ // Even empty p may make a sense.
+ w.dirty = true
+
+ var nn int
+ for len(p) > w.Available() && w.err == nil {
+ if w.noFlush {
+ w.Grow(len(p))
+ continue
+ }
+ if w.Buffered() == 0 {
+ // Large write, empty buffer. Write directly from p to avoid copy.
+ // Trade off here is that we make additional Write() to underlying
+ // io.Writer when writing frame header.
+ //
+ // On large buffers additional write is better than copying.
+ nn, _ = w.WriteThrough(p)
+ } else {
+ nn = copy(w.buf[w.n:], p)
+ w.n += nn
+ w.FlushFragment()
+ }
+ n += nn
+ p = p[nn:]
+ }
+ if w.err != nil {
+ return n, w.err
+ }
+ nn = copy(w.buf[w.n:], p)
+ w.n += nn
+ n += nn
+
+ // Even if w.Available() == 0 we will not flush buffer preventively because
+ // this could bring unwanted fragmentation. That is, user could create
+ // buffer with size that fits exactly all further Write() call, and then
+ // call Flush(), excepting that single and not fragmented frame will be
+ // sent. With preemptive flush this case will produce two frames – last one
+ // will be empty and just to set fin = true.
+
+ return n, w.err
+}
+
+func ceilPowerOfTwo(n int) int {
+ n |= n >> 1
+ n |= n >> 2
+ n |= n >> 4
+ n |= n >> 8
+ n |= n >> 16
+ n |= n >> 32
+ n++
+ return n
+}
+
+// Grow grows Writer's internal buffer capacity to guarantee space for another
+// n bytes of _payload_ -- that is, frame header is not included in n.
+func (w *Writer) Grow(n int) {
+ // NOTE: we must respect the possibility of header reserved bytes grow.
+ var (
+ size = len(w.raw)
+ prevOffset = len(w.raw) - len(w.buf)
+ nextOffset = len(w.raw) - len(w.buf)
+ buffered = w.Buffered()
+ )
+ for cap := size - nextOffset - buffered; cap < n; {
+ // This loop runs twice only at split cases, when reservation of raw
+ // buffer space for the header shrinks capacity of new buffer such that
+ // it still less than n.
+ //
+ // Loop is safe here because:
+ // - (offset + buffered + n) is greater than size, otherwise (cap < n)
+ // would be false:
+ // size = offset + buffered + freeSpace (cap)
+ // size' = offset + buffered + wantSpace (n)
+ // Since (cap < n) is true in the loop condition, size' is guaranteed
+ // to be greater => no infinite loop.
+ size = ceilPowerOfTwo(nextOffset + buffered + n)
+ nextOffset = reserve(w.state, size)
+ cap = size - nextOffset - buffered
+ }
+ if size < len(w.raw) {
+ panic("wsutil: buffer grow leads to its reduce")
+ }
+ if size == len(w.raw) {
+ return
+ }
+ p := make([]byte, size)
+ copy(p[nextOffset-prevOffset:], w.raw[:prevOffset+buffered])
+ w.raw = p
+ w.buf = w.raw[nextOffset:]
+}
+
+// WriteThrough writes data bypassing the buffer.
+// Note that Writer's buffer must be empty before calling WriteThrough().
+func (w *Writer) WriteThrough(p []byte) (n int, err error) {
+ if w.err != nil {
+ return 0, w.err
+ }
+ if w.Buffered() != 0 {
+ return 0, ErrNotEmpty
+ }
+
+ var frame ws.Frame
+ frame.Header = ws.Header{
+ OpCode: w.opCode(),
+ Fin: false,
+ Length: int64(len(p)),
+ }
+ for _, x := range w.extensions {
+ frame.Header, err = x.SetBits(frame.Header)
+ if err != nil {
+ return 0, err
+ }
+ }
+ if w.state.ClientSide() {
+ // Should copy bytes to prevent corruption of caller data.
+ payload := pbytes.GetLen(len(p))
+ defer pbytes.Put(payload)
+ copy(payload, p)
+
+ frame.Payload = payload
+ frame = ws.MaskFrameInPlace(frame)
+ } else {
+ frame.Payload = p
+ }
+
+ w.err = ws.WriteFrame(w.dest, frame)
+ if w.err == nil {
+ n = len(p)
+ }
+
+ w.dirty = true
+ w.fseq++
+
+ return n, w.err
+}
+
+// ReadFrom implements io.ReaderFrom.
+func (w *Writer) ReadFrom(src io.Reader) (n int64, err error) {
+ var nn int
+ for err == nil {
+ if w.Available() == 0 {
+ if w.noFlush {
+ w.Grow(w.Buffered()) // Twice bigger.
+ } else {
+ err = w.FlushFragment()
+ }
+ continue
+ }
+
+ // We copy the behavior of bufio.Writer here.
+ // Also, from the docs on io.ReaderFrom:
+ // ReadFrom reads data from r until EOF or error.
+ //
+ // See https://codereview.appspot.com/76400048/#ps1
+ const maxEmptyReads = 100
+ var nr int
+ for nr < maxEmptyReads {
+ nn, err = src.Read(w.buf[w.n:])
+ if nn != 0 || err != nil {
+ break
+ }
+ nr++
+ }
+ if nr == maxEmptyReads {
+ return n, io.ErrNoProgress
+ }
+
+ w.n += nn
+ n += int64(nn)
+ }
+ if err == io.EOF {
+ // NOTE: Do not flush preemptively.
+ // See the Write() sources for more info.
+ err = nil
+ w.dirty = true
+ }
+ return n, err
+}
+
+// Flush writes any buffered data to the underlying io.Writer.
+// It sends the frame with "fin" flag set to true.
+//
+// If no Write() or ReadFrom() was made, then Flush() does nothing.
+func (w *Writer) Flush() error {
+ if (!w.dirty && w.Buffered() == 0) || w.err != nil {
+ return w.err
+ }
+
+ w.err = w.flushFragment(true)
+ w.n = 0
+ w.dirty = false
+ w.fseq = 0
+
+ return w.err
+}
+
+// FlushFragment writes any buffered data to the underlying io.Writer.
+// It sends the frame with "fin" flag set to false.
+func (w *Writer) FlushFragment() error {
+ if w.Buffered() == 0 || w.err != nil {
+ return w.err
+ }
+
+ w.err = w.flushFragment(false)
+ w.n = 0
+ w.fseq++
+
+ return w.err
+}
+
+func (w *Writer) flushFragment(fin bool) (err error) {
+ var (
+ payload = w.buf[:w.n]
+ header = ws.Header{
+ OpCode: w.opCode(),
+ Fin: fin,
+ Length: int64(len(payload)),
+ }
+ )
+ for _, ext := range w.extensions {
+ header, err = ext.SetBits(header)
+ if err != nil {
+ return err
+ }
+ }
+ if w.state.ClientSide() {
+ header.Masked = true
+ header.Mask = ws.NewMask()
+ ws.Cipher(payload, header.Mask, 0)
+ }
+ // Write header to the header segment of the raw buffer.
+ var (
+ offset = len(w.raw) - len(w.buf)
+ skip = offset - ws.HeaderSize(header)
+ )
+ buf := bytesWriter{
+ buf: w.raw[skip:offset],
+ }
+ if err := ws.WriteHeader(&buf, header); err != nil {
+ // Must never be reached.
+ panic("dump header error: " + err.Error())
+ }
+ _, err = w.dest.Write(w.raw[skip : offset+w.n])
+ return err
+}
+
+func (w *Writer) opCode() ws.OpCode {
+ if w.fseq > 0 {
+ return ws.OpContinuation
+ }
+ return w.op
+}
+
+var errNoSpace = fmt.Errorf("not enough buffer space")
+
+type bytesWriter struct {
+ buf []byte
+ pos int
+}
+
+func (w *bytesWriter) Write(p []byte) (int, error) {
+ n := copy(w.buf[w.pos:], p)
+ w.pos += n
+ if n != len(p) {
+ return n, errNoSpace
+ }
+ return n, nil
+}
+
+func writeFrame(w io.Writer, s ws.State, op ws.OpCode, fin bool, p []byte) error {
+ var frame ws.Frame
+ if s.ClientSide() {
+ // Should copy bytes to prevent corruption of caller data.
+ payload := pbytes.GetLen(len(p))
+ defer pbytes.Put(payload)
+
+ copy(payload, p)
+
+ frame = ws.NewFrame(op, fin, payload)
+ frame = ws.MaskFrameInPlace(frame)
+ } else {
+ frame = ws.NewFrame(op, fin, p)
+ }
+
+ return ws.WriteFrame(w, frame)
+}
+
+// reserve calculates number of bytes need to be reserved for frame header.
+//
+// Note that instead of ws.HeaderSize() it does calculation based on the buffer
+// size, not the payload size.
+func reserve(state ws.State, n int) (offset int) {
+ var mask int
+ if state.ClientSide() {
+ mask = 4
+ }
+ switch {
+ case n <= int(len7)+mask+2:
+ return mask + 2
+ case n <= int(len16)+mask+4:
+ return mask + 4
+ default:
+ return mask + 10
+ }
+}
+
+// headerSize returns number of bytes needed to encode header of a frame with
+// given state and length.
+func headerSize(s ws.State, n int) int {
+ return ws.HeaderSize(ws.Header{
+ Length: int64(n),
+ Masked: s.ClientSide(),
+ })
+}
diff --git a/vendor/github.com/gobwas/ws/wsutil/wsutil.go b/vendor/github.com/gobwas/ws/wsutil/wsutil.go
new file mode 100644
index 0000000..86211f3
--- /dev/null
+++ b/vendor/github.com/gobwas/ws/wsutil/wsutil.go
@@ -0,0 +1,57 @@
+/*
+Package wsutil provides utilities for working with WebSocket protocol.
+
+Overview:
+
+ // Read masked text message from peer and check utf8 encoding.
+ header, err := ws.ReadHeader(conn)
+ if err != nil {
+ // handle err
+ }
+
+ // Prepare to read payload.
+ r := io.LimitReader(conn, header.Length)
+ r = wsutil.NewCipherReader(r, header.Mask)
+ r = wsutil.NewUTF8Reader(r)
+
+ payload, err := ioutil.ReadAll(r)
+ if err != nil {
+ // handle err
+ }
+
+You could get the same behavior using just `wsutil.Reader`:
+
+ r := wsutil.Reader{
+ Source: conn,
+ CheckUTF8: true,
+ }
+
+ payload, err := ioutil.ReadAll(r)
+ if err != nil {
+ // handle err
+ }
+
+Or even simplest:
+
+ payload, err := wsutil.ReadClientText(conn)
+ if err != nil {
+ // handle err
+ }
+
+Package is also exports tools for buffered writing:
+
+ // Create buffered writer, that will buffer output bytes and send them as
+ // 128-length fragments (with exception on large writes, see the doc).
+ writer := wsutil.NewWriterSize(conn, ws.StateServerSide, ws.OpText, 128)
+
+ _, err := io.CopyN(writer, rand.Reader, 100)
+ if err == nil {
+ err = writer.Flush()
+ }
+ if err != nil {
+ // handle error
+ }
+
+For more utils and helpers see the documentation.
+*/
+package wsutil
diff --git a/vendor/github.com/jmoiron/sqlx/.gitignore b/vendor/github.com/jmoiron/sqlx/.gitignore
new file mode 100644
index 0000000..b2be23c
--- /dev/null
+++ b/vendor/github.com/jmoiron/sqlx/.gitignore
@@ -0,0 +1,25 @@
+# Compiled Object files, Static and Dynamic libs (Shared Objects)
+*.o
+*.a
+*.so
+
+# Folders
+_obj
+_test
+.idea
+
+# Architecture specific extensions/prefixes
+*.[568vq]
+[568vq].out
+
+*.cgo1.go
+*.cgo2.c
+_cgo_defun.c
+_cgo_gotypes.go
+_cgo_export.*
+
+_testmain.go
+
+*.exe
+tags
+environ
diff --git a/vendor/github.com/jmoiron/sqlx/LICENSE b/vendor/github.com/jmoiron/sqlx/LICENSE
new file mode 100644
index 0000000..0d31edf
--- /dev/null
+++ b/vendor/github.com/jmoiron/sqlx/LICENSE
@@ -0,0 +1,23 @@
+ Copyright (c) 2013, Jason Moiron
+
+ 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/jmoiron/sqlx/Makefile b/vendor/github.com/jmoiron/sqlx/Makefile
new file mode 100644
index 0000000..448b9dd
--- /dev/null
+++ b/vendor/github.com/jmoiron/sqlx/Makefile
@@ -0,0 +1,30 @@
+.ONESHELL:
+SHELL = /bin/sh
+.SHELLFLAGS = -ec
+
+BASE_PACKAGE := github.com/jmoiron/sqlx
+
+tooling:
+ go install honnef.co/go/tools/cmd/staticcheck@v0.4.7
+ go install golang.org/x/vuln/cmd/govulncheck@v1.0.4
+ go install golang.org/x/tools/cmd/goimports@v0.20.0
+
+has-changes:
+ git diff --exit-code --quiet HEAD --
+
+lint:
+ go vet ./...
+ staticcheck -checks=all ./...
+
+fmt:
+ go list -f '{{.Dir}}' ./... | xargs -I {} goimports -local $(BASE_PACKAGE) -w {}
+
+vuln-check:
+ govulncheck ./...
+
+test-race:
+ go test -v -race -count=1 ./...
+
+update-dependencies:
+ go get -u -t -v ./...
+ go mod tidy
diff --git a/vendor/github.com/jmoiron/sqlx/README.md b/vendor/github.com/jmoiron/sqlx/README.md
new file mode 100644
index 0000000..5bfd231
--- /dev/null
+++ b/vendor/github.com/jmoiron/sqlx/README.md
@@ -0,0 +1,213 @@
+# sqlx
+
+[![CircleCI](https://dl.circleci.com/status-badge/img/gh/jmoiron/sqlx/tree/master.svg?style=shield)](https://dl.circleci.com/status-badge/redirect/gh/jmoiron/sqlx/tree/master) [![Coverage Status](https://coveralls.io/repos/github/jmoiron/sqlx/badge.svg?branch=master)](https://coveralls.io/github/jmoiron/sqlx?branch=master) [![Godoc](http://img.shields.io/badge/godoc-reference-blue.svg?style=flat)](https://godoc.org/github.com/jmoiron/sqlx) [![license](http://img.shields.io/badge/license-MIT-red.svg?style=flat)](https://raw.githubusercontent.com/jmoiron/sqlx/master/LICENSE)
+
+sqlx is a library which provides a set of extensions on go's standard
+`database/sql` library. The sqlx versions of `sql.DB`, `sql.TX`, `sql.Stmt`,
+et al. all leave the underlying interfaces untouched, so that their interfaces
+are a superset on the standard ones. This makes it relatively painless to
+integrate existing codebases using database/sql with sqlx.
+
+Major additional concepts are:
+
+* Marshal rows into structs (with embedded struct support), maps, and slices
+* Named parameter support including prepared statements
+* `Get` and `Select` to go quickly from query to struct/slice
+
+In addition to the [godoc API documentation](http://godoc.org/github.com/jmoiron/sqlx),
+there is also some [user documentation](http://jmoiron.github.io/sqlx/) that
+explains how to use `database/sql` along with sqlx.
+
+## Recent Changes
+
+1.3.0:
+
+* `sqlx.DB.Connx(context.Context) *sqlx.Conn`
+* `sqlx.BindDriver(driverName, bindType)`
+* support for `[]map[string]interface{}` to do "batch" insertions
+* allocation & perf improvements for `sqlx.In`
+
+DB.Connx returns an `sqlx.Conn`, which is an `sql.Conn`-alike consistent with
+sqlx's wrapping of other types.
+
+`BindDriver` allows users to control the bindvars that sqlx will use for drivers,
+and add new drivers at runtime. This results in a very slight performance hit
+when resolving the driver into a bind type (~40ns per call), but it allows users
+to specify what bindtype their driver uses even when sqlx has not been updated
+to know about it by default.
+
+### Backwards Compatibility
+
+Compatibility with the most recent two versions of Go is a requirement for any
+new changes. Compatibility beyond that is not guaranteed.
+
+Versioning is done with Go modules. Breaking changes (eg. removing deprecated API)
+will get major version number bumps.
+
+## install
+
+ go get github.com/jmoiron/sqlx
+
+## issues
+
+Row headers can be ambiguous (`SELECT 1 AS a, 2 AS a`), and the result of
+`Columns()` does not fully qualify column names in queries like:
+
+```sql
+SELECT a.id, a.name, b.id, b.name FROM foos AS a JOIN foos AS b ON a.parent = b.id;
+```
+
+making a struct or map destination ambiguous. Use `AS` in your queries
+to give columns distinct names, `rows.Scan` to scan them manually, or
+`SliceScan` to get a slice of results.
+
+## usage
+
+Below is an example which shows some common use cases for sqlx. Check
+[sqlx_test.go](https://github.com/jmoiron/sqlx/blob/master/sqlx_test.go) for more
+usage.
+
+
+```go
+package main
+
+import (
+ "database/sql"
+ "fmt"
+ "log"
+
+ _ "github.com/lib/pq"
+ "github.com/jmoiron/sqlx"
+)
+
+var schema = `
+CREATE TABLE person (
+ first_name text,
+ last_name text,
+ email text
+);
+
+CREATE TABLE place (
+ country text,
+ city text NULL,
+ telcode integer
+)`
+
+type Person struct {
+ FirstName string `db:"first_name"`
+ LastName string `db:"last_name"`
+ Email string
+}
+
+type Place struct {
+ Country string
+ City sql.NullString
+ TelCode int
+}
+
+func main() {
+ // this Pings the database trying to connect
+ // use sqlx.Open() for sql.Open() semantics
+ db, err := sqlx.Connect("postgres", "user=foo dbname=bar sslmode=disable")
+ if err != nil {
+ log.Fatalln(err)
+ }
+
+ // exec the schema or fail; multi-statement Exec behavior varies between
+ // database drivers; pq will exec them all, sqlite3 won't, ymmv
+ db.MustExec(schema)
+
+ tx := db.MustBegin()
+ tx.MustExec("INSERT INTO person (first_name, last_name, email) VALUES ($1, $2, $3)", "Jason", "Moiron", "jmoiron@jmoiron.net")
+ tx.MustExec("INSERT INTO person (first_name, last_name, email) VALUES ($1, $2, $3)", "John", "Doe", "johndoeDNE@gmail.net")
+ tx.MustExec("INSERT INTO place (country, city, telcode) VALUES ($1, $2, $3)", "United States", "New York", "1")
+ tx.MustExec("INSERT INTO place (country, telcode) VALUES ($1, $2)", "Hong Kong", "852")
+ tx.MustExec("INSERT INTO place (country, telcode) VALUES ($1, $2)", "Singapore", "65")
+ // Named queries can use structs, so if you have an existing struct (i.e. person := &Person{}) that you have populated, you can pass it in as &person
+ tx.NamedExec("INSERT INTO person (first_name, last_name, email) VALUES (:first_name, :last_name, :email)", &Person{"Jane", "Citizen", "jane.citzen@example.com"})
+ tx.Commit()
+
+ // Query the database, storing results in a []Person (wrapped in []interface{})
+ people := []Person{}
+ db.Select(&people, "SELECT * FROM person ORDER BY first_name ASC")
+ jason, john := people[0], people[1]
+
+ fmt.Printf("%#v\n%#v", jason, john)
+ // Person{FirstName:"Jason", LastName:"Moiron", Email:"jmoiron@jmoiron.net"}
+ // Person{FirstName:"John", LastName:"Doe", Email:"johndoeDNE@gmail.net"}
+
+ // You can also get a single result, a la QueryRow
+ jason = Person{}
+ err = db.Get(&jason, "SELECT * FROM person WHERE first_name=$1", "Jason")
+ fmt.Printf("%#v\n", jason)
+ // Person{FirstName:"Jason", LastName:"Moiron", Email:"jmoiron@jmoiron.net"}
+
+ // if you have null fields and use SELECT *, you must use sql.Null* in your struct
+ places := []Place{}
+ err = db.Select(&places, "SELECT * FROM place ORDER BY telcode ASC")
+ if err != nil {
+ fmt.Println(err)
+ return
+ }
+ usa, singsing, honkers := places[0], places[1], places[2]
+
+ fmt.Printf("%#v\n%#v\n%#v\n", usa, singsing, honkers)
+ // Place{Country:"United States", City:sql.NullString{String:"New York", Valid:true}, TelCode:1}
+ // Place{Country:"Singapore", City:sql.NullString{String:"", Valid:false}, TelCode:65}
+ // Place{Country:"Hong Kong", City:sql.NullString{String:"", Valid:false}, TelCode:852}
+
+ // Loop through rows using only one struct
+ place := Place{}
+ rows, err := db.Queryx("SELECT * FROM place")
+ for rows.Next() {
+ err := rows.StructScan(&place)
+ if err != nil {
+ log.Fatalln(err)
+ }
+ fmt.Printf("%#v\n", place)
+ }
+ // Place{Country:"United States", City:sql.NullString{String:"New York", Valid:true}, TelCode:1}
+ // Place{Country:"Hong Kong", City:sql.NullString{String:"", Valid:false}, TelCode:852}
+ // Place{Country:"Singapore", City:sql.NullString{String:"", Valid:false}, TelCode:65}
+
+ // Named queries, using `:name` as the bindvar. Automatic bindvar support
+ // which takes into account the dbtype based on the driverName on sqlx.Open/Connect
+ _, err = db.NamedExec(`INSERT INTO person (first_name,last_name,email) VALUES (:first,:last,:email)`,
+ map[string]interface{}{
+ "first": "Bin",
+ "last": "Smuth",
+ "email": "bensmith@allblacks.nz",
+ })
+
+ // Selects Mr. Smith from the database
+ rows, err = db.NamedQuery(`SELECT * FROM person WHERE first_name=:fn`, map[string]interface{}{"fn": "Bin"})
+
+ // Named queries can also use structs. Their bind names follow the same rules
+ // as the name -> db mapping, so struct fields are lowercased and the `db` tag
+ // is taken into consideration.
+ rows, err = db.NamedQuery(`SELECT * FROM person WHERE first_name=:first_name`, jason)
+
+
+ // batch insert
+
+ // batch insert with structs
+ personStructs := []Person{
+ {FirstName: "Ardie", LastName: "Savea", Email: "asavea@ab.co.nz"},
+ {FirstName: "Sonny Bill", LastName: "Williams", Email: "sbw@ab.co.nz"},
+ {FirstName: "Ngani", LastName: "Laumape", Email: "nlaumape@ab.co.nz"},
+ }
+
+ _, err = db.NamedExec(`INSERT INTO person (first_name, last_name, email)
+ VALUES (:first_name, :last_name, :email)`, personStructs)
+
+ // batch insert with maps
+ personMaps := []map[string]interface{}{
+ {"first_name": "Ardie", "last_name": "Savea", "email": "asavea@ab.co.nz"},
+ {"first_name": "Sonny Bill", "last_name": "Williams", "email": "sbw@ab.co.nz"},
+ {"first_name": "Ngani", "last_name": "Laumape", "email": "nlaumape@ab.co.nz"},
+ }
+
+ _, err = db.NamedExec(`INSERT INTO person (first_name, last_name, email)
+ VALUES (:first_name, :last_name, :email)`, personMaps)
+}
+```
diff --git a/vendor/github.com/jmoiron/sqlx/bind.go b/vendor/github.com/jmoiron/sqlx/bind.go
new file mode 100644
index 0000000..ec0da4e
--- /dev/null
+++ b/vendor/github.com/jmoiron/sqlx/bind.go
@@ -0,0 +1,265 @@
+package sqlx
+
+import (
+ "bytes"
+ "database/sql/driver"
+ "errors"
+ "reflect"
+ "strconv"
+ "strings"
+ "sync"
+
+ "github.com/jmoiron/sqlx/reflectx"
+)
+
+// Bindvar types supported by Rebind, BindMap and BindStruct.
+const (
+ UNKNOWN = iota
+ QUESTION
+ DOLLAR
+ NAMED
+ AT
+)
+
+var defaultBinds = map[int][]string{
+ DOLLAR: []string{"postgres", "pgx", "pq-timeouts", "cloudsqlpostgres", "ql", "nrpostgres", "cockroach"},
+ QUESTION: []string{"mysql", "sqlite3", "nrmysql", "nrsqlite3"},
+ NAMED: []string{"oci8", "ora", "goracle", "godror"},
+ AT: []string{"sqlserver"},
+}
+
+var binds sync.Map
+
+func init() {
+ for bind, drivers := range defaultBinds {
+ for _, driver := range drivers {
+ BindDriver(driver, bind)
+ }
+ }
+
+}
+
+// BindType returns the bindtype for a given database given a drivername.
+func BindType(driverName string) int {
+ itype, ok := binds.Load(driverName)
+ if !ok {
+ return UNKNOWN
+ }
+ return itype.(int)
+}
+
+// BindDriver sets the BindType for driverName to bindType.
+func BindDriver(driverName string, bindType int) {
+ binds.Store(driverName, bindType)
+}
+
+// FIXME: this should be able to be tolerant of escaped ?'s in queries without
+// losing much speed, and should be to avoid confusion.
+
+// Rebind a query from the default bindtype (QUESTION) to the target bindtype.
+func Rebind(bindType int, query string) string {
+ switch bindType {
+ case QUESTION, UNKNOWN:
+ return query
+ }
+
+ // Add space enough for 10 params before we have to allocate
+ rqb := make([]byte, 0, len(query)+10)
+
+ var i, j int
+
+ for i = strings.Index(query, "?"); i != -1; i = strings.Index(query, "?") {
+ rqb = append(rqb, query[:i]...)
+
+ switch bindType {
+ case DOLLAR:
+ rqb = append(rqb, '$')
+ case NAMED:
+ rqb = append(rqb, ':', 'a', 'r', 'g')
+ case AT:
+ rqb = append(rqb, '@', 'p')
+ }
+
+ j++
+ rqb = strconv.AppendInt(rqb, int64(j), 10)
+
+ query = query[i+1:]
+ }
+
+ return string(append(rqb, query...))
+}
+
+// Experimental implementation of Rebind which uses a bytes.Buffer. The code is
+// much simpler and should be more resistant to odd unicode, but it is twice as
+// slow. Kept here for benchmarking purposes and to possibly replace Rebind if
+// problems arise with its somewhat naive handling of unicode.
+func rebindBuff(bindType int, query string) string {
+ if bindType != DOLLAR {
+ return query
+ }
+
+ b := make([]byte, 0, len(query))
+ rqb := bytes.NewBuffer(b)
+ j := 1
+ for _, r := range query {
+ if r == '?' {
+ rqb.WriteRune('$')
+ rqb.WriteString(strconv.Itoa(j))
+ j++
+ } else {
+ rqb.WriteRune(r)
+ }
+ }
+
+ return rqb.String()
+}
+
+func asSliceForIn(i interface{}) (v reflect.Value, ok bool) {
+ if i == nil {
+ return reflect.Value{}, false
+ }
+
+ v = reflect.ValueOf(i)
+ t := reflectx.Deref(v.Type())
+
+ // Only expand slices
+ if t.Kind() != reflect.Slice {
+ return reflect.Value{}, false
+ }
+
+ // []byte is a driver.Value type so it should not be expanded
+ if t == reflect.TypeOf([]byte{}) {
+ return reflect.Value{}, false
+
+ }
+
+ return v, true
+}
+
+// In expands slice values in args, returning the modified query string
+// and a new arg list that can be executed by a database. The `query` should
+// use the `?` bindVar. The return value uses the `?` bindVar.
+func In(query string, args ...interface{}) (string, []interface{}, error) {
+ // argMeta stores reflect.Value and length for slices and
+ // the value itself for non-slice arguments
+ type argMeta struct {
+ v reflect.Value
+ i interface{}
+ length int
+ }
+
+ var flatArgsCount int
+ var anySlices bool
+
+ var stackMeta [32]argMeta
+
+ var meta []argMeta
+ if len(args) <= len(stackMeta) {
+ meta = stackMeta[:len(args)]
+ } else {
+ meta = make([]argMeta, len(args))
+ }
+
+ for i, arg := range args {
+ if a, ok := arg.(driver.Valuer); ok {
+ var err error
+ arg, err = a.Value()
+ if err != nil {
+ return "", nil, err
+ }
+ }
+
+ if v, ok := asSliceForIn(arg); ok {
+ meta[i].length = v.Len()
+ meta[i].v = v
+
+ anySlices = true
+ flatArgsCount += meta[i].length
+
+ if meta[i].length == 0 {
+ return "", nil, errors.New("empty slice passed to 'in' query")
+ }
+ } else {
+ meta[i].i = arg
+ flatArgsCount++
+ }
+ }
+
+ // don't do any parsing if there aren't any slices; note that this means
+ // some errors that we might have caught below will not be returned.
+ if !anySlices {
+ return query, args, nil
+ }
+
+ newArgs := make([]interface{}, 0, flatArgsCount)
+
+ var buf strings.Builder
+ buf.Grow(len(query) + len(", ?")*flatArgsCount)
+
+ var arg, offset int
+
+ for i := strings.IndexByte(query[offset:], '?'); i != -1; i = strings.IndexByte(query[offset:], '?') {
+ if arg >= len(meta) {
+ // if an argument wasn't passed, lets return an error; this is
+ // not actually how database/sql Exec/Query works, but since we are
+ // creating an argument list programmatically, we want to be able
+ // to catch these programmer errors earlier.
+ return "", nil, errors.New("number of bindVars exceeds arguments")
+ }
+
+ argMeta := meta[arg]
+ arg++
+
+ // not a slice, continue.
+ // our questionmark will either be written before the next expansion
+ // of a slice or after the loop when writing the rest of the query
+ if argMeta.length == 0 {
+ offset = offset + i + 1
+ newArgs = append(newArgs, argMeta.i)
+ continue
+ }
+
+ // write everything up to and including our ? character
+ buf.WriteString(query[:offset+i+1])
+
+ for si := 1; si < argMeta.length; si++ {
+ buf.WriteString(", ?")
+ }
+
+ newArgs = appendReflectSlice(newArgs, argMeta.v, argMeta.length)
+
+ // slice the query and reset the offset. this avoids some bookkeeping for
+ // the write after the loop
+ query = query[offset+i+1:]
+ offset = 0
+ }
+
+ buf.WriteString(query)
+
+ if arg < len(meta) {
+ return "", nil, errors.New("number of bindVars less than number arguments")
+ }
+
+ return buf.String(), newArgs, nil
+}
+
+func appendReflectSlice(args []interface{}, v reflect.Value, vlen int) []interface{} {
+ switch val := v.Interface().(type) {
+ case []interface{}:
+ args = append(args, val...)
+ case []int:
+ for i := range val {
+ args = append(args, val[i])
+ }
+ case []string:
+ for i := range val {
+ args = append(args, val[i])
+ }
+ default:
+ for si := 0; si < vlen; si++ {
+ args = append(args, v.Index(si).Interface())
+ }
+ }
+
+ return args
+}
diff --git a/vendor/github.com/jmoiron/sqlx/doc.go b/vendor/github.com/jmoiron/sqlx/doc.go
new file mode 100644
index 0000000..b801041
--- /dev/null
+++ b/vendor/github.com/jmoiron/sqlx/doc.go
@@ -0,0 +1,11 @@
+// Package sqlx provides general purpose extensions to database/sql.
+//
+// It is intended to seamlessly wrap database/sql and provide convenience
+// methods which are useful in the development of database driven applications.
+// None of the underlying database/sql methods are changed. Instead all extended
+// behavior is implemented through new methods defined on wrapper types.
+//
+// Additions include scanning into structs, named query support, rebinding
+// queries for different drivers, convenient shorthands for common error handling
+// and more.
+package sqlx
diff --git a/vendor/github.com/jmoiron/sqlx/named.go b/vendor/github.com/jmoiron/sqlx/named.go
new file mode 100644
index 0000000..6ac4477
--- /dev/null
+++ b/vendor/github.com/jmoiron/sqlx/named.go
@@ -0,0 +1,458 @@
+package sqlx
+
+// Named Query Support
+//
+// * BindMap - bind query bindvars to map/struct args
+// * NamedExec, NamedQuery - named query w/ struct or map
+// * NamedStmt - a pre-compiled named query which is a prepared statement
+//
+// Internal Interfaces:
+//
+// * compileNamedQuery - rebind a named query, returning a query and list of names
+// * bindArgs, bindMapArgs, bindAnyArgs - given a list of names, return an arglist
+//
+import (
+ "bytes"
+ "database/sql"
+ "errors"
+ "fmt"
+ "reflect"
+ "regexp"
+ "strconv"
+ "unicode"
+
+ "github.com/jmoiron/sqlx/reflectx"
+)
+
+// NamedStmt is a prepared statement that executes named queries. Prepare it
+// how you would execute a NamedQuery, but pass in a struct or map when executing.
+type NamedStmt struct {
+ Params []string
+ QueryString string
+ Stmt *Stmt
+}
+
+// Close closes the named statement.
+func (n *NamedStmt) Close() error {
+ return n.Stmt.Close()
+}
+
+// Exec executes a named statement using the struct passed.
+// Any named placeholder parameters are replaced with fields from arg.
+func (n *NamedStmt) Exec(arg interface{}) (sql.Result, error) {
+ args, err := bindAnyArgs(n.Params, arg, n.Stmt.Mapper)
+ if err != nil {
+ return *new(sql.Result), err
+ }
+ return n.Stmt.Exec(args...)
+}
+
+// Query executes a named statement using the struct argument, returning rows.
+// Any named placeholder parameters are replaced with fields from arg.
+func (n *NamedStmt) Query(arg interface{}) (*sql.Rows, error) {
+ args, err := bindAnyArgs(n.Params, arg, n.Stmt.Mapper)
+ if err != nil {
+ return nil, err
+ }
+ return n.Stmt.Query(args...)
+}
+
+// QueryRow executes a named statement against the database. Because sqlx cannot
+// create a *sql.Row with an error condition pre-set for binding errors, sqlx
+// returns a *sqlx.Row instead.
+// Any named placeholder parameters are replaced with fields from arg.
+func (n *NamedStmt) QueryRow(arg interface{}) *Row {
+ args, err := bindAnyArgs(n.Params, arg, n.Stmt.Mapper)
+ if err != nil {
+ return &Row{err: err}
+ }
+ return n.Stmt.QueryRowx(args...)
+}
+
+// MustExec execs a NamedStmt, panicing on error
+// Any named placeholder parameters are replaced with fields from arg.
+func (n *NamedStmt) MustExec(arg interface{}) sql.Result {
+ res, err := n.Exec(arg)
+ if err != nil {
+ panic(err)
+ }
+ return res
+}
+
+// Queryx using this NamedStmt
+// Any named placeholder parameters are replaced with fields from arg.
+func (n *NamedStmt) Queryx(arg interface{}) (*Rows, error) {
+ r, err := n.Query(arg)
+ if err != nil {
+ return nil, err
+ }
+ return &Rows{Rows: r, Mapper: n.Stmt.Mapper, unsafe: isUnsafe(n)}, err
+}
+
+// QueryRowx this NamedStmt. Because of limitations with QueryRow, this is
+// an alias for QueryRow.
+// Any named placeholder parameters are replaced with fields from arg.
+func (n *NamedStmt) QueryRowx(arg interface{}) *Row {
+ return n.QueryRow(arg)
+}
+
+// Select using this NamedStmt
+// Any named placeholder parameters are replaced with fields from arg.
+func (n *NamedStmt) Select(dest interface{}, arg interface{}) error {
+ rows, err := n.Queryx(arg)
+ if err != nil {
+ return err
+ }
+ // if something happens here, we want to make sure the rows are Closed
+ defer rows.Close()
+ return scanAll(rows, dest, false)
+}
+
+// Get using this NamedStmt
+// Any named placeholder parameters are replaced with fields from arg.
+func (n *NamedStmt) Get(dest interface{}, arg interface{}) error {
+ r := n.QueryRowx(arg)
+ return r.scanAny(dest, false)
+}
+
+// Unsafe creates an unsafe version of the NamedStmt
+func (n *NamedStmt) Unsafe() *NamedStmt {
+ r := &NamedStmt{Params: n.Params, Stmt: n.Stmt, QueryString: n.QueryString}
+ r.Stmt.unsafe = true
+ return r
+}
+
+// A union interface of preparer and binder, required to be able to prepare
+// named statements (as the bindtype must be determined).
+type namedPreparer interface {
+ Preparer
+ binder
+}
+
+func prepareNamed(p namedPreparer, query string) (*NamedStmt, error) {
+ bindType := BindType(p.DriverName())
+ q, args, err := compileNamedQuery([]byte(query), bindType)
+ if err != nil {
+ return nil, err
+ }
+ stmt, err := Preparex(p, q)
+ if err != nil {
+ return nil, err
+ }
+ return &NamedStmt{
+ QueryString: q,
+ Params: args,
+ Stmt: stmt,
+ }, nil
+}
+
+// convertMapStringInterface attempts to convert v to map[string]interface{}.
+// Unlike v.(map[string]interface{}), this function works on named types that
+// are convertible to map[string]interface{} as well.
+func convertMapStringInterface(v interface{}) (map[string]interface{}, bool) {
+ var m map[string]interface{}
+ mtype := reflect.TypeOf(m)
+ t := reflect.TypeOf(v)
+ if !t.ConvertibleTo(mtype) {
+ return nil, false
+ }
+ return reflect.ValueOf(v).Convert(mtype).Interface().(map[string]interface{}), true
+
+}
+
+func bindAnyArgs(names []string, arg interface{}, m *reflectx.Mapper) ([]interface{}, error) {
+ if maparg, ok := convertMapStringInterface(arg); ok {
+ return bindMapArgs(names, maparg)
+ }
+ return bindArgs(names, arg, m)
+}
+
+// private interface to generate a list of interfaces from a given struct
+// type, given a list of names to pull out of the struct. Used by public
+// BindStruct interface.
+func bindArgs(names []string, arg interface{}, m *reflectx.Mapper) ([]interface{}, error) {
+ arglist := make([]interface{}, 0, len(names))
+
+ // grab the indirected value of arg
+ var v reflect.Value
+ for v = reflect.ValueOf(arg); v.Kind() == reflect.Ptr; {
+ v = v.Elem()
+ }
+
+ err := m.TraversalsByNameFunc(v.Type(), names, func(i int, t []int) error {
+ if len(t) == 0 {
+ return fmt.Errorf("could not find name %s in %#v", names[i], arg)
+ }
+
+ val := reflectx.FieldByIndexesReadOnly(v, t)
+ arglist = append(arglist, val.Interface())
+
+ return nil
+ })
+
+ return arglist, err
+}
+
+// like bindArgs, but for maps.
+func bindMapArgs(names []string, arg map[string]interface{}) ([]interface{}, error) {
+ arglist := make([]interface{}, 0, len(names))
+
+ for _, name := range names {
+ val, ok := arg[name]
+ if !ok {
+ return arglist, fmt.Errorf("could not find name %s in %#v", name, arg)
+ }
+ arglist = append(arglist, val)
+ }
+ return arglist, nil
+}
+
+// bindStruct binds a named parameter query with fields from a struct argument.
+// The rules for binding field names to parameter names follow the same
+// conventions as for StructScan, including obeying the `db` struct tags.
+func bindStruct(bindType int, query string, arg interface{}, m *reflectx.Mapper) (string, []interface{}, error) {
+ bound, names, err := compileNamedQuery([]byte(query), bindType)
+ if err != nil {
+ return "", []interface{}{}, err
+ }
+
+ arglist, err := bindAnyArgs(names, arg, m)
+ if err != nil {
+ return "", []interface{}{}, err
+ }
+
+ return bound, arglist, nil
+}
+
+var valuesReg = regexp.MustCompile(`\)\s*(?i)VALUES\s*\(`)
+
+func findMatchingClosingBracketIndex(s string) int {
+ count := 0
+ for i, ch := range s {
+ if ch == '(' {
+ count++
+ }
+ if ch == ')' {
+ count--
+ if count == 0 {
+ return i
+ }
+ }
+ }
+ return 0
+}
+
+func fixBound(bound string, loop int) string {
+ loc := valuesReg.FindStringIndex(bound)
+ // defensive guard when "VALUES (...)" not found
+ if len(loc) < 2 {
+ return bound
+ }
+
+ openingBracketIndex := loc[1] - 1
+ index := findMatchingClosingBracketIndex(bound[openingBracketIndex:])
+ // defensive guard. must have closing bracket
+ if index == 0 {
+ return bound
+ }
+ closingBracketIndex := openingBracketIndex + index + 1
+
+ var buffer bytes.Buffer
+
+ buffer.WriteString(bound[0:closingBracketIndex])
+ for i := 0; i < loop-1; i++ {
+ buffer.WriteString(",")
+ buffer.WriteString(bound[openingBracketIndex:closingBracketIndex])
+ }
+ buffer.WriteString(bound[closingBracketIndex:])
+ return buffer.String()
+}
+
+// bindArray binds a named parameter query with fields from an array or slice of
+// structs argument.
+func bindArray(bindType int, query string, arg interface{}, m *reflectx.Mapper) (string, []interface{}, error) {
+ // do the initial binding with QUESTION; if bindType is not question,
+ // we can rebind it at the end.
+ bound, names, err := compileNamedQuery([]byte(query), QUESTION)
+ if err != nil {
+ return "", []interface{}{}, err
+ }
+ arrayValue := reflect.ValueOf(arg)
+ arrayLen := arrayValue.Len()
+ if arrayLen == 0 {
+ return "", []interface{}{}, fmt.Errorf("length of array is 0: %#v", arg)
+ }
+ var arglist = make([]interface{}, 0, len(names)*arrayLen)
+ for i := 0; i < arrayLen; i++ {
+ elemArglist, err := bindAnyArgs(names, arrayValue.Index(i).Interface(), m)
+ if err != nil {
+ return "", []interface{}{}, err
+ }
+ arglist = append(arglist, elemArglist...)
+ }
+ if arrayLen > 1 {
+ bound = fixBound(bound, arrayLen)
+ }
+ // adjust binding type if we weren't on question
+ if bindType != QUESTION {
+ bound = Rebind(bindType, bound)
+ }
+ return bound, arglist, nil
+}
+
+// bindMap binds a named parameter query with a map of arguments.
+func bindMap(bindType int, query string, args map[string]interface{}) (string, []interface{}, error) {
+ bound, names, err := compileNamedQuery([]byte(query), bindType)
+ if err != nil {
+ return "", []interface{}{}, err
+ }
+
+ arglist, err := bindMapArgs(names, args)
+ return bound, arglist, err
+}
+
+// -- Compilation of Named Queries
+
+// Allow digits and letters in bind params; additionally runes are
+// checked against underscores, meaning that bind params can have be
+// alphanumeric with underscores. Mind the difference between unicode
+// digits and numbers, where '5' is a digit but '五' is not.
+var allowedBindRunes = []*unicode.RangeTable{unicode.Letter, unicode.Digit}
+
+// FIXME: this function isn't safe for unicode named params, as a failing test
+// can testify. This is not a regression but a failure of the original code
+// as well. It should be modified to range over runes in a string rather than
+// bytes, even though this is less convenient and slower. Hopefully the
+// addition of the prepared NamedStmt (which will only do this once) will make
+// up for the slightly slower ad-hoc NamedExec/NamedQuery.
+
+// compile a NamedQuery into an unbound query (using the '?' bindvar) and
+// a list of names.
+func compileNamedQuery(qs []byte, bindType int) (query string, names []string, err error) {
+ names = make([]string, 0, 10)
+ rebound := make([]byte, 0, len(qs))
+
+ inName := false
+ last := len(qs) - 1
+ currentVar := 1
+ name := make([]byte, 0, 10)
+
+ for i, b := range qs {
+ // a ':' while we're in a name is an error
+ if b == ':' {
+ // if this is the second ':' in a '::' escape sequence, append a ':'
+ if inName && i > 0 && qs[i-1] == ':' {
+ rebound = append(rebound, ':')
+ inName = false
+ continue
+ } else if inName {
+ err = errors.New("unexpected `:` while reading named param at " + strconv.Itoa(i))
+ return query, names, err
+ }
+ inName = true
+ name = []byte{}
+ } else if inName && i > 0 && b == '=' && len(name) == 0 {
+ rebound = append(rebound, ':', '=')
+ inName = false
+ continue
+ // if we're in a name, and this is an allowed character, continue
+ } else if inName && (unicode.IsOneOf(allowedBindRunes, rune(b)) || b == '_' || b == '.') && i != last {
+ // append the byte to the name if we are in a name and not on the last byte
+ name = append(name, b)
+ // if we're in a name and it's not an allowed character, the name is done
+ } else if inName {
+ inName = false
+ // if this is the final byte of the string and it is part of the name, then
+ // make sure to add it to the name
+ if i == last && unicode.IsOneOf(allowedBindRunes, rune(b)) {
+ name = append(name, b)
+ }
+ // add the string representation to the names list
+ names = append(names, string(name))
+ // add a proper bindvar for the bindType
+ switch bindType {
+ // oracle only supports named type bind vars even for positional
+ case NAMED:
+ rebound = append(rebound, ':')
+ rebound = append(rebound, name...)
+ case QUESTION, UNKNOWN:
+ rebound = append(rebound, '?')
+ case DOLLAR:
+ rebound = append(rebound, '$')
+ for _, b := range strconv.Itoa(currentVar) {
+ rebound = append(rebound, byte(b))
+ }
+ currentVar++
+ case AT:
+ rebound = append(rebound, '@', 'p')
+ for _, b := range strconv.Itoa(currentVar) {
+ rebound = append(rebound, byte(b))
+ }
+ currentVar++
+ }
+ // add this byte to string unless it was not part of the name
+ if i != last {
+ rebound = append(rebound, b)
+ } else if !unicode.IsOneOf(allowedBindRunes, rune(b)) {
+ rebound = append(rebound, b)
+ }
+ } else {
+ // this is a normal byte and should just go onto the rebound query
+ rebound = append(rebound, b)
+ }
+ }
+
+ return string(rebound), names, err
+}
+
+// BindNamed binds a struct or a map to a query with named parameters.
+// DEPRECATED: use sqlx.Named` instead of this, it may be removed in future.
+func BindNamed(bindType int, query string, arg interface{}) (string, []interface{}, error) {
+ return bindNamedMapper(bindType, query, arg, mapper())
+}
+
+// Named takes a query using named parameters and an argument and
+// returns a new query with a list of args that can be executed by
+// a database. The return value uses the `?` bindvar.
+func Named(query string, arg interface{}) (string, []interface{}, error) {
+ return bindNamedMapper(QUESTION, query, arg, mapper())
+}
+
+func bindNamedMapper(bindType int, query string, arg interface{}, m *reflectx.Mapper) (string, []interface{}, error) {
+ t := reflect.TypeOf(arg)
+ k := t.Kind()
+ switch {
+ case k == reflect.Map && t.Key().Kind() == reflect.String:
+ m, ok := convertMapStringInterface(arg)
+ if !ok {
+ return "", nil, fmt.Errorf("sqlx.bindNamedMapper: unsupported map type: %T", arg)
+ }
+ return bindMap(bindType, query, m)
+ case k == reflect.Array || k == reflect.Slice:
+ return bindArray(bindType, query, arg, m)
+ default:
+ return bindStruct(bindType, query, arg, m)
+ }
+}
+
+// NamedQuery binds a named query and then runs Query on the result using the
+// provided Ext (sqlx.Tx, sqlx.Db). It works with both structs and with
+// map[string]interface{} types.
+func NamedQuery(e Ext, query string, arg interface{}) (*Rows, error) {
+ q, args, err := bindNamedMapper(BindType(e.DriverName()), query, arg, mapperFor(e))
+ if err != nil {
+ return nil, err
+ }
+ return e.Queryx(q, args...)
+}
+
+// NamedExec uses BindStruct to get a query executable by the driver and
+// then runs Exec on the result. Returns an error from the binding
+// or the query execution itself.
+func NamedExec(e Ext, query string, arg interface{}) (sql.Result, error) {
+ q, args, err := bindNamedMapper(BindType(e.DriverName()), query, arg, mapperFor(e))
+ if err != nil {
+ return nil, err
+ }
+ return e.Exec(q, args...)
+}
diff --git a/vendor/github.com/jmoiron/sqlx/named_context.go b/vendor/github.com/jmoiron/sqlx/named_context.go
new file mode 100644
index 0000000..9ad23f4
--- /dev/null
+++ b/vendor/github.com/jmoiron/sqlx/named_context.go
@@ -0,0 +1,133 @@
+//go:build go1.8
+// +build go1.8
+
+package sqlx
+
+import (
+ "context"
+ "database/sql"
+)
+
+// A union interface of contextPreparer and binder, required to be able to
+// prepare named statements with context (as the bindtype must be determined).
+type namedPreparerContext interface {
+ PreparerContext
+ binder
+}
+
+func prepareNamedContext(ctx context.Context, p namedPreparerContext, query string) (*NamedStmt, error) {
+ bindType := BindType(p.DriverName())
+ q, args, err := compileNamedQuery([]byte(query), bindType)
+ if err != nil {
+ return nil, err
+ }
+ stmt, err := PreparexContext(ctx, p, q)
+ if err != nil {
+ return nil, err
+ }
+ return &NamedStmt{
+ QueryString: q,
+ Params: args,
+ Stmt: stmt,
+ }, nil
+}
+
+// ExecContext executes a named statement using the struct passed.
+// Any named placeholder parameters are replaced with fields from arg.
+func (n *NamedStmt) ExecContext(ctx context.Context, arg interface{}) (sql.Result, error) {
+ args, err := bindAnyArgs(n.Params, arg, n.Stmt.Mapper)
+ if err != nil {
+ return *new(sql.Result), err
+ }
+ return n.Stmt.ExecContext(ctx, args...)
+}
+
+// QueryContext executes a named statement using the struct argument, returning rows.
+// Any named placeholder parameters are replaced with fields from arg.
+func (n *NamedStmt) QueryContext(ctx context.Context, arg interface{}) (*sql.Rows, error) {
+ args, err := bindAnyArgs(n.Params, arg, n.Stmt.Mapper)
+ if err != nil {
+ return nil, err
+ }
+ return n.Stmt.QueryContext(ctx, args...)
+}
+
+// QueryRowContext executes a named statement against the database. Because sqlx cannot
+// create a *sql.Row with an error condition pre-set for binding errors, sqlx
+// returns a *sqlx.Row instead.
+// Any named placeholder parameters are replaced with fields from arg.
+func (n *NamedStmt) QueryRowContext(ctx context.Context, arg interface{}) *Row {
+ args, err := bindAnyArgs(n.Params, arg, n.Stmt.Mapper)
+ if err != nil {
+ return &Row{err: err}
+ }
+ return n.Stmt.QueryRowxContext(ctx, args...)
+}
+
+// MustExecContext execs a NamedStmt, panicing on error
+// Any named placeholder parameters are replaced with fields from arg.
+func (n *NamedStmt) MustExecContext(ctx context.Context, arg interface{}) sql.Result {
+ res, err := n.ExecContext(ctx, arg)
+ if err != nil {
+ panic(err)
+ }
+ return res
+}
+
+// QueryxContext using this NamedStmt
+// Any named placeholder parameters are replaced with fields from arg.
+func (n *NamedStmt) QueryxContext(ctx context.Context, arg interface{}) (*Rows, error) {
+ r, err := n.QueryContext(ctx, arg)
+ if err != nil {
+ return nil, err
+ }
+ return &Rows{Rows: r, Mapper: n.Stmt.Mapper, unsafe: isUnsafe(n)}, err
+}
+
+// QueryRowxContext this NamedStmt. Because of limitations with QueryRow, this is
+// an alias for QueryRow.
+// Any named placeholder parameters are replaced with fields from arg.
+func (n *NamedStmt) QueryRowxContext(ctx context.Context, arg interface{}) *Row {
+ return n.QueryRowContext(ctx, arg)
+}
+
+// SelectContext using this NamedStmt
+// Any named placeholder parameters are replaced with fields from arg.
+func (n *NamedStmt) SelectContext(ctx context.Context, dest interface{}, arg interface{}) error {
+ rows, err := n.QueryxContext(ctx, arg)
+ if err != nil {
+ return err
+ }
+ // if something happens here, we want to make sure the rows are Closed
+ defer rows.Close()
+ return scanAll(rows, dest, false)
+}
+
+// GetContext using this NamedStmt
+// Any named placeholder parameters are replaced with fields from arg.
+func (n *NamedStmt) GetContext(ctx context.Context, dest interface{}, arg interface{}) error {
+ r := n.QueryRowxContext(ctx, arg)
+ return r.scanAny(dest, false)
+}
+
+// NamedQueryContext binds a named query and then runs Query on the result using the
+// provided Ext (sqlx.Tx, sqlx.Db). It works with both structs and with
+// map[string]interface{} types.
+func NamedQueryContext(ctx context.Context, e ExtContext, query string, arg interface{}) (*Rows, error) {
+ q, args, err := bindNamedMapper(BindType(e.DriverName()), query, arg, mapperFor(e))
+ if err != nil {
+ return nil, err
+ }
+ return e.QueryxContext(ctx, q, args...)
+}
+
+// NamedExecContext uses BindStruct to get a query executable by the driver and
+// then runs Exec on the result. Returns an error from the binding
+// or the query execution itself.
+func NamedExecContext(ctx context.Context, e ExtContext, query string, arg interface{}) (sql.Result, error) {
+ q, args, err := bindNamedMapper(BindType(e.DriverName()), query, arg, mapperFor(e))
+ if err != nil {
+ return nil, err
+ }
+ return e.ExecContext(ctx, q, args...)
+}
diff --git a/vendor/github.com/jmoiron/sqlx/reflectx/README.md b/vendor/github.com/jmoiron/sqlx/reflectx/README.md
new file mode 100644
index 0000000..f01d3d1
--- /dev/null
+++ b/vendor/github.com/jmoiron/sqlx/reflectx/README.md
@@ -0,0 +1,17 @@
+# reflectx
+
+The sqlx package has special reflect needs. In particular, it needs to:
+
+* be able to map a name to a field
+* understand embedded structs
+* understand mapping names to fields by a particular tag
+* user specified name -> field mapping functions
+
+These behaviors mimic the behaviors by the standard library marshallers and also the
+behavior of standard Go accessors.
+
+The first two are amply taken care of by `Reflect.Value.FieldByName`, and the third is
+addressed by `Reflect.Value.FieldByNameFunc`, but these don't quite understand struct
+tags in the ways that are vital to most marshallers, and they are slow.
+
+This reflectx package extends reflect to achieve these goals.
diff --git a/vendor/github.com/jmoiron/sqlx/reflectx/reflect.go b/vendor/github.com/jmoiron/sqlx/reflectx/reflect.go
new file mode 100644
index 0000000..8ec6a13
--- /dev/null
+++ b/vendor/github.com/jmoiron/sqlx/reflectx/reflect.go
@@ -0,0 +1,443 @@
+// Package reflectx implements extensions to the standard reflect lib suitable
+// for implementing marshalling and unmarshalling packages. The main Mapper type
+// allows for Go-compatible named attribute access, including accessing embedded
+// struct attributes and the ability to use functions and struct tags to
+// customize field names.
+package reflectx
+
+import (
+ "reflect"
+ "runtime"
+ "strings"
+ "sync"
+)
+
+// A FieldInfo is metadata for a struct field.
+type FieldInfo struct {
+ Index []int
+ Path string
+ Field reflect.StructField
+ Zero reflect.Value
+ Name string
+ Options map[string]string
+ Embedded bool
+ Children []*FieldInfo
+ Parent *FieldInfo
+}
+
+// A StructMap is an index of field metadata for a struct.
+type StructMap struct {
+ Tree *FieldInfo
+ Index []*FieldInfo
+ Paths map[string]*FieldInfo
+ Names map[string]*FieldInfo
+}
+
+// GetByPath returns a *FieldInfo for a given string path.
+func (f StructMap) GetByPath(path string) *FieldInfo {
+ return f.Paths[path]
+}
+
+// GetByTraversal returns a *FieldInfo for a given integer path. It is
+// analogous to reflect.FieldByIndex, but using the cached traversal
+// rather than re-executing the reflect machinery each time.
+func (f StructMap) GetByTraversal(index []int) *FieldInfo {
+ if len(index) == 0 {
+ return nil
+ }
+
+ tree := f.Tree
+ for _, i := range index {
+ if i >= len(tree.Children) || tree.Children[i] == nil {
+ return nil
+ }
+ tree = tree.Children[i]
+ }
+ return tree
+}
+
+// Mapper is a general purpose mapper of names to struct fields. A Mapper
+// behaves like most marshallers in the standard library, obeying a field tag
+// for name mapping but also providing a basic transform function.
+type Mapper struct {
+ cache map[reflect.Type]*StructMap
+ tagName string
+ tagMapFunc func(string) string
+ mapFunc func(string) string
+ mutex sync.Mutex
+}
+
+// NewMapper returns a new mapper using the tagName as its struct field tag.
+// If tagName is the empty string, it is ignored.
+func NewMapper(tagName string) *Mapper {
+ return &Mapper{
+ cache: make(map[reflect.Type]*StructMap),
+ tagName: tagName,
+ }
+}
+
+// NewMapperTagFunc returns a new mapper which contains a mapper for field names
+// AND a mapper for tag values. This is useful for tags like json which can
+// have values like "name,omitempty".
+func NewMapperTagFunc(tagName string, mapFunc, tagMapFunc func(string) string) *Mapper {
+ return &Mapper{
+ cache: make(map[reflect.Type]*StructMap),
+ tagName: tagName,
+ mapFunc: mapFunc,
+ tagMapFunc: tagMapFunc,
+ }
+}
+
+// NewMapperFunc returns a new mapper which optionally obeys a field tag and
+// a struct field name mapper func given by f. Tags will take precedence, but
+// for any other field, the mapped name will be f(field.Name)
+func NewMapperFunc(tagName string, f func(string) string) *Mapper {
+ return &Mapper{
+ cache: make(map[reflect.Type]*StructMap),
+ tagName: tagName,
+ mapFunc: f,
+ }
+}
+
+// TypeMap returns a mapping of field strings to int slices representing
+// the traversal down the struct to reach the field.
+func (m *Mapper) TypeMap(t reflect.Type) *StructMap {
+ m.mutex.Lock()
+ mapping, ok := m.cache[t]
+ if !ok {
+ mapping = getMapping(t, m.tagName, m.mapFunc, m.tagMapFunc)
+ m.cache[t] = mapping
+ }
+ m.mutex.Unlock()
+ return mapping
+}
+
+// FieldMap returns the mapper's mapping of field names to reflect values. Panics
+// if v's Kind is not Struct, or v is not Indirectable to a struct kind.
+func (m *Mapper) FieldMap(v reflect.Value) map[string]reflect.Value {
+ v = reflect.Indirect(v)
+ mustBe(v, reflect.Struct)
+
+ r := map[string]reflect.Value{}
+ tm := m.TypeMap(v.Type())
+ for tagName, fi := range tm.Names {
+ r[tagName] = FieldByIndexes(v, fi.Index)
+ }
+ return r
+}
+
+// FieldByName returns a field by its mapped name as a reflect.Value.
+// Panics if v's Kind is not Struct or v is not Indirectable to a struct Kind.
+// Returns zero Value if the name is not found.
+func (m *Mapper) FieldByName(v reflect.Value, name string) reflect.Value {
+ v = reflect.Indirect(v)
+ mustBe(v, reflect.Struct)
+
+ tm := m.TypeMap(v.Type())
+ fi, ok := tm.Names[name]
+ if !ok {
+ return v
+ }
+ return FieldByIndexes(v, fi.Index)
+}
+
+// FieldsByName returns a slice of values corresponding to the slice of names
+// for the value. Panics if v's Kind is not Struct or v is not Indirectable
+// to a struct Kind. Returns zero Value for each name not found.
+func (m *Mapper) FieldsByName(v reflect.Value, names []string) []reflect.Value {
+ v = reflect.Indirect(v)
+ mustBe(v, reflect.Struct)
+
+ tm := m.TypeMap(v.Type())
+ vals := make([]reflect.Value, 0, len(names))
+ for _, name := range names {
+ fi, ok := tm.Names[name]
+ if !ok {
+ vals = append(vals, *new(reflect.Value))
+ } else {
+ vals = append(vals, FieldByIndexes(v, fi.Index))
+ }
+ }
+ return vals
+}
+
+// TraversalsByName returns a slice of int slices which represent the struct
+// traversals for each mapped name. Panics if t is not a struct or Indirectable
+// to a struct. Returns empty int slice for each name not found.
+func (m *Mapper) TraversalsByName(t reflect.Type, names []string) [][]int {
+ r := make([][]int, 0, len(names))
+ m.TraversalsByNameFunc(t, names, func(_ int, i []int) error {
+ if i == nil {
+ r = append(r, []int{})
+ } else {
+ r = append(r, i)
+ }
+
+ return nil
+ })
+ return r
+}
+
+// TraversalsByNameFunc traverses the mapped names and calls fn with the index of
+// each name and the struct traversal represented by that name. Panics if t is not
+// a struct or Indirectable to a struct. Returns the first error returned by fn or nil.
+func (m *Mapper) TraversalsByNameFunc(t reflect.Type, names []string, fn func(int, []int) error) error {
+ t = Deref(t)
+ mustBe(t, reflect.Struct)
+ tm := m.TypeMap(t)
+ for i, name := range names {
+ fi, ok := tm.Names[name]
+ if !ok {
+ if err := fn(i, nil); err != nil {
+ return err
+ }
+ } else {
+ if err := fn(i, fi.Index); err != nil {
+ return err
+ }
+ }
+ }
+ return nil
+}
+
+// FieldByIndexes returns a value for the field given by the struct traversal
+// for the given value.
+func FieldByIndexes(v reflect.Value, indexes []int) reflect.Value {
+ for _, i := range indexes {
+ v = reflect.Indirect(v).Field(i)
+ // if this is a pointer and it's nil, allocate a new value and set it
+ if v.Kind() == reflect.Ptr && v.IsNil() {
+ alloc := reflect.New(Deref(v.Type()))
+ v.Set(alloc)
+ }
+ if v.Kind() == reflect.Map && v.IsNil() {
+ v.Set(reflect.MakeMap(v.Type()))
+ }
+ }
+ return v
+}
+
+// FieldByIndexesReadOnly returns a value for a particular struct traversal,
+// but is not concerned with allocating nil pointers because the value is
+// going to be used for reading and not setting.
+func FieldByIndexesReadOnly(v reflect.Value, indexes []int) reflect.Value {
+ for _, i := range indexes {
+ v = reflect.Indirect(v).Field(i)
+ }
+ return v
+}
+
+// Deref is Indirect for reflect.Types
+func Deref(t reflect.Type) reflect.Type {
+ if t.Kind() == reflect.Ptr {
+ t = t.Elem()
+ }
+ return t
+}
+
+// -- helpers & utilities --
+
+type kinder interface {
+ Kind() reflect.Kind
+}
+
+// mustBe checks a value against a kind, panicing with a reflect.ValueError
+// if the kind isn't that which is required.
+func mustBe(v kinder, expected reflect.Kind) {
+ if k := v.Kind(); k != expected {
+ panic(&reflect.ValueError{Method: methodName(), Kind: k})
+ }
+}
+
+// methodName returns the caller of the function calling methodName
+func methodName() string {
+ pc, _, _, _ := runtime.Caller(2)
+ f := runtime.FuncForPC(pc)
+ if f == nil {
+ return "unknown method"
+ }
+ return f.Name()
+}
+
+type typeQueue struct {
+ t reflect.Type
+ fi *FieldInfo
+ pp string // Parent path
+}
+
+// A copying append that creates a new slice each time.
+func apnd(is []int, i int) []int {
+ x := make([]int, len(is)+1)
+ copy(x, is)
+ x[len(x)-1] = i
+ return x
+}
+
+type mapf func(string) string
+
+// parseName parses the tag and the target name for the given field using
+// the tagName (eg 'json' for `json:"foo"` tags), mapFunc for mapping the
+// field's name to a target name, and tagMapFunc for mapping the tag to
+// a target name.
+func parseName(field reflect.StructField, tagName string, mapFunc, tagMapFunc mapf) (tag, fieldName string) {
+ // first, set the fieldName to the field's name
+ fieldName = field.Name
+ // if a mapFunc is set, use that to override the fieldName
+ if mapFunc != nil {
+ fieldName = mapFunc(fieldName)
+ }
+
+ // if there's no tag to look for, return the field name
+ if tagName == "" {
+ return "", fieldName
+ }
+
+ // if this tag is not set using the normal convention in the tag,
+ // then return the fieldname.. this check is done because according
+ // to the reflect documentation:
+ // If the tag does not have the conventional format,
+ // the value returned by Get is unspecified.
+ // which doesn't sound great.
+ if !strings.Contains(string(field.Tag), tagName+":") {
+ return "", fieldName
+ }
+
+ // at this point we're fairly sure that we have a tag, so lets pull it out
+ tag = field.Tag.Get(tagName)
+
+ // if we have a mapper function, call it on the whole tag
+ // XXX: this is a change from the old version, which pulled out the name
+ // before the tagMapFunc could be run, but I think this is the right way
+ if tagMapFunc != nil {
+ tag = tagMapFunc(tag)
+ }
+
+ // finally, split the options from the name
+ parts := strings.Split(tag, ",")
+ fieldName = parts[0]
+
+ return tag, fieldName
+}
+
+// parseOptions parses options out of a tag string, skipping the name
+func parseOptions(tag string) map[string]string {
+ parts := strings.Split(tag, ",")
+ options := make(map[string]string, len(parts))
+ if len(parts) > 1 {
+ for _, opt := range parts[1:] {
+ // short circuit potentially expensive split op
+ if strings.Contains(opt, "=") {
+ kv := strings.Split(opt, "=")
+ options[kv[0]] = kv[1]
+ continue
+ }
+ options[opt] = ""
+ }
+ }
+ return options
+}
+
+// getMapping returns a mapping for the t type, using the tagName, mapFunc and
+// tagMapFunc to determine the canonical names of fields.
+func getMapping(t reflect.Type, tagName string, mapFunc, tagMapFunc mapf) *StructMap {
+ m := []*FieldInfo{}
+
+ root := &FieldInfo{}
+ queue := []typeQueue{}
+ queue = append(queue, typeQueue{Deref(t), root, ""})
+
+QueueLoop:
+ for len(queue) != 0 {
+ // pop the first item off of the queue
+ tq := queue[0]
+ queue = queue[1:]
+
+ // ignore recursive field
+ for p := tq.fi.Parent; p != nil; p = p.Parent {
+ if tq.fi.Field.Type == p.Field.Type {
+ continue QueueLoop
+ }
+ }
+
+ nChildren := 0
+ if tq.t.Kind() == reflect.Struct {
+ nChildren = tq.t.NumField()
+ }
+ tq.fi.Children = make([]*FieldInfo, nChildren)
+
+ // iterate through all of its fields
+ for fieldPos := 0; fieldPos < nChildren; fieldPos++ {
+
+ f := tq.t.Field(fieldPos)
+
+ // parse the tag and the target name using the mapping options for this field
+ tag, name := parseName(f, tagName, mapFunc, tagMapFunc)
+
+ // if the name is "-", disabled via a tag, skip it
+ if name == "-" {
+ continue
+ }
+
+ fi := FieldInfo{
+ Field: f,
+ Name: name,
+ Zero: reflect.New(f.Type).Elem(),
+ Options: parseOptions(tag),
+ }
+
+ // if the path is empty this path is just the name
+ if tq.pp == "" {
+ fi.Path = fi.Name
+ } else {
+ fi.Path = tq.pp + "." + fi.Name
+ }
+
+ // skip unexported fields
+ if len(f.PkgPath) != 0 && !f.Anonymous {
+ continue
+ }
+
+ // bfs search of anonymous embedded structs
+ if f.Anonymous {
+ pp := tq.pp
+ if tag != "" {
+ pp = fi.Path
+ }
+
+ fi.Embedded = true
+ fi.Index = apnd(tq.fi.Index, fieldPos)
+ nChildren := 0
+ ft := Deref(f.Type)
+ if ft.Kind() == reflect.Struct {
+ nChildren = ft.NumField()
+ }
+ fi.Children = make([]*FieldInfo, nChildren)
+ queue = append(queue, typeQueue{Deref(f.Type), &fi, pp})
+ } else if fi.Zero.Kind() == reflect.Struct || (fi.Zero.Kind() == reflect.Ptr && fi.Zero.Type().Elem().Kind() == reflect.Struct) {
+ fi.Index = apnd(tq.fi.Index, fieldPos)
+ fi.Children = make([]*FieldInfo, Deref(f.Type).NumField())
+ queue = append(queue, typeQueue{Deref(f.Type), &fi, fi.Path})
+ }
+
+ fi.Index = apnd(tq.fi.Index, fieldPos)
+ fi.Parent = tq.fi
+ tq.fi.Children[fieldPos] = &fi
+ m = append(m, &fi)
+ }
+ }
+
+ flds := &StructMap{Index: m, Tree: root, Paths: map[string]*FieldInfo{}, Names: map[string]*FieldInfo{}}
+ for _, fi := range flds.Index {
+ // check if nothing has already been pushed with the same path
+ // sometimes you can choose to override a type using embedded struct
+ fld, ok := flds.Paths[fi.Path]
+ if !ok || fld.Embedded {
+ flds.Paths[fi.Path] = fi
+ if fi.Name != "" && !fi.Embedded {
+ flds.Names[fi.Path] = fi
+ }
+ }
+ }
+
+ return flds
+}
diff --git a/vendor/github.com/jmoiron/sqlx/sqlx.go b/vendor/github.com/jmoiron/sqlx/sqlx.go
new file mode 100644
index 0000000..8259a4f
--- /dev/null
+++ b/vendor/github.com/jmoiron/sqlx/sqlx.go
@@ -0,0 +1,1054 @@
+package sqlx
+
+import (
+ "database/sql"
+ "database/sql/driver"
+ "errors"
+ "fmt"
+ "io/ioutil"
+ "path/filepath"
+ "reflect"
+ "strings"
+ "sync"
+
+ "github.com/jmoiron/sqlx/reflectx"
+)
+
+// Although the NameMapper is convenient, in practice it should not
+// be relied on except for application code. If you are writing a library
+// that uses sqlx, you should be aware that the name mappings you expect
+// can be overridden by your user's application.
+
+// NameMapper is used to map column names to struct field names. By default,
+// it uses strings.ToLower to lowercase struct field names. It can be set
+// to whatever you want, but it is encouraged to be set before sqlx is used
+// as name-to-field mappings are cached after first use on a type.
+var NameMapper = strings.ToLower
+var origMapper = reflect.ValueOf(NameMapper)
+
+// Rather than creating on init, this is created when necessary so that
+// importers have time to customize the NameMapper.
+var mpr *reflectx.Mapper
+
+// mprMu protects mpr.
+var mprMu sync.Mutex
+
+// mapper returns a valid mapper using the configured NameMapper func.
+func mapper() *reflectx.Mapper {
+ mprMu.Lock()
+ defer mprMu.Unlock()
+
+ if mpr == nil {
+ mpr = reflectx.NewMapperFunc("db", NameMapper)
+ } else if origMapper != reflect.ValueOf(NameMapper) {
+ // if NameMapper has changed, create a new mapper
+ mpr = reflectx.NewMapperFunc("db", NameMapper)
+ origMapper = reflect.ValueOf(NameMapper)
+ }
+ return mpr
+}
+
+// isScannable takes the reflect.Type and the actual dest value and returns
+// whether or not it's Scannable. Something is scannable if:
+// - it is not a struct
+// - it implements sql.Scanner
+// - it has no exported fields
+func isScannable(t reflect.Type) bool {
+ if reflect.PtrTo(t).Implements(_scannerInterface) {
+ return true
+ }
+ if t.Kind() != reflect.Struct {
+ return true
+ }
+
+ // it's not important that we use the right mapper for this particular object,
+ // we're only concerned on how many exported fields this struct has
+ return len(mapper().TypeMap(t).Index) == 0
+}
+
+// ColScanner is an interface used by MapScan and SliceScan
+type ColScanner interface {
+ Columns() ([]string, error)
+ Scan(dest ...interface{}) error
+ Err() error
+}
+
+// Queryer is an interface used by Get and Select
+type Queryer interface {
+ Query(query string, args ...interface{}) (*sql.Rows, error)
+ Queryx(query string, args ...interface{}) (*Rows, error)
+ QueryRowx(query string, args ...interface{}) *Row
+}
+
+// Execer is an interface used by MustExec and LoadFile
+type Execer interface {
+ Exec(query string, args ...interface{}) (sql.Result, error)
+}
+
+// Binder is an interface for something which can bind queries (Tx, DB)
+type binder interface {
+ DriverName() string
+ Rebind(string) string
+ BindNamed(string, interface{}) (string, []interface{}, error)
+}
+
+// Ext is a union interface which can bind, query, and exec, used by
+// NamedQuery and NamedExec.
+type Ext interface {
+ binder
+ Queryer
+ Execer
+}
+
+// Preparer is an interface used by Preparex.
+type Preparer interface {
+ Prepare(query string) (*sql.Stmt, error)
+}
+
+// determine if any of our extensions are unsafe
+func isUnsafe(i interface{}) bool {
+ switch v := i.(type) {
+ case Row:
+ return v.unsafe
+ case *Row:
+ return v.unsafe
+ case Rows:
+ return v.unsafe
+ case *Rows:
+ return v.unsafe
+ case NamedStmt:
+ return v.Stmt.unsafe
+ case *NamedStmt:
+ return v.Stmt.unsafe
+ case Stmt:
+ return v.unsafe
+ case *Stmt:
+ return v.unsafe
+ case qStmt:
+ return v.unsafe
+ case *qStmt:
+ return v.unsafe
+ case DB:
+ return v.unsafe
+ case *DB:
+ return v.unsafe
+ case Tx:
+ return v.unsafe
+ case *Tx:
+ return v.unsafe
+ case sql.Rows, *sql.Rows:
+ return false
+ default:
+ return false
+ }
+}
+
+func mapperFor(i interface{}) *reflectx.Mapper {
+ switch i := i.(type) {
+ case DB:
+ return i.Mapper
+ case *DB:
+ return i.Mapper
+ case Tx:
+ return i.Mapper
+ case *Tx:
+ return i.Mapper
+ default:
+ return mapper()
+ }
+}
+
+var _scannerInterface = reflect.TypeOf((*sql.Scanner)(nil)).Elem()
+
+//lint:ignore U1000 ignoring this for now
+var _valuerInterface = reflect.TypeOf((*driver.Valuer)(nil)).Elem()
+
+// Row is a reimplementation of sql.Row in order to gain access to the underlying
+// sql.Rows.Columns() data, necessary for StructScan.
+type Row struct {
+ err error
+ unsafe bool
+ rows *sql.Rows
+ Mapper *reflectx.Mapper
+}
+
+// Scan is a fixed implementation of sql.Row.Scan, which does not discard the
+// underlying error from the internal rows object if it exists.
+func (r *Row) Scan(dest ...interface{}) error {
+ if r.err != nil {
+ return r.err
+ }
+
+ // TODO(bradfitz): for now we need to defensively clone all
+ // []byte that the driver returned (not permitting
+ // *RawBytes in Rows.Scan), since we're about to close
+ // the Rows in our defer, when we return from this function.
+ // the contract with the driver.Next(...) interface is that it
+ // can return slices into read-only temporary memory that's
+ // only valid until the next Scan/Close. But the TODO is that
+ // for a lot of drivers, this copy will be unnecessary. We
+ // should provide an optional interface for drivers to
+ // implement to say, "don't worry, the []bytes that I return
+ // from Next will not be modified again." (for instance, if
+ // they were obtained from the network anyway) But for now we
+ // don't care.
+ defer r.rows.Close()
+ for _, dp := range dest {
+ if _, ok := dp.(*sql.RawBytes); ok {
+ return errors.New("sql: RawBytes isn't allowed on Row.Scan")
+ }
+ }
+
+ if !r.rows.Next() {
+ if err := r.rows.Err(); err != nil {
+ return err
+ }
+ return sql.ErrNoRows
+ }
+ err := r.rows.Scan(dest...)
+ if err != nil {
+ return err
+ }
+ // Make sure the query can be processed to completion with no errors.
+ if err := r.rows.Close(); err != nil {
+ return err
+ }
+ return nil
+}
+
+// Columns returns the underlying sql.Rows.Columns(), or the deferred error usually
+// returned by Row.Scan()
+func (r *Row) Columns() ([]string, error) {
+ if r.err != nil {
+ return []string{}, r.err
+ }
+ return r.rows.Columns()
+}
+
+// ColumnTypes returns the underlying sql.Rows.ColumnTypes(), or the deferred error
+func (r *Row) ColumnTypes() ([]*sql.ColumnType, error) {
+ if r.err != nil {
+ return []*sql.ColumnType{}, r.err
+ }
+ return r.rows.ColumnTypes()
+}
+
+// Err returns the error encountered while scanning.
+func (r *Row) Err() error {
+ return r.err
+}
+
+// DB is a wrapper around sql.DB which keeps track of the driverName upon Open,
+// used mostly to automatically bind named queries using the right bindvars.
+type DB struct {
+ *sql.DB
+ driverName string
+ unsafe bool
+ Mapper *reflectx.Mapper
+}
+
+// NewDb returns a new sqlx DB wrapper for a pre-existing *sql.DB. The
+// driverName of the original database is required for named query support.
+//
+//lint:ignore ST1003 changing this would break the package interface.
+func NewDb(db *sql.DB, driverName string) *DB {
+ return &DB{DB: db, driverName: driverName, Mapper: mapper()}
+}
+
+// DriverName returns the driverName passed to the Open function for this DB.
+func (db *DB) DriverName() string {
+ return db.driverName
+}
+
+// Open is the same as sql.Open, but returns an *sqlx.DB instead.
+func Open(driverName, dataSourceName string) (*DB, error) {
+ db, err := sql.Open(driverName, dataSourceName)
+ if err != nil {
+ return nil, err
+ }
+ return &DB{DB: db, driverName: driverName, Mapper: mapper()}, err
+}
+
+// MustOpen is the same as sql.Open, but returns an *sqlx.DB instead and panics on error.
+func MustOpen(driverName, dataSourceName string) *DB {
+ db, err := Open(driverName, dataSourceName)
+ if err != nil {
+ panic(err)
+ }
+ return db
+}
+
+// MapperFunc sets a new mapper for this db using the default sqlx struct tag
+// and the provided mapper function.
+func (db *DB) MapperFunc(mf func(string) string) {
+ db.Mapper = reflectx.NewMapperFunc("db", mf)
+}
+
+// Rebind transforms a query from QUESTION to the DB driver's bindvar type.
+func (db *DB) Rebind(query string) string {
+ return Rebind(BindType(db.driverName), query)
+}
+
+// Unsafe returns a version of DB which will silently succeed to scan when
+// columns in the SQL result have no fields in the destination struct.
+// sqlx.Stmt and sqlx.Tx which are created from this DB will inherit its
+// safety behavior.
+func (db *DB) Unsafe() *DB {
+ return &DB{DB: db.DB, driverName: db.driverName, unsafe: true, Mapper: db.Mapper}
+}
+
+// BindNamed binds a query using the DB driver's bindvar type.
+func (db *DB) BindNamed(query string, arg interface{}) (string, []interface{}, error) {
+ return bindNamedMapper(BindType(db.driverName), query, arg, db.Mapper)
+}
+
+// NamedQuery using this DB.
+// Any named placeholder parameters are replaced with fields from arg.
+func (db *DB) NamedQuery(query string, arg interface{}) (*Rows, error) {
+ return NamedQuery(db, query, arg)
+}
+
+// NamedExec using this DB.
+// Any named placeholder parameters are replaced with fields from arg.
+func (db *DB) NamedExec(query string, arg interface{}) (sql.Result, error) {
+ return NamedExec(db, query, arg)
+}
+
+// Select using this DB.
+// Any placeholder parameters are replaced with supplied args.
+func (db *DB) Select(dest interface{}, query string, args ...interface{}) error {
+ return Select(db, dest, query, args...)
+}
+
+// Get using this DB.
+// Any placeholder parameters are replaced with supplied args.
+// An error is returned if the result set is empty.
+func (db *DB) Get(dest interface{}, query string, args ...interface{}) error {
+ return Get(db, dest, query, args...)
+}
+
+// MustBegin starts a transaction, and panics on error. Returns an *sqlx.Tx instead
+// of an *sql.Tx.
+func (db *DB) MustBegin() *Tx {
+ tx, err := db.Beginx()
+ if err != nil {
+ panic(err)
+ }
+ return tx
+}
+
+// Beginx begins a transaction and returns an *sqlx.Tx instead of an *sql.Tx.
+func (db *DB) Beginx() (*Tx, error) {
+ tx, err := db.DB.Begin()
+ if err != nil {
+ return nil, err
+ }
+ return &Tx{Tx: tx, driverName: db.driverName, unsafe: db.unsafe, Mapper: db.Mapper}, err
+}
+
+// Queryx queries the database and returns an *sqlx.Rows.
+// Any placeholder parameters are replaced with supplied args.
+func (db *DB) Queryx(query string, args ...interface{}) (*Rows, error) {
+ r, err := db.DB.Query(query, args...)
+ if err != nil {
+ return nil, err
+ }
+ return &Rows{Rows: r, unsafe: db.unsafe, Mapper: db.Mapper}, err
+}
+
+// QueryRowx queries the database and returns an *sqlx.Row.
+// Any placeholder parameters are replaced with supplied args.
+func (db *DB) QueryRowx(query string, args ...interface{}) *Row {
+ rows, err := db.DB.Query(query, args...)
+ return &Row{rows: rows, err: err, unsafe: db.unsafe, Mapper: db.Mapper}
+}
+
+// MustExec (panic) runs MustExec using this database.
+// Any placeholder parameters are replaced with supplied args.
+func (db *DB) MustExec(query string, args ...interface{}) sql.Result {
+ return MustExec(db, query, args...)
+}
+
+// Preparex returns an sqlx.Stmt instead of a sql.Stmt
+func (db *DB) Preparex(query string) (*Stmt, error) {
+ return Preparex(db, query)
+}
+
+// PrepareNamed returns an sqlx.NamedStmt
+func (db *DB) PrepareNamed(query string) (*NamedStmt, error) {
+ return prepareNamed(db, query)
+}
+
+// Conn is a wrapper around sql.Conn with extra functionality
+type Conn struct {
+ *sql.Conn
+ driverName string
+ unsafe bool
+ Mapper *reflectx.Mapper
+}
+
+// Tx is an sqlx wrapper around sql.Tx with extra functionality
+type Tx struct {
+ *sql.Tx
+ driverName string
+ unsafe bool
+ Mapper *reflectx.Mapper
+}
+
+// DriverName returns the driverName used by the DB which began this transaction.
+func (tx *Tx) DriverName() string {
+ return tx.driverName
+}
+
+// Rebind a query within a transaction's bindvar type.
+func (tx *Tx) Rebind(query string) string {
+ return Rebind(BindType(tx.driverName), query)
+}
+
+// Unsafe returns a version of Tx which will silently succeed to scan when
+// columns in the SQL result have no fields in the destination struct.
+func (tx *Tx) Unsafe() *Tx {
+ return &Tx{Tx: tx.Tx, driverName: tx.driverName, unsafe: true, Mapper: tx.Mapper}
+}
+
+// BindNamed binds a query within a transaction's bindvar type.
+func (tx *Tx) BindNamed(query string, arg interface{}) (string, []interface{}, error) {
+ return bindNamedMapper(BindType(tx.driverName), query, arg, tx.Mapper)
+}
+
+// NamedQuery within a transaction.
+// Any named placeholder parameters are replaced with fields from arg.
+func (tx *Tx) NamedQuery(query string, arg interface{}) (*Rows, error) {
+ return NamedQuery(tx, query, arg)
+}
+
+// NamedExec a named query within a transaction.
+// Any named placeholder parameters are replaced with fields from arg.
+func (tx *Tx) NamedExec(query string, arg interface{}) (sql.Result, error) {
+ return NamedExec(tx, query, arg)
+}
+
+// Select within a transaction.
+// Any placeholder parameters are replaced with supplied args.
+func (tx *Tx) Select(dest interface{}, query string, args ...interface{}) error {
+ return Select(tx, dest, query, args...)
+}
+
+// Queryx within a transaction.
+// Any placeholder parameters are replaced with supplied args.
+func (tx *Tx) Queryx(query string, args ...interface{}) (*Rows, error) {
+ r, err := tx.Tx.Query(query, args...)
+ if err != nil {
+ return nil, err
+ }
+ return &Rows{Rows: r, unsafe: tx.unsafe, Mapper: tx.Mapper}, err
+}
+
+// QueryRowx within a transaction.
+// Any placeholder parameters are replaced with supplied args.
+func (tx *Tx) QueryRowx(query string, args ...interface{}) *Row {
+ rows, err := tx.Tx.Query(query, args...)
+ return &Row{rows: rows, err: err, unsafe: tx.unsafe, Mapper: tx.Mapper}
+}
+
+// Get within a transaction.
+// Any placeholder parameters are replaced with supplied args.
+// An error is returned if the result set is empty.
+func (tx *Tx) Get(dest interface{}, query string, args ...interface{}) error {
+ return Get(tx, dest, query, args...)
+}
+
+// MustExec runs MustExec within a transaction.
+// Any placeholder parameters are replaced with supplied args.
+func (tx *Tx) MustExec(query string, args ...interface{}) sql.Result {
+ return MustExec(tx, query, args...)
+}
+
+// Preparex a statement within a transaction.
+func (tx *Tx) Preparex(query string) (*Stmt, error) {
+ return Preparex(tx, query)
+}
+
+// Stmtx returns a version of the prepared statement which runs within a transaction. Provided
+// stmt can be either *sql.Stmt or *sqlx.Stmt.
+func (tx *Tx) Stmtx(stmt interface{}) *Stmt {
+ var s *sql.Stmt
+ switch v := stmt.(type) {
+ case Stmt:
+ s = v.Stmt
+ case *Stmt:
+ s = v.Stmt
+ case *sql.Stmt:
+ s = v
+ default:
+ panic(fmt.Sprintf("non-statement type %v passed to Stmtx", reflect.ValueOf(stmt).Type()))
+ }
+ return &Stmt{Stmt: tx.Stmt(s), Mapper: tx.Mapper}
+}
+
+// NamedStmt returns a version of the prepared statement which runs within a transaction.
+func (tx *Tx) NamedStmt(stmt *NamedStmt) *NamedStmt {
+ return &NamedStmt{
+ QueryString: stmt.QueryString,
+ Params: stmt.Params,
+ Stmt: tx.Stmtx(stmt.Stmt),
+ }
+}
+
+// PrepareNamed returns an sqlx.NamedStmt
+func (tx *Tx) PrepareNamed(query string) (*NamedStmt, error) {
+ return prepareNamed(tx, query)
+}
+
+// Stmt is an sqlx wrapper around sql.Stmt with extra functionality
+type Stmt struct {
+ *sql.Stmt
+ unsafe bool
+ Mapper *reflectx.Mapper
+}
+
+// Unsafe returns a version of Stmt which will silently succeed to scan when
+// columns in the SQL result have no fields in the destination struct.
+func (s *Stmt) Unsafe() *Stmt {
+ return &Stmt{Stmt: s.Stmt, unsafe: true, Mapper: s.Mapper}
+}
+
+// Select using the prepared statement.
+// Any placeholder parameters are replaced with supplied args.
+func (s *Stmt) Select(dest interface{}, args ...interface{}) error {
+ return Select(&qStmt{s}, dest, "", args...)
+}
+
+// Get using the prepared statement.
+// Any placeholder parameters are replaced with supplied args.
+// An error is returned if the result set is empty.
+func (s *Stmt) Get(dest interface{}, args ...interface{}) error {
+ return Get(&qStmt{s}, dest, "", args...)
+}
+
+// MustExec (panic) using this statement. Note that the query portion of the error
+// output will be blank, as Stmt does not expose its query.
+// Any placeholder parameters are replaced with supplied args.
+func (s *Stmt) MustExec(args ...interface{}) sql.Result {
+ return MustExec(&qStmt{s}, "", args...)
+}
+
+// QueryRowx using this statement.
+// Any placeholder parameters are replaced with supplied args.
+func (s *Stmt) QueryRowx(args ...interface{}) *Row {
+ qs := &qStmt{s}
+ return qs.QueryRowx("", args...)
+}
+
+// Queryx using this statement.
+// Any placeholder parameters are replaced with supplied args.
+func (s *Stmt) Queryx(args ...interface{}) (*Rows, error) {
+ qs := &qStmt{s}
+ return qs.Queryx("", args...)
+}
+
+// qStmt is an unexposed wrapper which lets you use a Stmt as a Queryer & Execer by
+// implementing those interfaces and ignoring the `query` argument.
+type qStmt struct{ *Stmt }
+
+func (q *qStmt) Query(query string, args ...interface{}) (*sql.Rows, error) {
+ return q.Stmt.Query(args...)
+}
+
+func (q *qStmt) Queryx(query string, args ...interface{}) (*Rows, error) {
+ r, err := q.Stmt.Query(args...)
+ if err != nil {
+ return nil, err
+ }
+ return &Rows{Rows: r, unsafe: q.Stmt.unsafe, Mapper: q.Stmt.Mapper}, err
+}
+
+func (q *qStmt) QueryRowx(query string, args ...interface{}) *Row {
+ rows, err := q.Stmt.Query(args...)
+ return &Row{rows: rows, err: err, unsafe: q.Stmt.unsafe, Mapper: q.Stmt.Mapper}
+}
+
+func (q *qStmt) Exec(query string, args ...interface{}) (sql.Result, error) {
+ return q.Stmt.Exec(args...)
+}
+
+// Rows is a wrapper around sql.Rows which caches costly reflect operations
+// during a looped StructScan
+type Rows struct {
+ *sql.Rows
+ unsafe bool
+ Mapper *reflectx.Mapper
+ // these fields cache memory use for a rows during iteration w/ structScan
+ started bool
+ fields [][]int
+ values []interface{}
+}
+
+// SliceScan using this Rows.
+func (r *Rows) SliceScan() ([]interface{}, error) {
+ return SliceScan(r)
+}
+
+// MapScan using this Rows.
+func (r *Rows) MapScan(dest map[string]interface{}) error {
+ return MapScan(r, dest)
+}
+
+// StructScan is like sql.Rows.Scan, but scans a single Row into a single Struct.
+// Use this and iterate over Rows manually when the memory load of Select() might be
+// prohibitive. *Rows.StructScan caches the reflect work of matching up column
+// positions to fields to avoid that overhead per scan, which means it is not safe
+// to run StructScan on the same Rows instance with different struct types.
+func (r *Rows) StructScan(dest interface{}) error {
+ v := reflect.ValueOf(dest)
+
+ if v.Kind() != reflect.Ptr {
+ return errors.New("must pass a pointer, not a value, to StructScan destination")
+ }
+
+ v = v.Elem()
+
+ if !r.started {
+ columns, err := r.Columns()
+ if err != nil {
+ return err
+ }
+ m := r.Mapper
+
+ r.fields = m.TraversalsByName(v.Type(), columns)
+ // if we are not unsafe and are missing fields, return an error
+ if f, err := missingFields(r.fields); err != nil && !r.unsafe {
+ return fmt.Errorf("missing destination name %s in %T", columns[f], dest)
+ }
+ r.values = make([]interface{}, len(columns))
+ r.started = true
+ }
+
+ err := fieldsByTraversal(v, r.fields, r.values, true)
+ if err != nil {
+ return err
+ }
+ // scan into the struct field pointers and append to our results
+ err = r.Scan(r.values...)
+ if err != nil {
+ return err
+ }
+ return r.Err()
+}
+
+// Connect to a database and verify with a ping.
+func Connect(driverName, dataSourceName string) (*DB, error) {
+ db, err := Open(driverName, dataSourceName)
+ if err != nil {
+ return nil, err
+ }
+ err = db.Ping()
+ if err != nil {
+ db.Close()
+ return nil, err
+ }
+ return db, nil
+}
+
+// MustConnect connects to a database and panics on error.
+func MustConnect(driverName, dataSourceName string) *DB {
+ db, err := Connect(driverName, dataSourceName)
+ if err != nil {
+ panic(err)
+ }
+ return db
+}
+
+// Preparex prepares a statement.
+func Preparex(p Preparer, query string) (*Stmt, error) {
+ s, err := p.Prepare(query)
+ if err != nil {
+ return nil, err
+ }
+ return &Stmt{Stmt: s, unsafe: isUnsafe(p), Mapper: mapperFor(p)}, err
+}
+
+// Select executes a query using the provided Queryer, and StructScans each row
+// into dest, which must be a slice. If the slice elements are scannable, then
+// the result set must have only one column. Otherwise, StructScan is used.
+// The *sql.Rows are closed automatically.
+// Any placeholder parameters are replaced with supplied args.
+func Select(q Queryer, dest interface{}, query string, args ...interface{}) error {
+ rows, err := q.Queryx(query, args...)
+ if err != nil {
+ return err
+ }
+ // if something happens here, we want to make sure the rows are Closed
+ defer rows.Close()
+ return scanAll(rows, dest, false)
+}
+
+// Get does a QueryRow using the provided Queryer, and scans the resulting row
+// to dest. If dest is scannable, the result must only have one column. Otherwise,
+// StructScan is used. Get will return sql.ErrNoRows like row.Scan would.
+// Any placeholder parameters are replaced with supplied args.
+// An error is returned if the result set is empty.
+func Get(q Queryer, dest interface{}, query string, args ...interface{}) error {
+ r := q.QueryRowx(query, args...)
+ return r.scanAny(dest, false)
+}
+
+// LoadFile exec's every statement in a file (as a single call to Exec).
+// LoadFile may return a nil *sql.Result if errors are encountered locating or
+// reading the file at path. LoadFile reads the entire file into memory, so it
+// is not suitable for loading large data dumps, but can be useful for initializing
+// schemas or loading indexes.
+//
+// FIXME: this does not really work with multi-statement files for mattn/go-sqlite3
+// or the go-mysql-driver/mysql drivers; pq seems to be an exception here. Detecting
+// this by requiring something with DriverName() and then attempting to split the
+// queries will be difficult to get right, and its current driver-specific behavior
+// is deemed at least not complex in its incorrectness.
+func LoadFile(e Execer, path string) (*sql.Result, error) {
+ realpath, err := filepath.Abs(path)
+ if err != nil {
+ return nil, err
+ }
+ contents, err := ioutil.ReadFile(realpath)
+ if err != nil {
+ return nil, err
+ }
+ res, err := e.Exec(string(contents))
+ return &res, err
+}
+
+// MustExec execs the query using e and panics if there was an error.
+// Any placeholder parameters are replaced with supplied args.
+func MustExec(e Execer, query string, args ...interface{}) sql.Result {
+ res, err := e.Exec(query, args...)
+ if err != nil {
+ panic(err)
+ }
+ return res
+}
+
+// SliceScan using this Rows.
+func (r *Row) SliceScan() ([]interface{}, error) {
+ return SliceScan(r)
+}
+
+// MapScan using this Rows.
+func (r *Row) MapScan(dest map[string]interface{}) error {
+ return MapScan(r, dest)
+}
+
+func (r *Row) scanAny(dest interface{}, structOnly bool) error {
+ if r.err != nil {
+ return r.err
+ }
+ if r.rows == nil {
+ r.err = sql.ErrNoRows
+ return r.err
+ }
+ defer r.rows.Close()
+
+ v := reflect.ValueOf(dest)
+ if v.Kind() != reflect.Ptr {
+ return errors.New("must pass a pointer, not a value, to StructScan destination")
+ }
+ if v.IsNil() {
+ return errors.New("nil pointer passed to StructScan destination")
+ }
+
+ base := reflectx.Deref(v.Type())
+ scannable := isScannable(base)
+
+ if structOnly && scannable {
+ return structOnlyError(base)
+ }
+
+ columns, err := r.Columns()
+ if err != nil {
+ return err
+ }
+
+ if scannable && len(columns) > 1 {
+ return fmt.Errorf("scannable dest type %s with >1 columns (%d) in result", base.Kind(), len(columns))
+ }
+
+ if scannable {
+ return r.Scan(dest)
+ }
+
+ m := r.Mapper
+
+ fields := m.TraversalsByName(v.Type(), columns)
+ // if we are not unsafe and are missing fields, return an error
+ if f, err := missingFields(fields); err != nil && !r.unsafe {
+ return fmt.Errorf("missing destination name %s in %T", columns[f], dest)
+ }
+ values := make([]interface{}, len(columns))
+
+ err = fieldsByTraversal(v, fields, values, true)
+ if err != nil {
+ return err
+ }
+ // scan into the struct field pointers and append to our results
+ return r.Scan(values...)
+}
+
+// StructScan a single Row into dest.
+func (r *Row) StructScan(dest interface{}) error {
+ return r.scanAny(dest, true)
+}
+
+// SliceScan a row, returning a []interface{} with values similar to MapScan.
+// This function is primarily intended for use where the number of columns
+// is not known. Because you can pass an []interface{} directly to Scan,
+// it's recommended that you do that as it will not have to allocate new
+// slices per row.
+func SliceScan(r ColScanner) ([]interface{}, error) {
+ // ignore r.started, since we needn't use reflect for anything.
+ columns, err := r.Columns()
+ if err != nil {
+ return []interface{}{}, err
+ }
+
+ values := make([]interface{}, len(columns))
+ for i := range values {
+ values[i] = new(interface{})
+ }
+
+ err = r.Scan(values...)
+
+ if err != nil {
+ return values, err
+ }
+
+ for i := range columns {
+ values[i] = *(values[i].(*interface{}))
+ }
+
+ return values, r.Err()
+}
+
+// MapScan scans a single Row into the dest map[string]interface{}.
+// Use this to get results for SQL that might not be under your control
+// (for instance, if you're building an interface for an SQL server that
+// executes SQL from input). Please do not use this as a primary interface!
+// This will modify the map sent to it in place, so reuse the same map with
+// care. Columns which occur more than once in the result will overwrite
+// each other!
+func MapScan(r ColScanner, dest map[string]interface{}) error {
+ // ignore r.started, since we needn't use reflect for anything.
+ columns, err := r.Columns()
+ if err != nil {
+ return err
+ }
+
+ values := make([]interface{}, len(columns))
+ for i := range values {
+ values[i] = new(interface{})
+ }
+
+ err = r.Scan(values...)
+ if err != nil {
+ return err
+ }
+
+ for i, column := range columns {
+ dest[column] = *(values[i].(*interface{}))
+ }
+
+ return r.Err()
+}
+
+type rowsi interface {
+ Close() error
+ Columns() ([]string, error)
+ Err() error
+ Next() bool
+ Scan(...interface{}) error
+}
+
+// structOnlyError returns an error appropriate for type when a non-scannable
+// struct is expected but something else is given
+func structOnlyError(t reflect.Type) error {
+ isStruct := t.Kind() == reflect.Struct
+ isScanner := reflect.PtrTo(t).Implements(_scannerInterface)
+ if !isStruct {
+ return fmt.Errorf("expected %s but got %s", reflect.Struct, t.Kind())
+ }
+ if isScanner {
+ return fmt.Errorf("structscan expects a struct dest but the provided struct type %s implements scanner", t.Name())
+ }
+ return fmt.Errorf("expected a struct, but struct %s has no exported fields", t.Name())
+}
+
+// scanAll scans all rows into a destination, which must be a slice of any
+// type. It resets the slice length to zero before appending each element to
+// the slice. If the destination slice type is a Struct, then StructScan will
+// be used on each row. If the destination is some other kind of base type,
+// then each row must only have one column which can scan into that type. This
+// allows you to do something like:
+//
+// rows, _ := db.Query("select id from people;")
+// var ids []int
+// scanAll(rows, &ids, false)
+//
+// and ids will be a list of the id results. I realize that this is a desirable
+// interface to expose to users, but for now it will only be exposed via changes
+// to `Get` and `Select`. The reason that this has been implemented like this is
+// this is the only way to not duplicate reflect work in the new API while
+// maintaining backwards compatibility.
+func scanAll(rows rowsi, dest interface{}, structOnly bool) error {
+ var v, vp reflect.Value
+
+ value := reflect.ValueOf(dest)
+
+ // json.Unmarshal returns errors for these
+ if value.Kind() != reflect.Ptr {
+ return errors.New("must pass a pointer, not a value, to StructScan destination")
+ }
+ if value.IsNil() {
+ return errors.New("nil pointer passed to StructScan destination")
+ }
+ direct := reflect.Indirect(value)
+
+ slice, err := baseType(value.Type(), reflect.Slice)
+ if err != nil {
+ return err
+ }
+ direct.SetLen(0)
+
+ isPtr := slice.Elem().Kind() == reflect.Ptr
+ base := reflectx.Deref(slice.Elem())
+ scannable := isScannable(base)
+
+ if structOnly && scannable {
+ return structOnlyError(base)
+ }
+
+ columns, err := rows.Columns()
+ if err != nil {
+ return err
+ }
+
+ // if it's a base type make sure it only has 1 column; if not return an error
+ if scannable && len(columns) > 1 {
+ return fmt.Errorf("non-struct dest type %s with >1 columns (%d)", base.Kind(), len(columns))
+ }
+
+ if !scannable {
+ var values []interface{}
+ var m *reflectx.Mapper
+
+ switch rows := rows.(type) {
+ case *Rows:
+ m = rows.Mapper
+ default:
+ m = mapper()
+ }
+
+ fields := m.TraversalsByName(base, columns)
+ // if we are not unsafe and are missing fields, return an error
+ if f, err := missingFields(fields); err != nil && !isUnsafe(rows) {
+ return fmt.Errorf("missing destination name %s in %T", columns[f], dest)
+ }
+ values = make([]interface{}, len(columns))
+
+ for rows.Next() {
+ // create a new struct type (which returns PtrTo) and indirect it
+ vp = reflect.New(base)
+ v = reflect.Indirect(vp)
+
+ err = fieldsByTraversal(v, fields, values, true)
+ if err != nil {
+ return err
+ }
+
+ // scan into the struct field pointers and append to our results
+ err = rows.Scan(values...)
+ if err != nil {
+ return err
+ }
+
+ if isPtr {
+ direct.Set(reflect.Append(direct, vp))
+ } else {
+ direct.Set(reflect.Append(direct, v))
+ }
+ }
+ } else {
+ for rows.Next() {
+ vp = reflect.New(base)
+ err = rows.Scan(vp.Interface())
+ if err != nil {
+ return err
+ }
+ // append
+ if isPtr {
+ direct.Set(reflect.Append(direct, vp))
+ } else {
+ direct.Set(reflect.Append(direct, reflect.Indirect(vp)))
+ }
+ }
+ }
+
+ return rows.Err()
+}
+
+// FIXME: StructScan was the very first bit of API in sqlx, and now unfortunately
+// it doesn't really feel like it's named properly. There is an incongruency
+// between this and the way that StructScan (which might better be ScanStruct
+// anyway) works on a rows object.
+
+// StructScan all rows from an sql.Rows or an sqlx.Rows into the dest slice.
+// StructScan will scan in the entire rows result, so if you do not want to
+// allocate structs for the entire result, use Queryx and see sqlx.Rows.StructScan.
+// If rows is sqlx.Rows, it will use its mapper, otherwise it will use the default.
+func StructScan(rows rowsi, dest interface{}) error {
+ return scanAll(rows, dest, true)
+
+}
+
+// reflect helpers
+
+func baseType(t reflect.Type, expected reflect.Kind) (reflect.Type, error) {
+ t = reflectx.Deref(t)
+ if t.Kind() != expected {
+ return nil, fmt.Errorf("expected %s but got %s", expected, t.Kind())
+ }
+ return t, nil
+}
+
+// fieldsByName fills a values interface with fields from the passed value based
+// on the traversals in int. If ptrs is true, return addresses instead of values.
+// We write this instead of using FieldsByName to save allocations and map lookups
+// when iterating over many rows. Empty traversals will get an interface pointer.
+// Because of the necessity of requesting ptrs or values, it's considered a bit too
+// specialized for inclusion in reflectx itself.
+func fieldsByTraversal(v reflect.Value, traversals [][]int, values []interface{}, ptrs bool) error {
+ v = reflect.Indirect(v)
+ if v.Kind() != reflect.Struct {
+ return errors.New("argument not a struct")
+ }
+
+ for i, traversal := range traversals {
+ if len(traversal) == 0 {
+ values[i] = new(interface{})
+ continue
+ }
+ f := reflectx.FieldByIndexes(v, traversal)
+ if ptrs {
+ values[i] = f.Addr().Interface()
+ } else {
+ values[i] = f.Interface()
+ }
+ }
+ return nil
+}
+
+func missingFields(transversals [][]int) (field int, err error) {
+ for i, t := range transversals {
+ if len(t) == 0 {
+ return i, errors.New("missing field")
+ }
+ }
+ return 0, nil
+}
diff --git a/vendor/github.com/jmoiron/sqlx/sqlx_context.go b/vendor/github.com/jmoiron/sqlx/sqlx_context.go
new file mode 100644
index 0000000..32621d5
--- /dev/null
+++ b/vendor/github.com/jmoiron/sqlx/sqlx_context.go
@@ -0,0 +1,415 @@
+//go:build go1.8
+// +build go1.8
+
+package sqlx
+
+import (
+ "context"
+ "database/sql"
+ "fmt"
+ "io/ioutil"
+ "path/filepath"
+ "reflect"
+)
+
+// ConnectContext to a database and verify with a ping.
+func ConnectContext(ctx context.Context, driverName, dataSourceName string) (*DB, error) {
+ db, err := Open(driverName, dataSourceName)
+ if err != nil {
+ return db, err
+ }
+ err = db.PingContext(ctx)
+ return db, err
+}
+
+// QueryerContext is an interface used by GetContext and SelectContext
+type QueryerContext interface {
+ QueryContext(ctx context.Context, query string, args ...interface{}) (*sql.Rows, error)
+ QueryxContext(ctx context.Context, query string, args ...interface{}) (*Rows, error)
+ QueryRowxContext(ctx context.Context, query string, args ...interface{}) *Row
+}
+
+// PreparerContext is an interface used by PreparexContext.
+type PreparerContext interface {
+ PrepareContext(ctx context.Context, query string) (*sql.Stmt, error)
+}
+
+// ExecerContext is an interface used by MustExecContext and LoadFileContext
+type ExecerContext interface {
+ ExecContext(ctx context.Context, query string, args ...interface{}) (sql.Result, error)
+}
+
+// ExtContext is a union interface which can bind, query, and exec, with Context
+// used by NamedQueryContext and NamedExecContext.
+type ExtContext interface {
+ binder
+ QueryerContext
+ ExecerContext
+}
+
+// SelectContext executes a query using the provided Queryer, and StructScans
+// each row into dest, which must be a slice. If the slice elements are
+// scannable, then the result set must have only one column. Otherwise,
+// StructScan is used. The *sql.Rows are closed automatically.
+// Any placeholder parameters are replaced with supplied args.
+func SelectContext(ctx context.Context, q QueryerContext, dest interface{}, query string, args ...interface{}) error {
+ rows, err := q.QueryxContext(ctx, query, args...)
+ if err != nil {
+ return err
+ }
+ // if something happens here, we want to make sure the rows are Closed
+ defer rows.Close()
+ return scanAll(rows, dest, false)
+}
+
+// PreparexContext prepares a statement.
+//
+// The provided context is used for the preparation of the statement, not for
+// the execution of the statement.
+func PreparexContext(ctx context.Context, p PreparerContext, query string) (*Stmt, error) {
+ s, err := p.PrepareContext(ctx, query)
+ if err != nil {
+ return nil, err
+ }
+ return &Stmt{Stmt: s, unsafe: isUnsafe(p), Mapper: mapperFor(p)}, err
+}
+
+// GetContext does a QueryRow using the provided Queryer, and scans the
+// resulting row to dest. If dest is scannable, the result must only have one
+// column. Otherwise, StructScan is used. Get will return sql.ErrNoRows like
+// row.Scan would. Any placeholder parameters are replaced with supplied args.
+// An error is returned if the result set is empty.
+func GetContext(ctx context.Context, q QueryerContext, dest interface{}, query string, args ...interface{}) error {
+ r := q.QueryRowxContext(ctx, query, args...)
+ return r.scanAny(dest, false)
+}
+
+// LoadFileContext exec's every statement in a file (as a single call to Exec).
+// LoadFileContext may return a nil *sql.Result if errors are encountered
+// locating or reading the file at path. LoadFile reads the entire file into
+// memory, so it is not suitable for loading large data dumps, but can be useful
+// for initializing schemas or loading indexes.
+//
+// FIXME: this does not really work with multi-statement files for mattn/go-sqlite3
+// or the go-mysql-driver/mysql drivers; pq seems to be an exception here. Detecting
+// this by requiring something with DriverName() and then attempting to split the
+// queries will be difficult to get right, and its current driver-specific behavior
+// is deemed at least not complex in its incorrectness.
+func LoadFileContext(ctx context.Context, e ExecerContext, path string) (*sql.Result, error) {
+ realpath, err := filepath.Abs(path)
+ if err != nil {
+ return nil, err
+ }
+ contents, err := ioutil.ReadFile(realpath)
+ if err != nil {
+ return nil, err
+ }
+ res, err := e.ExecContext(ctx, string(contents))
+ return &res, err
+}
+
+// MustExecContext execs the query using e and panics if there was an error.
+// Any placeholder parameters are replaced with supplied args.
+func MustExecContext(ctx context.Context, e ExecerContext, query string, args ...interface{}) sql.Result {
+ res, err := e.ExecContext(ctx, query, args...)
+ if err != nil {
+ panic(err)
+ }
+ return res
+}
+
+// PrepareNamedContext returns an sqlx.NamedStmt
+func (db *DB) PrepareNamedContext(ctx context.Context, query string) (*NamedStmt, error) {
+ return prepareNamedContext(ctx, db, query)
+}
+
+// NamedQueryContext using this DB.
+// Any named placeholder parameters are replaced with fields from arg.
+func (db *DB) NamedQueryContext(ctx context.Context, query string, arg interface{}) (*Rows, error) {
+ return NamedQueryContext(ctx, db, query, arg)
+}
+
+// NamedExecContext using this DB.
+// Any named placeholder parameters are replaced with fields from arg.
+func (db *DB) NamedExecContext(ctx context.Context, query string, arg interface{}) (sql.Result, error) {
+ return NamedExecContext(ctx, db, query, arg)
+}
+
+// SelectContext using this DB.
+// Any placeholder parameters are replaced with supplied args.
+func (db *DB) SelectContext(ctx context.Context, dest interface{}, query string, args ...interface{}) error {
+ return SelectContext(ctx, db, dest, query, args...)
+}
+
+// GetContext using this DB.
+// Any placeholder parameters are replaced with supplied args.
+// An error is returned if the result set is empty.
+func (db *DB) GetContext(ctx context.Context, dest interface{}, query string, args ...interface{}) error {
+ return GetContext(ctx, db, dest, query, args...)
+}
+
+// PreparexContext returns an sqlx.Stmt instead of a sql.Stmt.
+//
+// The provided context is used for the preparation of the statement, not for
+// the execution of the statement.
+func (db *DB) PreparexContext(ctx context.Context, query string) (*Stmt, error) {
+ return PreparexContext(ctx, db, query)
+}
+
+// QueryxContext queries the database and returns an *sqlx.Rows.
+// Any placeholder parameters are replaced with supplied args.
+func (db *DB) QueryxContext(ctx context.Context, query string, args ...interface{}) (*Rows, error) {
+ r, err := db.DB.QueryContext(ctx, query, args...)
+ if err != nil {
+ return nil, err
+ }
+ return &Rows{Rows: r, unsafe: db.unsafe, Mapper: db.Mapper}, err
+}
+
+// QueryRowxContext queries the database and returns an *sqlx.Row.
+// Any placeholder parameters are replaced with supplied args.
+func (db *DB) QueryRowxContext(ctx context.Context, query string, args ...interface{}) *Row {
+ rows, err := db.DB.QueryContext(ctx, query, args...)
+ return &Row{rows: rows, err: err, unsafe: db.unsafe, Mapper: db.Mapper}
+}
+
+// MustBeginTx starts a transaction, and panics on error. Returns an *sqlx.Tx instead
+// of an *sql.Tx.
+//
+// The provided context is used until the transaction is committed or rolled
+// back. If the context is canceled, the sql package will roll back the
+// transaction. Tx.Commit will return an error if the context provided to
+// MustBeginContext is canceled.
+func (db *DB) MustBeginTx(ctx context.Context, opts *sql.TxOptions) *Tx {
+ tx, err := db.BeginTxx(ctx, opts)
+ if err != nil {
+ panic(err)
+ }
+ return tx
+}
+
+// MustExecContext (panic) runs MustExec using this database.
+// Any placeholder parameters are replaced with supplied args.
+func (db *DB) MustExecContext(ctx context.Context, query string, args ...interface{}) sql.Result {
+ return MustExecContext(ctx, db, query, args...)
+}
+
+// BeginTxx begins a transaction and returns an *sqlx.Tx instead of an
+// *sql.Tx.
+//
+// The provided context is used until the transaction is committed or rolled
+// back. If the context is canceled, the sql package will roll back the
+// transaction. Tx.Commit will return an error if the context provided to
+// BeginxContext is canceled.
+func (db *DB) BeginTxx(ctx context.Context, opts *sql.TxOptions) (*Tx, error) {
+ tx, err := db.DB.BeginTx(ctx, opts)
+ if err != nil {
+ return nil, err
+ }
+ return &Tx{Tx: tx, driverName: db.driverName, unsafe: db.unsafe, Mapper: db.Mapper}, err
+}
+
+// Connx returns an *sqlx.Conn instead of an *sql.Conn.
+func (db *DB) Connx(ctx context.Context) (*Conn, error) {
+ conn, err := db.DB.Conn(ctx)
+ if err != nil {
+ return nil, err
+ }
+
+ return &Conn{Conn: conn, driverName: db.driverName, unsafe: db.unsafe, Mapper: db.Mapper}, nil
+}
+
+// BeginTxx begins a transaction and returns an *sqlx.Tx instead of an
+// *sql.Tx.
+//
+// The provided context is used until the transaction is committed or rolled
+// back. If the context is canceled, the sql package will roll back the
+// transaction. Tx.Commit will return an error if the context provided to
+// BeginxContext is canceled.
+func (c *Conn) BeginTxx(ctx context.Context, opts *sql.TxOptions) (*Tx, error) {
+ tx, err := c.Conn.BeginTx(ctx, opts)
+ if err != nil {
+ return nil, err
+ }
+ return &Tx{Tx: tx, driverName: c.driverName, unsafe: c.unsafe, Mapper: c.Mapper}, err
+}
+
+// SelectContext using this Conn.
+// Any placeholder parameters are replaced with supplied args.
+func (c *Conn) SelectContext(ctx context.Context, dest interface{}, query string, args ...interface{}) error {
+ return SelectContext(ctx, c, dest, query, args...)
+}
+
+// GetContext using this Conn.
+// Any placeholder parameters are replaced with supplied args.
+// An error is returned if the result set is empty.
+func (c *Conn) GetContext(ctx context.Context, dest interface{}, query string, args ...interface{}) error {
+ return GetContext(ctx, c, dest, query, args...)
+}
+
+// PreparexContext returns an sqlx.Stmt instead of a sql.Stmt.
+//
+// The provided context is used for the preparation of the statement, not for
+// the execution of the statement.
+func (c *Conn) PreparexContext(ctx context.Context, query string) (*Stmt, error) {
+ return PreparexContext(ctx, c, query)
+}
+
+// QueryxContext queries the database and returns an *sqlx.Rows.
+// Any placeholder parameters are replaced with supplied args.
+func (c *Conn) QueryxContext(ctx context.Context, query string, args ...interface{}) (*Rows, error) {
+ r, err := c.Conn.QueryContext(ctx, query, args...)
+ if err != nil {
+ return nil, err
+ }
+ return &Rows{Rows: r, unsafe: c.unsafe, Mapper: c.Mapper}, err
+}
+
+// QueryRowxContext queries the database and returns an *sqlx.Row.
+// Any placeholder parameters are replaced with supplied args.
+func (c *Conn) QueryRowxContext(ctx context.Context, query string, args ...interface{}) *Row {
+ rows, err := c.Conn.QueryContext(ctx, query, args...)
+ return &Row{rows: rows, err: err, unsafe: c.unsafe, Mapper: c.Mapper}
+}
+
+// Rebind a query within a Conn's bindvar type.
+func (c *Conn) Rebind(query string) string {
+ return Rebind(BindType(c.driverName), query)
+}
+
+// StmtxContext returns a version of the prepared statement which runs within a
+// transaction. Provided stmt can be either *sql.Stmt or *sqlx.Stmt.
+func (tx *Tx) StmtxContext(ctx context.Context, stmt interface{}) *Stmt {
+ var s *sql.Stmt
+ switch v := stmt.(type) {
+ case Stmt:
+ s = v.Stmt
+ case *Stmt:
+ s = v.Stmt
+ case *sql.Stmt:
+ s = v
+ default:
+ panic(fmt.Sprintf("non-statement type %v passed to Stmtx", reflect.ValueOf(stmt).Type()))
+ }
+ return &Stmt{Stmt: tx.StmtContext(ctx, s), Mapper: tx.Mapper}
+}
+
+// NamedStmtContext returns a version of the prepared statement which runs
+// within a transaction.
+func (tx *Tx) NamedStmtContext(ctx context.Context, stmt *NamedStmt) *NamedStmt {
+ return &NamedStmt{
+ QueryString: stmt.QueryString,
+ Params: stmt.Params,
+ Stmt: tx.StmtxContext(ctx, stmt.Stmt),
+ }
+}
+
+// PreparexContext returns an sqlx.Stmt instead of a sql.Stmt.
+//
+// The provided context is used for the preparation of the statement, not for
+// the execution of the statement.
+func (tx *Tx) PreparexContext(ctx context.Context, query string) (*Stmt, error) {
+ return PreparexContext(ctx, tx, query)
+}
+
+// PrepareNamedContext returns an sqlx.NamedStmt
+func (tx *Tx) PrepareNamedContext(ctx context.Context, query string) (*NamedStmt, error) {
+ return prepareNamedContext(ctx, tx, query)
+}
+
+// MustExecContext runs MustExecContext within a transaction.
+// Any placeholder parameters are replaced with supplied args.
+func (tx *Tx) MustExecContext(ctx context.Context, query string, args ...interface{}) sql.Result {
+ return MustExecContext(ctx, tx, query, args...)
+}
+
+// QueryxContext within a transaction and context.
+// Any placeholder parameters are replaced with supplied args.
+func (tx *Tx) QueryxContext(ctx context.Context, query string, args ...interface{}) (*Rows, error) {
+ r, err := tx.Tx.QueryContext(ctx, query, args...)
+ if err != nil {
+ return nil, err
+ }
+ return &Rows{Rows: r, unsafe: tx.unsafe, Mapper: tx.Mapper}, err
+}
+
+// SelectContext within a transaction and context.
+// Any placeholder parameters are replaced with supplied args.
+func (tx *Tx) SelectContext(ctx context.Context, dest interface{}, query string, args ...interface{}) error {
+ return SelectContext(ctx, tx, dest, query, args...)
+}
+
+// GetContext within a transaction and context.
+// Any placeholder parameters are replaced with supplied args.
+// An error is returned if the result set is empty.
+func (tx *Tx) GetContext(ctx context.Context, dest interface{}, query string, args ...interface{}) error {
+ return GetContext(ctx, tx, dest, query, args...)
+}
+
+// QueryRowxContext within a transaction and context.
+// Any placeholder parameters are replaced with supplied args.
+func (tx *Tx) QueryRowxContext(ctx context.Context, query string, args ...interface{}) *Row {
+ rows, err := tx.Tx.QueryContext(ctx, query, args...)
+ return &Row{rows: rows, err: err, unsafe: tx.unsafe, Mapper: tx.Mapper}
+}
+
+// NamedExecContext using this Tx.
+// Any named placeholder parameters are replaced with fields from arg.
+func (tx *Tx) NamedExecContext(ctx context.Context, query string, arg interface{}) (sql.Result, error) {
+ return NamedExecContext(ctx, tx, query, arg)
+}
+
+// SelectContext using the prepared statement.
+// Any placeholder parameters are replaced with supplied args.
+func (s *Stmt) SelectContext(ctx context.Context, dest interface{}, args ...interface{}) error {
+ return SelectContext(ctx, &qStmt{s}, dest, "", args...)
+}
+
+// GetContext using the prepared statement.
+// Any placeholder parameters are replaced with supplied args.
+// An error is returned if the result set is empty.
+func (s *Stmt) GetContext(ctx context.Context, dest interface{}, args ...interface{}) error {
+ return GetContext(ctx, &qStmt{s}, dest, "", args...)
+}
+
+// MustExecContext (panic) using this statement. Note that the query portion of
+// the error output will be blank, as Stmt does not expose its query.
+// Any placeholder parameters are replaced with supplied args.
+func (s *Stmt) MustExecContext(ctx context.Context, args ...interface{}) sql.Result {
+ return MustExecContext(ctx, &qStmt{s}, "", args...)
+}
+
+// QueryRowxContext using this statement.
+// Any placeholder parameters are replaced with supplied args.
+func (s *Stmt) QueryRowxContext(ctx context.Context, args ...interface{}) *Row {
+ qs := &qStmt{s}
+ return qs.QueryRowxContext(ctx, "", args...)
+}
+
+// QueryxContext using this statement.
+// Any placeholder parameters are replaced with supplied args.
+func (s *Stmt) QueryxContext(ctx context.Context, args ...interface{}) (*Rows, error) {
+ qs := &qStmt{s}
+ return qs.QueryxContext(ctx, "", args...)
+}
+
+func (q *qStmt) QueryContext(ctx context.Context, query string, args ...interface{}) (*sql.Rows, error) {
+ return q.Stmt.QueryContext(ctx, args...)
+}
+
+func (q *qStmt) QueryxContext(ctx context.Context, query string, args ...interface{}) (*Rows, error) {
+ r, err := q.Stmt.QueryContext(ctx, args...)
+ if err != nil {
+ return nil, err
+ }
+ return &Rows{Rows: r, unsafe: q.Stmt.unsafe, Mapper: q.Stmt.Mapper}, err
+}
+
+func (q *qStmt) QueryRowxContext(ctx context.Context, query string, args ...interface{}) *Row {
+ rows, err := q.Stmt.QueryContext(ctx, args...)
+ return &Row{rows: rows, err: err, unsafe: q.Stmt.unsafe, Mapper: q.Stmt.Mapper}
+}
+
+func (q *qStmt) ExecContext(ctx context.Context, query string, args ...interface{}) (sql.Result, error) {
+ return q.Stmt.ExecContext(ctx, args...)
+}
diff --git a/vendor/github.com/josharian/intern/README.md b/vendor/github.com/josharian/intern/README.md
new file mode 100644
index 0000000..ffc44b2
--- /dev/null
+++ b/vendor/github.com/josharian/intern/README.md
@@ -0,0 +1,5 @@
+Docs: https://godoc.org/github.com/josharian/intern
+
+See also [Go issue 5160](https://golang.org/issue/5160).
+
+License: MIT
diff --git a/vendor/github.com/josharian/intern/intern.go b/vendor/github.com/josharian/intern/intern.go
new file mode 100644
index 0000000..7acb1fe
--- /dev/null
+++ b/vendor/github.com/josharian/intern/intern.go
@@ -0,0 +1,44 @@
+// Package intern interns strings.
+// Interning is best effort only.
+// Interned strings may be removed automatically
+// at any time without notification.
+// All functions may be called concurrently
+// with themselves and each other.
+package intern
+
+import "sync"
+
+var (
+ pool sync.Pool = sync.Pool{
+ New: func() interface{} {
+ return make(map[string]string)
+ },
+ }
+)
+
+// String returns s, interned.
+func String(s string) string {
+ m := pool.Get().(map[string]string)
+ c, ok := m[s]
+ if ok {
+ pool.Put(m)
+ return c
+ }
+ m[s] = s
+ pool.Put(m)
+ return s
+}
+
+// Bytes returns b converted to a string, interned.
+func Bytes(b []byte) string {
+ m := pool.Get().(map[string]string)
+ c, ok := m[string(b)]
+ if ok {
+ pool.Put(m)
+ return c
+ }
+ s := string(b)
+ m[s] = s
+ pool.Put(m)
+ return s
+}
diff --git a/vendor/github.com/josharian/intern/license.md b/vendor/github.com/josharian/intern/license.md
new file mode 100644
index 0000000..353d305
--- /dev/null
+++ b/vendor/github.com/josharian/intern/license.md
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2019 Josh Bleecher Snyder
+
+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/klauspost/compress/LICENSE b/vendor/github.com/klauspost/compress/LICENSE
new file mode 100644
index 0000000..87d5574
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/LICENSE
@@ -0,0 +1,304 @@
+Copyright (c) 2012 The Go Authors. All rights reserved.
+Copyright (c) 2019 Klaus Post. 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.
+
+------------------
+
+Files: gzhttp/*
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright 2016-2017 The New York Times Company
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+------------------
+
+Files: s2/cmd/internal/readahead/*
+
+The MIT License (MIT)
+
+Copyright (c) 2015 Klaus Post
+
+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.
+
+---------------------
+Files: snappy/*
+Files: internal/snapref/*
+
+Copyright (c) 2011 The Snappy-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.
+
+-----------------
+
+Files: s2/cmd/internal/filepathx/*
+
+Copyright 2016 The filepathx Authors
+
+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/klauspost/compress/flate/deflate.go b/vendor/github.com/klauspost/compress/flate/deflate.go
new file mode 100644
index 0000000..66d1657
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/flate/deflate.go
@@ -0,0 +1,1017 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Copyright (c) 2015 Klaus Post
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package flate
+
+import (
+ "encoding/binary"
+ "errors"
+ "fmt"
+ "io"
+ "math"
+)
+
+const (
+ NoCompression = 0
+ BestSpeed = 1
+ BestCompression = 9
+ DefaultCompression = -1
+
+ // HuffmanOnly disables Lempel-Ziv match searching and only performs Huffman
+ // entropy encoding. This mode is useful in compressing data that has
+ // already been compressed with an LZ style algorithm (e.g. Snappy or LZ4)
+ // that lacks an entropy encoder. Compression gains are achieved when
+ // certain bytes in the input stream occur more frequently than others.
+ //
+ // Note that HuffmanOnly produces a compressed output that is
+ // RFC 1951 compliant. That is, any valid DEFLATE decompressor will
+ // continue to be able to decompress this output.
+ HuffmanOnly = -2
+ ConstantCompression = HuffmanOnly // compatibility alias.
+
+ logWindowSize = 15
+ windowSize = 1 << logWindowSize
+ windowMask = windowSize - 1
+ logMaxOffsetSize = 15 // Standard DEFLATE
+ minMatchLength = 4 // The smallest match that the compressor looks for
+ maxMatchLength = 258 // The longest match for the compressor
+ minOffsetSize = 1 // The shortest offset that makes any sense
+
+ // The maximum number of tokens we will encode at the time.
+ // Smaller sizes usually creates less optimal blocks.
+ // Bigger can make context switching slow.
+ // We use this for levels 7-9, so we make it big.
+ maxFlateBlockTokens = 1 << 15
+ maxStoreBlockSize = 65535
+ hashBits = 17 // After 17 performance degrades
+ hashSize = 1 << hashBits
+ hashMask = (1 << hashBits) - 1
+ hashShift = (hashBits + minMatchLength - 1) / minMatchLength
+ maxHashOffset = 1 << 28
+
+ skipNever = math.MaxInt32
+
+ debugDeflate = false
+)
+
+type compressionLevel struct {
+ good, lazy, nice, chain, fastSkipHashing, level int
+}
+
+// Compression levels have been rebalanced from zlib deflate defaults
+// to give a bigger spread in speed and compression.
+// See https://blog.klauspost.com/rebalancing-deflate-compression-levels/
+var levels = []compressionLevel{
+ {}, // 0
+ // Level 1-6 uses specialized algorithm - values not used
+ {0, 0, 0, 0, 0, 1},
+ {0, 0, 0, 0, 0, 2},
+ {0, 0, 0, 0, 0, 3},
+ {0, 0, 0, 0, 0, 4},
+ {0, 0, 0, 0, 0, 5},
+ {0, 0, 0, 0, 0, 6},
+ // Levels 7-9 use increasingly more lazy matching
+ // and increasingly stringent conditions for "good enough".
+ {8, 12, 16, 24, skipNever, 7},
+ {16, 30, 40, 64, skipNever, 8},
+ {32, 258, 258, 1024, skipNever, 9},
+}
+
+// advancedState contains state for the advanced levels, with bigger hash tables, etc.
+type advancedState struct {
+ // deflate state
+ length int
+ offset int
+ maxInsertIndex int
+ chainHead int
+ hashOffset int
+
+ ii uint16 // position of last match, intended to overflow to reset.
+
+ // input window: unprocessed data is window[index:windowEnd]
+ index int
+ hashMatch [maxMatchLength + minMatchLength]uint32
+
+ // Input hash chains
+ // hashHead[hashValue] contains the largest inputIndex with the specified hash value
+ // If hashHead[hashValue] is within the current window, then
+ // hashPrev[hashHead[hashValue] & windowMask] contains the previous index
+ // with the same hash value.
+ hashHead [hashSize]uint32
+ hashPrev [windowSize]uint32
+}
+
+type compressor struct {
+ compressionLevel
+
+ h *huffmanEncoder
+ w *huffmanBitWriter
+
+ // compression algorithm
+ fill func(*compressor, []byte) int // copy data to window
+ step func(*compressor) // process window
+
+ window []byte
+ windowEnd int
+ blockStart int // window index where current tokens start
+ err error
+
+ // queued output tokens
+ tokens tokens
+ fast fastEnc
+ state *advancedState
+
+ sync bool // requesting flush
+ byteAvailable bool // if true, still need to process window[index-1].
+}
+
+func (d *compressor) fillDeflate(b []byte) int {
+ s := d.state
+ if s.index >= 2*windowSize-(minMatchLength+maxMatchLength) {
+ // shift the window by windowSize
+ //copy(d.window[:], d.window[windowSize:2*windowSize])
+ *(*[windowSize]byte)(d.window) = *(*[windowSize]byte)(d.window[windowSize:])
+ s.index -= windowSize
+ d.windowEnd -= windowSize
+ if d.blockStart >= windowSize {
+ d.blockStart -= windowSize
+ } else {
+ d.blockStart = math.MaxInt32
+ }
+ s.hashOffset += windowSize
+ if s.hashOffset > maxHashOffset {
+ delta := s.hashOffset - 1
+ s.hashOffset -= delta
+ s.chainHead -= delta
+ // Iterate over slices instead of arrays to avoid copying
+ // the entire table onto the stack (Issue #18625).
+ for i, v := range s.hashPrev[:] {
+ if int(v) > delta {
+ s.hashPrev[i] = uint32(int(v) - delta)
+ } else {
+ s.hashPrev[i] = 0
+ }
+ }
+ for i, v := range s.hashHead[:] {
+ if int(v) > delta {
+ s.hashHead[i] = uint32(int(v) - delta)
+ } else {
+ s.hashHead[i] = 0
+ }
+ }
+ }
+ }
+ n := copy(d.window[d.windowEnd:], b)
+ d.windowEnd += n
+ return n
+}
+
+func (d *compressor) writeBlock(tok *tokens, index int, eof bool) error {
+ if index > 0 || eof {
+ var window []byte
+ if d.blockStart <= index {
+ window = d.window[d.blockStart:index]
+ }
+ d.blockStart = index
+ //d.w.writeBlock(tok, eof, window)
+ d.w.writeBlockDynamic(tok, eof, window, d.sync)
+ return d.w.err
+ }
+ return nil
+}
+
+// writeBlockSkip writes the current block and uses the number of tokens
+// to determine if the block should be stored on no matches, or
+// only huffman encoded.
+func (d *compressor) writeBlockSkip(tok *tokens, index int, eof bool) error {
+ if index > 0 || eof {
+ if d.blockStart <= index {
+ window := d.window[d.blockStart:index]
+ // If we removed less than a 64th of all literals
+ // we huffman compress the block.
+ if int(tok.n) > len(window)-int(tok.n>>6) {
+ d.w.writeBlockHuff(eof, window, d.sync)
+ } else {
+ // Write a dynamic huffman block.
+ d.w.writeBlockDynamic(tok, eof, window, d.sync)
+ }
+ } else {
+ d.w.writeBlock(tok, eof, nil)
+ }
+ d.blockStart = index
+ return d.w.err
+ }
+ return nil
+}
+
+// fillWindow will fill the current window with the supplied
+// dictionary and calculate all hashes.
+// This is much faster than doing a full encode.
+// Should only be used after a start/reset.
+func (d *compressor) fillWindow(b []byte) {
+ // Do not fill window if we are in store-only or huffman mode.
+ if d.level <= 0 && d.level > -MinCustomWindowSize {
+ return
+ }
+ if d.fast != nil {
+ // encode the last data, but discard the result
+ if len(b) > maxMatchOffset {
+ b = b[len(b)-maxMatchOffset:]
+ }
+ d.fast.Encode(&d.tokens, b)
+ d.tokens.Reset()
+ return
+ }
+ s := d.state
+ // If we are given too much, cut it.
+ if len(b) > windowSize {
+ b = b[len(b)-windowSize:]
+ }
+ // Add all to window.
+ n := copy(d.window[d.windowEnd:], b)
+
+ // Calculate 256 hashes at the time (more L1 cache hits)
+ loops := (n + 256 - minMatchLength) / 256
+ for j := 0; j < loops; j++ {
+ startindex := j * 256
+ end := startindex + 256 + minMatchLength - 1
+ if end > n {
+ end = n
+ }
+ tocheck := d.window[startindex:end]
+ dstSize := len(tocheck) - minMatchLength + 1
+
+ if dstSize <= 0 {
+ continue
+ }
+
+ dst := s.hashMatch[:dstSize]
+ bulkHash4(tocheck, dst)
+ var newH uint32
+ for i, val := range dst {
+ di := i + startindex
+ newH = val & hashMask
+ // Get previous value with the same hash.
+ // Our chain should point to the previous value.
+ s.hashPrev[di&windowMask] = s.hashHead[newH]
+ // Set the head of the hash chain to us.
+ s.hashHead[newH] = uint32(di + s.hashOffset)
+ }
+ }
+ // Update window information.
+ d.windowEnd += n
+ s.index = n
+}
+
+// Try to find a match starting at index whose length is greater than prevSize.
+// We only look at chainCount possibilities before giving up.
+// pos = s.index, prevHead = s.chainHead-s.hashOffset, prevLength=minMatchLength-1, lookahead
+func (d *compressor) findMatch(pos int, prevHead int, lookahead int) (length, offset int, ok bool) {
+ minMatchLook := maxMatchLength
+ if lookahead < minMatchLook {
+ minMatchLook = lookahead
+ }
+
+ win := d.window[0 : pos+minMatchLook]
+
+ // We quit when we get a match that's at least nice long
+ nice := len(win) - pos
+ if d.nice < nice {
+ nice = d.nice
+ }
+
+ // If we've got a match that's good enough, only look in 1/4 the chain.
+ tries := d.chain
+ length = minMatchLength - 1
+
+ wEnd := win[pos+length]
+ wPos := win[pos:]
+ minIndex := pos - windowSize
+ if minIndex < 0 {
+ minIndex = 0
+ }
+ offset = 0
+
+ if d.chain < 100 {
+ for i := prevHead; tries > 0; tries-- {
+ if wEnd == win[i+length] {
+ n := matchLen(win[i:i+minMatchLook], wPos)
+ if n > length {
+ length = n
+ offset = pos - i
+ ok = true
+ if n >= nice {
+ // The match is good enough that we don't try to find a better one.
+ break
+ }
+ wEnd = win[pos+n]
+ }
+ }
+ if i <= minIndex {
+ // hashPrev[i & windowMask] has already been overwritten, so stop now.
+ break
+ }
+ i = int(d.state.hashPrev[i&windowMask]) - d.state.hashOffset
+ if i < minIndex {
+ break
+ }
+ }
+ return
+ }
+
+ // Minimum gain to accept a match.
+ cGain := 4
+
+ // Some like it higher (CSV), some like it lower (JSON)
+ const baseCost = 3
+ // Base is 4 bytes at with an additional cost.
+ // Matches must be better than this.
+
+ for i := prevHead; tries > 0; tries-- {
+ if wEnd == win[i+length] {
+ n := matchLen(win[i:i+minMatchLook], wPos)
+ if n > length {
+ // Calculate gain. Estimate
+ newGain := d.h.bitLengthRaw(wPos[:n]) - int(offsetExtraBits[offsetCode(uint32(pos-i))]) - baseCost - int(lengthExtraBits[lengthCodes[(n-3)&255]])
+
+ //fmt.Println("gain:", newGain, "prev:", cGain, "raw:", d.h.bitLengthRaw(wPos[:n]), "this-len:", n, "prev-len:", length)
+ if newGain > cGain {
+ length = n
+ offset = pos - i
+ cGain = newGain
+ ok = true
+ if n >= nice {
+ // The match is good enough that we don't try to find a better one.
+ break
+ }
+ wEnd = win[pos+n]
+ }
+ }
+ }
+ if i <= minIndex {
+ // hashPrev[i & windowMask] has already been overwritten, so stop now.
+ break
+ }
+ i = int(d.state.hashPrev[i&windowMask]) - d.state.hashOffset
+ if i < minIndex {
+ break
+ }
+ }
+ return
+}
+
+func (d *compressor) writeStoredBlock(buf []byte) error {
+ if d.w.writeStoredHeader(len(buf), false); d.w.err != nil {
+ return d.w.err
+ }
+ d.w.writeBytes(buf)
+ return d.w.err
+}
+
+// hash4 returns a hash representation of the first 4 bytes
+// of the supplied slice.
+// The caller must ensure that len(b) >= 4.
+func hash4(b []byte) uint32 {
+ return hash4u(binary.LittleEndian.Uint32(b), hashBits)
+}
+
+// hash4 returns the hash of u to fit in a hash table with h bits.
+// Preferably h should be a constant and should always be <32.
+func hash4u(u uint32, h uint8) uint32 {
+ return (u * prime4bytes) >> (32 - h)
+}
+
+// bulkHash4 will compute hashes using the same
+// algorithm as hash4
+func bulkHash4(b []byte, dst []uint32) {
+ if len(b) < 4 {
+ return
+ }
+ hb := binary.LittleEndian.Uint32(b)
+
+ dst[0] = hash4u(hb, hashBits)
+ end := len(b) - 4 + 1
+ for i := 1; i < end; i++ {
+ hb = (hb >> 8) | uint32(b[i+3])<<24
+ dst[i] = hash4u(hb, hashBits)
+ }
+}
+
+func (d *compressor) initDeflate() {
+ d.window = make([]byte, 2*windowSize)
+ d.byteAvailable = false
+ d.err = nil
+ if d.state == nil {
+ return
+ }
+ s := d.state
+ s.index = 0
+ s.hashOffset = 1
+ s.length = minMatchLength - 1
+ s.offset = 0
+ s.chainHead = -1
+}
+
+// deflateLazy is the same as deflate, but with d.fastSkipHashing == skipNever,
+// meaning it always has lazy matching on.
+func (d *compressor) deflateLazy() {
+ s := d.state
+ // Sanity enables additional runtime tests.
+ // It's intended to be used during development
+ // to supplement the currently ad-hoc unit tests.
+ const sanity = debugDeflate
+
+ if d.windowEnd-s.index < minMatchLength+maxMatchLength && !d.sync {
+ return
+ }
+ if d.windowEnd != s.index && d.chain > 100 {
+ // Get literal huffman coder.
+ if d.h == nil {
+ d.h = newHuffmanEncoder(maxFlateBlockTokens)
+ }
+ var tmp [256]uint16
+ for _, v := range d.window[s.index:d.windowEnd] {
+ tmp[v]++
+ }
+ d.h.generate(tmp[:], 15)
+ }
+
+ s.maxInsertIndex = d.windowEnd - (minMatchLength - 1)
+
+ for {
+ if sanity && s.index > d.windowEnd {
+ panic("index > windowEnd")
+ }
+ lookahead := d.windowEnd - s.index
+ if lookahead < minMatchLength+maxMatchLength {
+ if !d.sync {
+ return
+ }
+ if sanity && s.index > d.windowEnd {
+ panic("index > windowEnd")
+ }
+ if lookahead == 0 {
+ // Flush current output block if any.
+ if d.byteAvailable {
+ // There is still one pending token that needs to be flushed
+ d.tokens.AddLiteral(d.window[s.index-1])
+ d.byteAvailable = false
+ }
+ if d.tokens.n > 0 {
+ if d.err = d.writeBlock(&d.tokens, s.index, false); d.err != nil {
+ return
+ }
+ d.tokens.Reset()
+ }
+ return
+ }
+ }
+ if s.index < s.maxInsertIndex {
+ // Update the hash
+ hash := hash4(d.window[s.index:])
+ ch := s.hashHead[hash]
+ s.chainHead = int(ch)
+ s.hashPrev[s.index&windowMask] = ch
+ s.hashHead[hash] = uint32(s.index + s.hashOffset)
+ }
+ prevLength := s.length
+ prevOffset := s.offset
+ s.length = minMatchLength - 1
+ s.offset = 0
+ minIndex := s.index - windowSize
+ if minIndex < 0 {
+ minIndex = 0
+ }
+
+ if s.chainHead-s.hashOffset >= minIndex && lookahead > prevLength && prevLength < d.lazy {
+ if newLength, newOffset, ok := d.findMatch(s.index, s.chainHead-s.hashOffset, lookahead); ok {
+ s.length = newLength
+ s.offset = newOffset
+ }
+ }
+
+ if prevLength >= minMatchLength && s.length <= prevLength {
+ // No better match, but check for better match at end...
+ //
+ // Skip forward a number of bytes.
+ // Offset of 2 seems to yield best results. 3 is sometimes better.
+ const checkOff = 2
+
+ // Check all, except full length
+ if prevLength < maxMatchLength-checkOff {
+ prevIndex := s.index - 1
+ if prevIndex+prevLength < s.maxInsertIndex {
+ end := lookahead
+ if lookahead > maxMatchLength+checkOff {
+ end = maxMatchLength + checkOff
+ }
+ end += prevIndex
+
+ // Hash at match end.
+ h := hash4(d.window[prevIndex+prevLength:])
+ ch2 := int(s.hashHead[h]) - s.hashOffset - prevLength
+ if prevIndex-ch2 != prevOffset && ch2 > minIndex+checkOff {
+ length := matchLen(d.window[prevIndex+checkOff:end], d.window[ch2+checkOff:])
+ // It seems like a pure length metric is best.
+ if length > prevLength {
+ prevLength = length
+ prevOffset = prevIndex - ch2
+
+ // Extend back...
+ for i := checkOff - 1; i >= 0; i-- {
+ if prevLength >= maxMatchLength || d.window[prevIndex+i] != d.window[ch2+i] {
+ // Emit tokens we "owe"
+ for j := 0; j <= i; j++ {
+ d.tokens.AddLiteral(d.window[prevIndex+j])
+ if d.tokens.n == maxFlateBlockTokens {
+ // The block includes the current character
+ if d.err = d.writeBlock(&d.tokens, s.index, false); d.err != nil {
+ return
+ }
+ d.tokens.Reset()
+ }
+ s.index++
+ if s.index < s.maxInsertIndex {
+ h := hash4(d.window[s.index:])
+ ch := s.hashHead[h]
+ s.chainHead = int(ch)
+ s.hashPrev[s.index&windowMask] = ch
+ s.hashHead[h] = uint32(s.index + s.hashOffset)
+ }
+ }
+ break
+ } else {
+ prevLength++
+ }
+ }
+ } else if false {
+ // Check one further ahead.
+ // Only rarely better, disabled for now.
+ prevIndex++
+ h := hash4(d.window[prevIndex+prevLength:])
+ ch2 := int(s.hashHead[h]) - s.hashOffset - prevLength
+ if prevIndex-ch2 != prevOffset && ch2 > minIndex+checkOff {
+ length := matchLen(d.window[prevIndex+checkOff:end], d.window[ch2+checkOff:])
+ // It seems like a pure length metric is best.
+ if length > prevLength+checkOff {
+ prevLength = length
+ prevOffset = prevIndex - ch2
+ prevIndex--
+
+ // Extend back...
+ for i := checkOff; i >= 0; i-- {
+ if prevLength >= maxMatchLength || d.window[prevIndex+i] != d.window[ch2+i-1] {
+ // Emit tokens we "owe"
+ for j := 0; j <= i; j++ {
+ d.tokens.AddLiteral(d.window[prevIndex+j])
+ if d.tokens.n == maxFlateBlockTokens {
+ // The block includes the current character
+ if d.err = d.writeBlock(&d.tokens, s.index, false); d.err != nil {
+ return
+ }
+ d.tokens.Reset()
+ }
+ s.index++
+ if s.index < s.maxInsertIndex {
+ h := hash4(d.window[s.index:])
+ ch := s.hashHead[h]
+ s.chainHead = int(ch)
+ s.hashPrev[s.index&windowMask] = ch
+ s.hashHead[h] = uint32(s.index + s.hashOffset)
+ }
+ }
+ break
+ } else {
+ prevLength++
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ // There was a match at the previous step, and the current match is
+ // not better. Output the previous match.
+ d.tokens.AddMatch(uint32(prevLength-3), uint32(prevOffset-minOffsetSize))
+
+ // Insert in the hash table all strings up to the end of the match.
+ // index and index-1 are already inserted. If there is not enough
+ // lookahead, the last two strings are not inserted into the hash
+ // table.
+ newIndex := s.index + prevLength - 1
+ // Calculate missing hashes
+ end := newIndex
+ if end > s.maxInsertIndex {
+ end = s.maxInsertIndex
+ }
+ end += minMatchLength - 1
+ startindex := s.index + 1
+ if startindex > s.maxInsertIndex {
+ startindex = s.maxInsertIndex
+ }
+ tocheck := d.window[startindex:end]
+ dstSize := len(tocheck) - minMatchLength + 1
+ if dstSize > 0 {
+ dst := s.hashMatch[:dstSize]
+ bulkHash4(tocheck, dst)
+ var newH uint32
+ for i, val := range dst {
+ di := i + startindex
+ newH = val & hashMask
+ // Get previous value with the same hash.
+ // Our chain should point to the previous value.
+ s.hashPrev[di&windowMask] = s.hashHead[newH]
+ // Set the head of the hash chain to us.
+ s.hashHead[newH] = uint32(di + s.hashOffset)
+ }
+ }
+
+ s.index = newIndex
+ d.byteAvailable = false
+ s.length = minMatchLength - 1
+ if d.tokens.n == maxFlateBlockTokens {
+ // The block includes the current character
+ if d.err = d.writeBlock(&d.tokens, s.index, false); d.err != nil {
+ return
+ }
+ d.tokens.Reset()
+ }
+ s.ii = 0
+ } else {
+ // Reset, if we got a match this run.
+ if s.length >= minMatchLength {
+ s.ii = 0
+ }
+ // We have a byte waiting. Emit it.
+ if d.byteAvailable {
+ s.ii++
+ d.tokens.AddLiteral(d.window[s.index-1])
+ if d.tokens.n == maxFlateBlockTokens {
+ if d.err = d.writeBlock(&d.tokens, s.index, false); d.err != nil {
+ return
+ }
+ d.tokens.Reset()
+ }
+ s.index++
+
+ // If we have a long run of no matches, skip additional bytes
+ // Resets when s.ii overflows after 64KB.
+ if n := int(s.ii) - d.chain; n > 0 {
+ n = 1 + int(n>>6)
+ for j := 0; j < n; j++ {
+ if s.index >= d.windowEnd-1 {
+ break
+ }
+ d.tokens.AddLiteral(d.window[s.index-1])
+ if d.tokens.n == maxFlateBlockTokens {
+ if d.err = d.writeBlock(&d.tokens, s.index, false); d.err != nil {
+ return
+ }
+ d.tokens.Reset()
+ }
+ // Index...
+ if s.index < s.maxInsertIndex {
+ h := hash4(d.window[s.index:])
+ ch := s.hashHead[h]
+ s.chainHead = int(ch)
+ s.hashPrev[s.index&windowMask] = ch
+ s.hashHead[h] = uint32(s.index + s.hashOffset)
+ }
+ s.index++
+ }
+ // Flush last byte
+ d.tokens.AddLiteral(d.window[s.index-1])
+ d.byteAvailable = false
+ // s.length = minMatchLength - 1 // not needed, since s.ii is reset above, so it should never be > minMatchLength
+ if d.tokens.n == maxFlateBlockTokens {
+ if d.err = d.writeBlock(&d.tokens, s.index, false); d.err != nil {
+ return
+ }
+ d.tokens.Reset()
+ }
+ }
+ } else {
+ s.index++
+ d.byteAvailable = true
+ }
+ }
+ }
+}
+
+func (d *compressor) store() {
+ if d.windowEnd > 0 && (d.windowEnd == maxStoreBlockSize || d.sync) {
+ d.err = d.writeStoredBlock(d.window[:d.windowEnd])
+ d.windowEnd = 0
+ }
+}
+
+// fillWindow will fill the buffer with data for huffman-only compression.
+// The number of bytes copied is returned.
+func (d *compressor) fillBlock(b []byte) int {
+ n := copy(d.window[d.windowEnd:], b)
+ d.windowEnd += n
+ return n
+}
+
+// storeHuff will compress and store the currently added data,
+// if enough has been accumulated or we at the end of the stream.
+// Any error that occurred will be in d.err
+func (d *compressor) storeHuff() {
+ if d.windowEnd < len(d.window) && !d.sync || d.windowEnd == 0 {
+ return
+ }
+ d.w.writeBlockHuff(false, d.window[:d.windowEnd], d.sync)
+ d.err = d.w.err
+ d.windowEnd = 0
+}
+
+// storeFast will compress and store the currently added data,
+// if enough has been accumulated or we at the end of the stream.
+// Any error that occurred will be in d.err
+func (d *compressor) storeFast() {
+ // We only compress if we have maxStoreBlockSize.
+ if d.windowEnd < len(d.window) {
+ if !d.sync {
+ return
+ }
+ // Handle extremely small sizes.
+ if d.windowEnd < 128 {
+ if d.windowEnd == 0 {
+ return
+ }
+ if d.windowEnd <= 32 {
+ d.err = d.writeStoredBlock(d.window[:d.windowEnd])
+ } else {
+ d.w.writeBlockHuff(false, d.window[:d.windowEnd], true)
+ d.err = d.w.err
+ }
+ d.tokens.Reset()
+ d.windowEnd = 0
+ d.fast.Reset()
+ return
+ }
+ }
+
+ d.fast.Encode(&d.tokens, d.window[:d.windowEnd])
+ // If we made zero matches, store the block as is.
+ if d.tokens.n == 0 {
+ d.err = d.writeStoredBlock(d.window[:d.windowEnd])
+ // If we removed less than 1/16th, huffman compress the block.
+ } else if int(d.tokens.n) > d.windowEnd-(d.windowEnd>>4) {
+ d.w.writeBlockHuff(false, d.window[:d.windowEnd], d.sync)
+ d.err = d.w.err
+ } else {
+ d.w.writeBlockDynamic(&d.tokens, false, d.window[:d.windowEnd], d.sync)
+ d.err = d.w.err
+ }
+ d.tokens.Reset()
+ d.windowEnd = 0
+}
+
+// write will add input byte to the stream.
+// Unless an error occurs all bytes will be consumed.
+func (d *compressor) write(b []byte) (n int, err error) {
+ if d.err != nil {
+ return 0, d.err
+ }
+ n = len(b)
+ for len(b) > 0 {
+ if d.windowEnd == len(d.window) || d.sync {
+ d.step(d)
+ }
+ b = b[d.fill(d, b):]
+ if d.err != nil {
+ return 0, d.err
+ }
+ }
+ return n, d.err
+}
+
+func (d *compressor) syncFlush() error {
+ d.sync = true
+ if d.err != nil {
+ return d.err
+ }
+ d.step(d)
+ if d.err == nil {
+ d.w.writeStoredHeader(0, false)
+ d.w.flush()
+ d.err = d.w.err
+ }
+ d.sync = false
+ return d.err
+}
+
+func (d *compressor) init(w io.Writer, level int) (err error) {
+ d.w = newHuffmanBitWriter(w)
+
+ switch {
+ case level == NoCompression:
+ d.window = make([]byte, maxStoreBlockSize)
+ d.fill = (*compressor).fillBlock
+ d.step = (*compressor).store
+ case level == ConstantCompression:
+ d.w.logNewTablePenalty = 10
+ d.window = make([]byte, 32<<10)
+ d.fill = (*compressor).fillBlock
+ d.step = (*compressor).storeHuff
+ case level == DefaultCompression:
+ level = 5
+ fallthrough
+ case level >= 1 && level <= 6:
+ d.w.logNewTablePenalty = 7
+ d.fast = newFastEnc(level)
+ d.window = make([]byte, maxStoreBlockSize)
+ d.fill = (*compressor).fillBlock
+ d.step = (*compressor).storeFast
+ case 7 <= level && level <= 9:
+ d.w.logNewTablePenalty = 8
+ d.state = &advancedState{}
+ d.compressionLevel = levels[level]
+ d.initDeflate()
+ d.fill = (*compressor).fillDeflate
+ d.step = (*compressor).deflateLazy
+ case -level >= MinCustomWindowSize && -level <= MaxCustomWindowSize:
+ d.w.logNewTablePenalty = 7
+ d.fast = &fastEncL5Window{maxOffset: int32(-level), cur: maxStoreBlockSize}
+ d.window = make([]byte, maxStoreBlockSize)
+ d.fill = (*compressor).fillBlock
+ d.step = (*compressor).storeFast
+ default:
+ return fmt.Errorf("flate: invalid compression level %d: want value in range [-2, 9]", level)
+ }
+ d.level = level
+ return nil
+}
+
+// reset the state of the compressor.
+func (d *compressor) reset(w io.Writer) {
+ d.w.reset(w)
+ d.sync = false
+ d.err = nil
+ // We only need to reset a few things for Snappy.
+ if d.fast != nil {
+ d.fast.Reset()
+ d.windowEnd = 0
+ d.tokens.Reset()
+ return
+ }
+ switch d.compressionLevel.chain {
+ case 0:
+ // level was NoCompression or ConstantCompresssion.
+ d.windowEnd = 0
+ default:
+ s := d.state
+ s.chainHead = -1
+ for i := range s.hashHead {
+ s.hashHead[i] = 0
+ }
+ for i := range s.hashPrev {
+ s.hashPrev[i] = 0
+ }
+ s.hashOffset = 1
+ s.index, d.windowEnd = 0, 0
+ d.blockStart, d.byteAvailable = 0, false
+ d.tokens.Reset()
+ s.length = minMatchLength - 1
+ s.offset = 0
+ s.ii = 0
+ s.maxInsertIndex = 0
+ }
+}
+
+func (d *compressor) close() error {
+ if d.err != nil {
+ return d.err
+ }
+ d.sync = true
+ d.step(d)
+ if d.err != nil {
+ return d.err
+ }
+ if d.w.writeStoredHeader(0, true); d.w.err != nil {
+ return d.w.err
+ }
+ d.w.flush()
+ d.w.reset(nil)
+ return d.w.err
+}
+
+// NewWriter returns a new Writer compressing data at the given level.
+// Following zlib, levels range from 1 (BestSpeed) to 9 (BestCompression);
+// higher levels typically run slower but compress more.
+// Level 0 (NoCompression) does not attempt any compression; it only adds the
+// necessary DEFLATE framing.
+// Level -1 (DefaultCompression) uses the default compression level.
+// Level -2 (ConstantCompression) will use Huffman compression only, giving
+// a very fast compression for all types of input, but sacrificing considerable
+// compression efficiency.
+//
+// If level is in the range [-2, 9] then the error returned will be nil.
+// Otherwise the error returned will be non-nil.
+func NewWriter(w io.Writer, level int) (*Writer, error) {
+ var dw Writer
+ if err := dw.d.init(w, level); err != nil {
+ return nil, err
+ }
+ return &dw, nil
+}
+
+// NewWriterDict is like NewWriter but initializes the new
+// Writer with a preset dictionary. The returned Writer behaves
+// as if the dictionary had been written to it without producing
+// any compressed output. The compressed data written to w
+// can only be decompressed by a Reader initialized with the
+// same dictionary.
+func NewWriterDict(w io.Writer, level int, dict []byte) (*Writer, error) {
+ zw, err := NewWriter(w, level)
+ if err != nil {
+ return nil, err
+ }
+ zw.d.fillWindow(dict)
+ zw.dict = append(zw.dict, dict...) // duplicate dictionary for Reset method.
+ return zw, err
+}
+
+// MinCustomWindowSize is the minimum window size that can be sent to NewWriterWindow.
+const MinCustomWindowSize = 32
+
+// MaxCustomWindowSize is the maximum custom window that can be sent to NewWriterWindow.
+const MaxCustomWindowSize = windowSize
+
+// NewWriterWindow returns a new Writer compressing data with a custom window size.
+// windowSize must be from MinCustomWindowSize to MaxCustomWindowSize.
+func NewWriterWindow(w io.Writer, windowSize int) (*Writer, error) {
+ if windowSize < MinCustomWindowSize {
+ return nil, errors.New("flate: requested window size less than MinWindowSize")
+ }
+ if windowSize > MaxCustomWindowSize {
+ return nil, errors.New("flate: requested window size bigger than MaxCustomWindowSize")
+ }
+ var dw Writer
+ if err := dw.d.init(w, -windowSize); err != nil {
+ return nil, err
+ }
+ return &dw, nil
+}
+
+// A Writer takes data written to it and writes the compressed
+// form of that data to an underlying writer (see NewWriter).
+type Writer struct {
+ d compressor
+ dict []byte
+}
+
+// Write writes data to w, which will eventually write the
+// compressed form of data to its underlying writer.
+func (w *Writer) Write(data []byte) (n int, err error) {
+ return w.d.write(data)
+}
+
+// Flush flushes any pending data to the underlying writer.
+// It is useful mainly in compressed network protocols, to ensure that
+// a remote reader has enough data to reconstruct a packet.
+// Flush does not return until the data has been written.
+// Calling Flush when there is no pending data still causes the Writer
+// to emit a sync marker of at least 4 bytes.
+// If the underlying writer returns an error, Flush returns that error.
+//
+// In the terminology of the zlib library, Flush is equivalent to Z_SYNC_FLUSH.
+func (w *Writer) Flush() error {
+ // For more about flushing:
+ // http://www.bolet.org/~pornin/deflate-flush.html
+ return w.d.syncFlush()
+}
+
+// Close flushes and closes the writer.
+func (w *Writer) Close() error {
+ return w.d.close()
+}
+
+// Reset discards the writer's state and makes it equivalent to
+// the result of NewWriter or NewWriterDict called with dst
+// and w's level and dictionary.
+func (w *Writer) Reset(dst io.Writer) {
+ if len(w.dict) > 0 {
+ // w was created with NewWriterDict
+ w.d.reset(dst)
+ if dst != nil {
+ w.d.fillWindow(w.dict)
+ }
+ } else {
+ // w was created with NewWriter
+ w.d.reset(dst)
+ }
+}
+
+// ResetDict discards the writer's state and makes it equivalent to
+// the result of NewWriter or NewWriterDict called with dst
+// and w's level, but sets a specific dictionary.
+func (w *Writer) ResetDict(dst io.Writer, dict []byte) {
+ w.dict = dict
+ w.d.reset(dst)
+ w.d.fillWindow(w.dict)
+}
diff --git a/vendor/github.com/klauspost/compress/flate/dict_decoder.go b/vendor/github.com/klauspost/compress/flate/dict_decoder.go
new file mode 100644
index 0000000..bb36351
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/flate/dict_decoder.go
@@ -0,0 +1,184 @@
+// Copyright 2016 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 flate
+
+// dictDecoder implements the LZ77 sliding dictionary as used in decompression.
+// LZ77 decompresses data through sequences of two forms of commands:
+//
+// - Literal insertions: Runs of one or more symbols are inserted into the data
+// stream as is. This is accomplished through the writeByte method for a
+// single symbol, or combinations of writeSlice/writeMark for multiple symbols.
+// Any valid stream must start with a literal insertion if no preset dictionary
+// is used.
+//
+// - Backward copies: Runs of one or more symbols are copied from previously
+// emitted data. Backward copies come as the tuple (dist, length) where dist
+// determines how far back in the stream to copy from and length determines how
+// many bytes to copy. Note that it is valid for the length to be greater than
+// the distance. Since LZ77 uses forward copies, that situation is used to
+// perform a form of run-length encoding on repeated runs of symbols.
+// The writeCopy and tryWriteCopy are used to implement this command.
+//
+// For performance reasons, this implementation performs little to no sanity
+// checks about the arguments. As such, the invariants documented for each
+// method call must be respected.
+type dictDecoder struct {
+ hist []byte // Sliding window history
+
+ // Invariant: 0 <= rdPos <= wrPos <= len(hist)
+ wrPos int // Current output position in buffer
+ rdPos int // Have emitted hist[:rdPos] already
+ full bool // Has a full window length been written yet?
+}
+
+// init initializes dictDecoder to have a sliding window dictionary of the given
+// size. If a preset dict is provided, it will initialize the dictionary with
+// the contents of dict.
+func (dd *dictDecoder) init(size int, dict []byte) {
+ *dd = dictDecoder{hist: dd.hist}
+
+ if cap(dd.hist) < size {
+ dd.hist = make([]byte, size)
+ }
+ dd.hist = dd.hist[:size]
+
+ if len(dict) > len(dd.hist) {
+ dict = dict[len(dict)-len(dd.hist):]
+ }
+ dd.wrPos = copy(dd.hist, dict)
+ if dd.wrPos == len(dd.hist) {
+ dd.wrPos = 0
+ dd.full = true
+ }
+ dd.rdPos = dd.wrPos
+}
+
+// histSize reports the total amount of historical data in the dictionary.
+func (dd *dictDecoder) histSize() int {
+ if dd.full {
+ return len(dd.hist)
+ }
+ return dd.wrPos
+}
+
+// availRead reports the number of bytes that can be flushed by readFlush.
+func (dd *dictDecoder) availRead() int {
+ return dd.wrPos - dd.rdPos
+}
+
+// availWrite reports the available amount of output buffer space.
+func (dd *dictDecoder) availWrite() int {
+ return len(dd.hist) - dd.wrPos
+}
+
+// writeSlice returns a slice of the available buffer to write data to.
+//
+// This invariant will be kept: len(s) <= availWrite()
+func (dd *dictDecoder) writeSlice() []byte {
+ return dd.hist[dd.wrPos:]
+}
+
+// writeMark advances the writer pointer by cnt.
+//
+// This invariant must be kept: 0 <= cnt <= availWrite()
+func (dd *dictDecoder) writeMark(cnt int) {
+ dd.wrPos += cnt
+}
+
+// writeByte writes a single byte to the dictionary.
+//
+// This invariant must be kept: 0 < availWrite()
+func (dd *dictDecoder) writeByte(c byte) {
+ dd.hist[dd.wrPos] = c
+ dd.wrPos++
+}
+
+// writeCopy copies a string at a given (dist, length) to the output.
+// This returns the number of bytes copied and may be less than the requested
+// length if the available space in the output buffer is too small.
+//
+// This invariant must be kept: 0 < dist <= histSize()
+func (dd *dictDecoder) writeCopy(dist, length int) int {
+ dstBase := dd.wrPos
+ dstPos := dstBase
+ srcPos := dstPos - dist
+ endPos := dstPos + length
+ if endPos > len(dd.hist) {
+ endPos = len(dd.hist)
+ }
+
+ // Copy non-overlapping section after destination position.
+ //
+ // This section is non-overlapping in that the copy length for this section
+ // is always less than or equal to the backwards distance. This can occur
+ // if a distance refers to data that wraps-around in the buffer.
+ // Thus, a backwards copy is performed here; that is, the exact bytes in
+ // the source prior to the copy is placed in the destination.
+ if srcPos < 0 {
+ srcPos += len(dd.hist)
+ dstPos += copy(dd.hist[dstPos:endPos], dd.hist[srcPos:])
+ srcPos = 0
+ }
+
+ // Copy possibly overlapping section before destination position.
+ //
+ // This section can overlap if the copy length for this section is larger
+ // than the backwards distance. This is allowed by LZ77 so that repeated
+ // strings can be succinctly represented using (dist, length) pairs.
+ // Thus, a forwards copy is performed here; that is, the bytes copied is
+ // possibly dependent on the resulting bytes in the destination as the copy
+ // progresses along. This is functionally equivalent to the following:
+ //
+ // for i := 0; i < endPos-dstPos; i++ {
+ // dd.hist[dstPos+i] = dd.hist[srcPos+i]
+ // }
+ // dstPos = endPos
+ //
+ for dstPos < endPos {
+ dstPos += copy(dd.hist[dstPos:endPos], dd.hist[srcPos:dstPos])
+ }
+
+ dd.wrPos = dstPos
+ return dstPos - dstBase
+}
+
+// tryWriteCopy tries to copy a string at a given (distance, length) to the
+// output. This specialized version is optimized for short distances.
+//
+// This method is designed to be inlined for performance reasons.
+//
+// This invariant must be kept: 0 < dist <= histSize()
+func (dd *dictDecoder) tryWriteCopy(dist, length int) int {
+ dstPos := dd.wrPos
+ endPos := dstPos + length
+ if dstPos < dist || endPos > len(dd.hist) {
+ return 0
+ }
+ dstBase := dstPos
+ srcPos := dstPos - dist
+
+ // Copy possibly overlapping section before destination position.
+loop:
+ dstPos += copy(dd.hist[dstPos:endPos], dd.hist[srcPos:dstPos])
+ if dstPos < endPos {
+ goto loop // Avoid for-loop so that this function can be inlined
+ }
+
+ dd.wrPos = dstPos
+ return dstPos - dstBase
+}
+
+// readFlush returns a slice of the historical buffer that is ready to be
+// emitted to the user. The data returned by readFlush must be fully consumed
+// before calling any other dictDecoder methods.
+func (dd *dictDecoder) readFlush() []byte {
+ toRead := dd.hist[dd.rdPos:dd.wrPos]
+ dd.rdPos = dd.wrPos
+ if dd.wrPos == len(dd.hist) {
+ dd.wrPos, dd.rdPos = 0, 0
+ dd.full = true
+ }
+ return toRead
+}
diff --git a/vendor/github.com/klauspost/compress/flate/fast_encoder.go b/vendor/github.com/klauspost/compress/flate/fast_encoder.go
new file mode 100644
index 0000000..c8124b5
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/flate/fast_encoder.go
@@ -0,0 +1,193 @@
+// Copyright 2011 The Snappy-Go Authors. All rights reserved.
+// Modified for deflate by Klaus Post (c) 2015.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package flate
+
+import (
+ "encoding/binary"
+ "fmt"
+)
+
+type fastEnc interface {
+ Encode(dst *tokens, src []byte)
+ Reset()
+}
+
+func newFastEnc(level int) fastEnc {
+ switch level {
+ case 1:
+ return &fastEncL1{fastGen: fastGen{cur: maxStoreBlockSize}}
+ case 2:
+ return &fastEncL2{fastGen: fastGen{cur: maxStoreBlockSize}}
+ case 3:
+ return &fastEncL3{fastGen: fastGen{cur: maxStoreBlockSize}}
+ case 4:
+ return &fastEncL4{fastGen: fastGen{cur: maxStoreBlockSize}}
+ case 5:
+ return &fastEncL5{fastGen: fastGen{cur: maxStoreBlockSize}}
+ case 6:
+ return &fastEncL6{fastGen: fastGen{cur: maxStoreBlockSize}}
+ default:
+ panic("invalid level specified")
+ }
+}
+
+const (
+ tableBits = 15 // Bits used in the table
+ tableSize = 1 << tableBits // Size of the table
+ tableShift = 32 - tableBits // Right-shift to get the tableBits most significant bits of a uint32.
+ baseMatchOffset = 1 // The smallest match offset
+ baseMatchLength = 3 // The smallest match length per the RFC section 3.2.5
+ maxMatchOffset = 1 << 15 // The largest match offset
+
+ bTableBits = 17 // Bits used in the big tables
+ bTableSize = 1 << bTableBits // Size of the table
+ allocHistory = maxStoreBlockSize * 5 // Size to preallocate for history.
+ bufferReset = (1 << 31) - allocHistory - maxStoreBlockSize - 1 // Reset the buffer offset when reaching this.
+)
+
+const (
+ prime3bytes = 506832829
+ prime4bytes = 2654435761
+ prime5bytes = 889523592379
+ prime6bytes = 227718039650203
+ prime7bytes = 58295818150454627
+ prime8bytes = 0xcf1bbcdcb7a56463
+)
+
+func load3232(b []byte, i int32) uint32 {
+ return binary.LittleEndian.Uint32(b[i:])
+}
+
+func load6432(b []byte, i int32) uint64 {
+ return binary.LittleEndian.Uint64(b[i:])
+}
+
+type tableEntry struct {
+ offset int32
+}
+
+// fastGen maintains the table for matches,
+// and the previous byte block for level 2.
+// This is the generic implementation.
+type fastGen struct {
+ hist []byte
+ cur int32
+}
+
+func (e *fastGen) addBlock(src []byte) int32 {
+ // check if we have space already
+ if len(e.hist)+len(src) > cap(e.hist) {
+ if cap(e.hist) == 0 {
+ e.hist = make([]byte, 0, allocHistory)
+ } else {
+ if cap(e.hist) < maxMatchOffset*2 {
+ panic("unexpected buffer size")
+ }
+ // Move down
+ offset := int32(len(e.hist)) - maxMatchOffset
+ // copy(e.hist[0:maxMatchOffset], e.hist[offset:])
+ *(*[maxMatchOffset]byte)(e.hist) = *(*[maxMatchOffset]byte)(e.hist[offset:])
+ e.cur += offset
+ e.hist = e.hist[:maxMatchOffset]
+ }
+ }
+ s := int32(len(e.hist))
+ e.hist = append(e.hist, src...)
+ return s
+}
+
+type tableEntryPrev struct {
+ Cur tableEntry
+ Prev tableEntry
+}
+
+// hash7 returns the hash of the lowest 7 bytes of u to fit in a hash table with h bits.
+// Preferably h should be a constant and should always be <64.
+func hash7(u uint64, h uint8) uint32 {
+ return uint32(((u << (64 - 56)) * prime7bytes) >> ((64 - h) & reg8SizeMask64))
+}
+
+// hashLen returns a hash of the lowest mls bytes of with length output bits.
+// mls must be >=3 and <=8. Any other value will return hash for 4 bytes.
+// length should always be < 32.
+// Preferably length and mls should be a constant for inlining.
+func hashLen(u uint64, length, mls uint8) uint32 {
+ switch mls {
+ case 3:
+ return (uint32(u<<8) * prime3bytes) >> (32 - length)
+ case 5:
+ return uint32(((u << (64 - 40)) * prime5bytes) >> (64 - length))
+ case 6:
+ return uint32(((u << (64 - 48)) * prime6bytes) >> (64 - length))
+ case 7:
+ return uint32(((u << (64 - 56)) * prime7bytes) >> (64 - length))
+ case 8:
+ return uint32((u * prime8bytes) >> (64 - length))
+ default:
+ return (uint32(u) * prime4bytes) >> (32 - length)
+ }
+}
+
+// matchlen will return the match length between offsets and t in src.
+// The maximum length returned is maxMatchLength - 4.
+// It is assumed that s > t, that t >=0 and s < len(src).
+func (e *fastGen) matchlen(s, t int32, src []byte) int32 {
+ if debugDecode {
+ if t >= s {
+ panic(fmt.Sprint("t >=s:", t, s))
+ }
+ if int(s) >= len(src) {
+ panic(fmt.Sprint("s >= len(src):", s, len(src)))
+ }
+ if t < 0 {
+ panic(fmt.Sprint("t < 0:", t))
+ }
+ if s-t > maxMatchOffset {
+ panic(fmt.Sprint(s, "-", t, "(", s-t, ") > maxMatchLength (", maxMatchOffset, ")"))
+ }
+ }
+ s1 := int(s) + maxMatchLength - 4
+ if s1 > len(src) {
+ s1 = len(src)
+ }
+
+ // Extend the match to be as long as possible.
+ return int32(matchLen(src[s:s1], src[t:]))
+}
+
+// matchlenLong will return the match length between offsets and t in src.
+// It is assumed that s > t, that t >=0 and s < len(src).
+func (e *fastGen) matchlenLong(s, t int32, src []byte) int32 {
+ if debugDeflate {
+ if t >= s {
+ panic(fmt.Sprint("t >=s:", t, s))
+ }
+ if int(s) >= len(src) {
+ panic(fmt.Sprint("s >= len(src):", s, len(src)))
+ }
+ if t < 0 {
+ panic(fmt.Sprint("t < 0:", t))
+ }
+ if s-t > maxMatchOffset {
+ panic(fmt.Sprint(s, "-", t, "(", s-t, ") > maxMatchLength (", maxMatchOffset, ")"))
+ }
+ }
+ // Extend the match to be as long as possible.
+ return int32(matchLen(src[s:], src[t:]))
+}
+
+// Reset the encoding table.
+func (e *fastGen) Reset() {
+ if cap(e.hist) < allocHistory {
+ e.hist = make([]byte, 0, allocHistory)
+ }
+ // We offset current position so everything will be out of reach.
+ // If we are above the buffer reset it will be cleared anyway since len(hist) == 0.
+ if e.cur <= bufferReset {
+ e.cur += maxMatchOffset + int32(len(e.hist))
+ }
+ e.hist = e.hist[:0]
+}
diff --git a/vendor/github.com/klauspost/compress/flate/huffman_bit_writer.go b/vendor/github.com/klauspost/compress/flate/huffman_bit_writer.go
new file mode 100644
index 0000000..f70594c
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/flate/huffman_bit_writer.go
@@ -0,0 +1,1182 @@
+// Copyright 2009 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 flate
+
+import (
+ "encoding/binary"
+ "fmt"
+ "io"
+ "math"
+)
+
+const (
+ // The largest offset code.
+ offsetCodeCount = 30
+
+ // The special code used to mark the end of a block.
+ endBlockMarker = 256
+
+ // The first length code.
+ lengthCodesStart = 257
+
+ // The number of codegen codes.
+ codegenCodeCount = 19
+ badCode = 255
+
+ // maxPredefinedTokens is the maximum number of tokens
+ // where we check if fixed size is smaller.
+ maxPredefinedTokens = 250
+
+ // bufferFlushSize indicates the buffer size
+ // after which bytes are flushed to the writer.
+ // Should preferably be a multiple of 6, since
+ // we accumulate 6 bytes between writes to the buffer.
+ bufferFlushSize = 246
+)
+
+// Minimum length code that emits bits.
+const lengthExtraBitsMinCode = 8
+
+// The number of extra bits needed by length code X - LENGTH_CODES_START.
+var lengthExtraBits = [32]uint8{
+ /* 257 */ 0, 0, 0,
+ /* 260 */ 0, 0, 0, 0, 0, 1, 1, 1, 1, 2,
+ /* 270 */ 2, 2, 2, 3, 3, 3, 3, 4, 4, 4,
+ /* 280 */ 4, 5, 5, 5, 5, 0,
+}
+
+// The length indicated by length code X - LENGTH_CODES_START.
+var lengthBase = [32]uint8{
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 10,
+ 12, 14, 16, 20, 24, 28, 32, 40, 48, 56,
+ 64, 80, 96, 112, 128, 160, 192, 224, 255,
+}
+
+// Minimum offset code that emits bits.
+const offsetExtraBitsMinCode = 4
+
+// offset code word extra bits.
+var offsetExtraBits = [32]int8{
+ 0, 0, 0, 0, 1, 1, 2, 2, 3, 3,
+ 4, 4, 5, 5, 6, 6, 7, 7, 8, 8,
+ 9, 9, 10, 10, 11, 11, 12, 12, 13, 13,
+ /* extended window */
+ 14, 14,
+}
+
+var offsetCombined = [32]uint32{}
+
+func init() {
+ var offsetBase = [32]uint32{
+ /* normal deflate */
+ 0x000000, 0x000001, 0x000002, 0x000003, 0x000004,
+ 0x000006, 0x000008, 0x00000c, 0x000010, 0x000018,
+ 0x000020, 0x000030, 0x000040, 0x000060, 0x000080,
+ 0x0000c0, 0x000100, 0x000180, 0x000200, 0x000300,
+ 0x000400, 0x000600, 0x000800, 0x000c00, 0x001000,
+ 0x001800, 0x002000, 0x003000, 0x004000, 0x006000,
+
+ /* extended window */
+ 0x008000, 0x00c000,
+ }
+
+ for i := range offsetCombined[:] {
+ // Don't use extended window values...
+ if offsetExtraBits[i] == 0 || offsetBase[i] > 0x006000 {
+ continue
+ }
+ offsetCombined[i] = uint32(offsetExtraBits[i]) | (offsetBase[i] << 8)
+ }
+}
+
+// The odd order in which the codegen code sizes are written.
+var codegenOrder = []uint32{16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}
+
+type huffmanBitWriter struct {
+ // writer is the underlying writer.
+ // Do not use it directly; use the write method, which ensures
+ // that Write errors are sticky.
+ writer io.Writer
+
+ // Data waiting to be written is bytes[0:nbytes]
+ // and then the low nbits of bits.
+ bits uint64
+ nbits uint8
+ nbytes uint8
+ lastHuffMan bool
+ literalEncoding *huffmanEncoder
+ tmpLitEncoding *huffmanEncoder
+ offsetEncoding *huffmanEncoder
+ codegenEncoding *huffmanEncoder
+ err error
+ lastHeader int
+ // Set between 0 (reused block can be up to 2x the size)
+ logNewTablePenalty uint
+ bytes [256 + 8]byte
+ literalFreq [lengthCodesStart + 32]uint16
+ offsetFreq [32]uint16
+ codegenFreq [codegenCodeCount]uint16
+
+ // codegen must have an extra space for the final symbol.
+ codegen [literalCount + offsetCodeCount + 1]uint8
+}
+
+// Huffman reuse.
+//
+// The huffmanBitWriter supports reusing huffman tables and thereby combining block sections.
+//
+// This is controlled by several variables:
+//
+// If lastHeader is non-zero the Huffman table can be reused.
+// This also indicates that a Huffman table has been generated that can output all
+// possible symbols.
+// It also indicates that an EOB has not yet been emitted, so if a new tabel is generated
+// an EOB with the previous table must be written.
+//
+// If lastHuffMan is set, a table for outputting literals has been generated and offsets are invalid.
+//
+// An incoming block estimates the output size of a new table using a 'fresh' by calculating the
+// optimal size and adding a penalty in 'logNewTablePenalty'.
+// A Huffman table is not optimal, which is why we add a penalty, and generating a new table
+// is slower both for compression and decompression.
+
+func newHuffmanBitWriter(w io.Writer) *huffmanBitWriter {
+ return &huffmanBitWriter{
+ writer: w,
+ literalEncoding: newHuffmanEncoder(literalCount),
+ tmpLitEncoding: newHuffmanEncoder(literalCount),
+ codegenEncoding: newHuffmanEncoder(codegenCodeCount),
+ offsetEncoding: newHuffmanEncoder(offsetCodeCount),
+ }
+}
+
+func (w *huffmanBitWriter) reset(writer io.Writer) {
+ w.writer = writer
+ w.bits, w.nbits, w.nbytes, w.err = 0, 0, 0, nil
+ w.lastHeader = 0
+ w.lastHuffMan = false
+}
+
+func (w *huffmanBitWriter) canReuse(t *tokens) (ok bool) {
+ a := t.offHist[:offsetCodeCount]
+ b := w.offsetEncoding.codes
+ b = b[:len(a)]
+ for i, v := range a {
+ if v != 0 && b[i].zero() {
+ return false
+ }
+ }
+
+ a = t.extraHist[:literalCount-256]
+ b = w.literalEncoding.codes[256:literalCount]
+ b = b[:len(a)]
+ for i, v := range a {
+ if v != 0 && b[i].zero() {
+ return false
+ }
+ }
+
+ a = t.litHist[:256]
+ b = w.literalEncoding.codes[:len(a)]
+ for i, v := range a {
+ if v != 0 && b[i].zero() {
+ return false
+ }
+ }
+ return true
+}
+
+func (w *huffmanBitWriter) flush() {
+ if w.err != nil {
+ w.nbits = 0
+ return
+ }
+ if w.lastHeader > 0 {
+ // We owe an EOB
+ w.writeCode(w.literalEncoding.codes[endBlockMarker])
+ w.lastHeader = 0
+ }
+ n := w.nbytes
+ for w.nbits != 0 {
+ w.bytes[n] = byte(w.bits)
+ w.bits >>= 8
+ if w.nbits > 8 { // Avoid underflow
+ w.nbits -= 8
+ } else {
+ w.nbits = 0
+ }
+ n++
+ }
+ w.bits = 0
+ w.write(w.bytes[:n])
+ w.nbytes = 0
+}
+
+func (w *huffmanBitWriter) write(b []byte) {
+ if w.err != nil {
+ return
+ }
+ _, w.err = w.writer.Write(b)
+}
+
+func (w *huffmanBitWriter) writeBits(b int32, nb uint8) {
+ w.bits |= uint64(b) << (w.nbits & 63)
+ w.nbits += nb
+ if w.nbits >= 48 {
+ w.writeOutBits()
+ }
+}
+
+func (w *huffmanBitWriter) writeBytes(bytes []byte) {
+ if w.err != nil {
+ return
+ }
+ n := w.nbytes
+ if w.nbits&7 != 0 {
+ w.err = InternalError("writeBytes with unfinished bits")
+ return
+ }
+ for w.nbits != 0 {
+ w.bytes[n] = byte(w.bits)
+ w.bits >>= 8
+ w.nbits -= 8
+ n++
+ }
+ if n != 0 {
+ w.write(w.bytes[:n])
+ }
+ w.nbytes = 0
+ w.write(bytes)
+}
+
+// RFC 1951 3.2.7 specifies a special run-length encoding for specifying
+// the literal and offset lengths arrays (which are concatenated into a single
+// array). This method generates that run-length encoding.
+//
+// The result is written into the codegen array, and the frequencies
+// of each code is written into the codegenFreq array.
+// Codes 0-15 are single byte codes. Codes 16-18 are followed by additional
+// information. Code badCode is an end marker
+//
+// numLiterals The number of literals in literalEncoding
+// numOffsets The number of offsets in offsetEncoding
+// litenc, offenc The literal and offset encoder to use
+func (w *huffmanBitWriter) generateCodegen(numLiterals int, numOffsets int, litEnc, offEnc *huffmanEncoder) {
+ for i := range w.codegenFreq {
+ w.codegenFreq[i] = 0
+ }
+ // Note that we are using codegen both as a temporary variable for holding
+ // a copy of the frequencies, and as the place where we put the result.
+ // This is fine because the output is always shorter than the input used
+ // so far.
+ codegen := w.codegen[:] // cache
+ // Copy the concatenated code sizes to codegen. Put a marker at the end.
+ cgnl := codegen[:numLiterals]
+ for i := range cgnl {
+ cgnl[i] = litEnc.codes[i].len()
+ }
+
+ cgnl = codegen[numLiterals : numLiterals+numOffsets]
+ for i := range cgnl {
+ cgnl[i] = offEnc.codes[i].len()
+ }
+ codegen[numLiterals+numOffsets] = badCode
+
+ size := codegen[0]
+ count := 1
+ outIndex := 0
+ for inIndex := 1; size != badCode; inIndex++ {
+ // INVARIANT: We have seen "count" copies of size that have not yet
+ // had output generated for them.
+ nextSize := codegen[inIndex]
+ if nextSize == size {
+ count++
+ continue
+ }
+ // We need to generate codegen indicating "count" of size.
+ if size != 0 {
+ codegen[outIndex] = size
+ outIndex++
+ w.codegenFreq[size]++
+ count--
+ for count >= 3 {
+ n := 6
+ if n > count {
+ n = count
+ }
+ codegen[outIndex] = 16
+ outIndex++
+ codegen[outIndex] = uint8(n - 3)
+ outIndex++
+ w.codegenFreq[16]++
+ count -= n
+ }
+ } else {
+ for count >= 11 {
+ n := 138
+ if n > count {
+ n = count
+ }
+ codegen[outIndex] = 18
+ outIndex++
+ codegen[outIndex] = uint8(n - 11)
+ outIndex++
+ w.codegenFreq[18]++
+ count -= n
+ }
+ if count >= 3 {
+ // count >= 3 && count <= 10
+ codegen[outIndex] = 17
+ outIndex++
+ codegen[outIndex] = uint8(count - 3)
+ outIndex++
+ w.codegenFreq[17]++
+ count = 0
+ }
+ }
+ count--
+ for ; count >= 0; count-- {
+ codegen[outIndex] = size
+ outIndex++
+ w.codegenFreq[size]++
+ }
+ // Set up invariant for next time through the loop.
+ size = nextSize
+ count = 1
+ }
+ // Marker indicating the end of the codegen.
+ codegen[outIndex] = badCode
+}
+
+func (w *huffmanBitWriter) codegens() int {
+ numCodegens := len(w.codegenFreq)
+ for numCodegens > 4 && w.codegenFreq[codegenOrder[numCodegens-1]] == 0 {
+ numCodegens--
+ }
+ return numCodegens
+}
+
+func (w *huffmanBitWriter) headerSize() (size, numCodegens int) {
+ numCodegens = len(w.codegenFreq)
+ for numCodegens > 4 && w.codegenFreq[codegenOrder[numCodegens-1]] == 0 {
+ numCodegens--
+ }
+ return 3 + 5 + 5 + 4 + (3 * numCodegens) +
+ w.codegenEncoding.bitLength(w.codegenFreq[:]) +
+ int(w.codegenFreq[16])*2 +
+ int(w.codegenFreq[17])*3 +
+ int(w.codegenFreq[18])*7, numCodegens
+}
+
+// dynamicSize returns the size of dynamically encoded data in bits.
+func (w *huffmanBitWriter) dynamicReuseSize(litEnc, offEnc *huffmanEncoder) (size int) {
+ size = litEnc.bitLength(w.literalFreq[:]) +
+ offEnc.bitLength(w.offsetFreq[:])
+ return size
+}
+
+// dynamicSize returns the size of dynamically encoded data in bits.
+func (w *huffmanBitWriter) dynamicSize(litEnc, offEnc *huffmanEncoder, extraBits int) (size, numCodegens int) {
+ header, numCodegens := w.headerSize()
+ size = header +
+ litEnc.bitLength(w.literalFreq[:]) +
+ offEnc.bitLength(w.offsetFreq[:]) +
+ extraBits
+ return size, numCodegens
+}
+
+// extraBitSize will return the number of bits that will be written
+// as "extra" bits on matches.
+func (w *huffmanBitWriter) extraBitSize() int {
+ total := 0
+ for i, n := range w.literalFreq[257:literalCount] {
+ total += int(n) * int(lengthExtraBits[i&31])
+ }
+ for i, n := range w.offsetFreq[:offsetCodeCount] {
+ total += int(n) * int(offsetExtraBits[i&31])
+ }
+ return total
+}
+
+// fixedSize returns the size of dynamically encoded data in bits.
+func (w *huffmanBitWriter) fixedSize(extraBits int) int {
+ return 3 +
+ fixedLiteralEncoding.bitLength(w.literalFreq[:]) +
+ fixedOffsetEncoding.bitLength(w.offsetFreq[:]) +
+ extraBits
+}
+
+// storedSize calculates the stored size, including header.
+// The function returns the size in bits and whether the block
+// fits inside a single block.
+func (w *huffmanBitWriter) storedSize(in []byte) (int, bool) {
+ if in == nil {
+ return 0, false
+ }
+ if len(in) <= maxStoreBlockSize {
+ return (len(in) + 5) * 8, true
+ }
+ return 0, false
+}
+
+func (w *huffmanBitWriter) writeCode(c hcode) {
+ // The function does not get inlined if we "& 63" the shift.
+ w.bits |= c.code64() << (w.nbits & 63)
+ w.nbits += c.len()
+ if w.nbits >= 48 {
+ w.writeOutBits()
+ }
+}
+
+// writeOutBits will write bits to the buffer.
+func (w *huffmanBitWriter) writeOutBits() {
+ bits := w.bits
+ w.bits >>= 48
+ w.nbits -= 48
+ n := w.nbytes
+
+ // We over-write, but faster...
+ binary.LittleEndian.PutUint64(w.bytes[n:], bits)
+ n += 6
+
+ if n >= bufferFlushSize {
+ if w.err != nil {
+ n = 0
+ return
+ }
+ w.write(w.bytes[:n])
+ n = 0
+ }
+
+ w.nbytes = n
+}
+
+// Write the header of a dynamic Huffman block to the output stream.
+//
+// numLiterals The number of literals specified in codegen
+// numOffsets The number of offsets specified in codegen
+// numCodegens The number of codegens used in codegen
+func (w *huffmanBitWriter) writeDynamicHeader(numLiterals int, numOffsets int, numCodegens int, isEof bool) {
+ if w.err != nil {
+ return
+ }
+ var firstBits int32 = 4
+ if isEof {
+ firstBits = 5
+ }
+ w.writeBits(firstBits, 3)
+ w.writeBits(int32(numLiterals-257), 5)
+ w.writeBits(int32(numOffsets-1), 5)
+ w.writeBits(int32(numCodegens-4), 4)
+
+ for i := 0; i < numCodegens; i++ {
+ value := uint(w.codegenEncoding.codes[codegenOrder[i]].len())
+ w.writeBits(int32(value), 3)
+ }
+
+ i := 0
+ for {
+ var codeWord = uint32(w.codegen[i])
+ i++
+ if codeWord == badCode {
+ break
+ }
+ w.writeCode(w.codegenEncoding.codes[codeWord])
+
+ switch codeWord {
+ case 16:
+ w.writeBits(int32(w.codegen[i]), 2)
+ i++
+ case 17:
+ w.writeBits(int32(w.codegen[i]), 3)
+ i++
+ case 18:
+ w.writeBits(int32(w.codegen[i]), 7)
+ i++
+ }
+ }
+}
+
+// writeStoredHeader will write a stored header.
+// If the stored block is only used for EOF,
+// it is replaced with a fixed huffman block.
+func (w *huffmanBitWriter) writeStoredHeader(length int, isEof bool) {
+ if w.err != nil {
+ return
+ }
+ if w.lastHeader > 0 {
+ // We owe an EOB
+ w.writeCode(w.literalEncoding.codes[endBlockMarker])
+ w.lastHeader = 0
+ }
+
+ // To write EOF, use a fixed encoding block. 10 bits instead of 5 bytes.
+ if length == 0 && isEof {
+ w.writeFixedHeader(isEof)
+ // EOB: 7 bits, value: 0
+ w.writeBits(0, 7)
+ w.flush()
+ return
+ }
+
+ var flag int32
+ if isEof {
+ flag = 1
+ }
+ w.writeBits(flag, 3)
+ w.flush()
+ w.writeBits(int32(length), 16)
+ w.writeBits(int32(^uint16(length)), 16)
+}
+
+func (w *huffmanBitWriter) writeFixedHeader(isEof bool) {
+ if w.err != nil {
+ return
+ }
+ if w.lastHeader > 0 {
+ // We owe an EOB
+ w.writeCode(w.literalEncoding.codes[endBlockMarker])
+ w.lastHeader = 0
+ }
+
+ // Indicate that we are a fixed Huffman block
+ var value int32 = 2
+ if isEof {
+ value = 3
+ }
+ w.writeBits(value, 3)
+}
+
+// writeBlock will write a block of tokens with the smallest encoding.
+// The original input can be supplied, and if the huffman encoded data
+// is larger than the original bytes, the data will be written as a
+// stored block.
+// If the input is nil, the tokens will always be Huffman encoded.
+func (w *huffmanBitWriter) writeBlock(tokens *tokens, eof bool, input []byte) {
+ if w.err != nil {
+ return
+ }
+
+ tokens.AddEOB()
+ if w.lastHeader > 0 {
+ // We owe an EOB
+ w.writeCode(w.literalEncoding.codes[endBlockMarker])
+ w.lastHeader = 0
+ }
+ numLiterals, numOffsets := w.indexTokens(tokens, false)
+ w.generate()
+ var extraBits int
+ storedSize, storable := w.storedSize(input)
+ if storable {
+ extraBits = w.extraBitSize()
+ }
+
+ // Figure out smallest code.
+ // Fixed Huffman baseline.
+ var literalEncoding = fixedLiteralEncoding
+ var offsetEncoding = fixedOffsetEncoding
+ var size = math.MaxInt32
+ if tokens.n < maxPredefinedTokens {
+ size = w.fixedSize(extraBits)
+ }
+
+ // Dynamic Huffman?
+ var numCodegens int
+
+ // Generate codegen and codegenFrequencies, which indicates how to encode
+ // the literalEncoding and the offsetEncoding.
+ w.generateCodegen(numLiterals, numOffsets, w.literalEncoding, w.offsetEncoding)
+ w.codegenEncoding.generate(w.codegenFreq[:], 7)
+ dynamicSize, numCodegens := w.dynamicSize(w.literalEncoding, w.offsetEncoding, extraBits)
+
+ if dynamicSize < size {
+ size = dynamicSize
+ literalEncoding = w.literalEncoding
+ offsetEncoding = w.offsetEncoding
+ }
+
+ // Stored bytes?
+ if storable && storedSize <= size {
+ w.writeStoredHeader(len(input), eof)
+ w.writeBytes(input)
+ return
+ }
+
+ // Huffman.
+ if literalEncoding == fixedLiteralEncoding {
+ w.writeFixedHeader(eof)
+ } else {
+ w.writeDynamicHeader(numLiterals, numOffsets, numCodegens, eof)
+ }
+
+ // Write the tokens.
+ w.writeTokens(tokens.Slice(), literalEncoding.codes, offsetEncoding.codes)
+}
+
+// writeBlockDynamic encodes a block using a dynamic Huffman table.
+// This should be used if the symbols used have a disproportionate
+// histogram distribution.
+// If input is supplied and the compression savings are below 1/16th of the
+// input size the block is stored.
+func (w *huffmanBitWriter) writeBlockDynamic(tokens *tokens, eof bool, input []byte, sync bool) {
+ if w.err != nil {
+ return
+ }
+
+ sync = sync || eof
+ if sync {
+ tokens.AddEOB()
+ }
+
+ // We cannot reuse pure huffman table, and must mark as EOF.
+ if (w.lastHuffMan || eof) && w.lastHeader > 0 {
+ // We will not try to reuse.
+ w.writeCode(w.literalEncoding.codes[endBlockMarker])
+ w.lastHeader = 0
+ w.lastHuffMan = false
+ }
+
+ // fillReuse enables filling of empty values.
+ // This will make encodings always reusable without testing.
+ // However, this does not appear to benefit on most cases.
+ const fillReuse = false
+
+ // Check if we can reuse...
+ if !fillReuse && w.lastHeader > 0 && !w.canReuse(tokens) {
+ w.writeCode(w.literalEncoding.codes[endBlockMarker])
+ w.lastHeader = 0
+ }
+
+ numLiterals, numOffsets := w.indexTokens(tokens, !sync)
+ extraBits := 0
+ ssize, storable := w.storedSize(input)
+
+ const usePrefs = true
+ if storable || w.lastHeader > 0 {
+ extraBits = w.extraBitSize()
+ }
+
+ var size int
+
+ // Check if we should reuse.
+ if w.lastHeader > 0 {
+ // Estimate size for using a new table.
+ // Use the previous header size as the best estimate.
+ newSize := w.lastHeader + tokens.EstimatedBits()
+ newSize += int(w.literalEncoding.codes[endBlockMarker].len()) + newSize>>w.logNewTablePenalty
+
+ // The estimated size is calculated as an optimal table.
+ // We add a penalty to make it more realistic and re-use a bit more.
+ reuseSize := w.dynamicReuseSize(w.literalEncoding, w.offsetEncoding) + extraBits
+
+ // Check if a new table is better.
+ if newSize < reuseSize {
+ // Write the EOB we owe.
+ w.writeCode(w.literalEncoding.codes[endBlockMarker])
+ size = newSize
+ w.lastHeader = 0
+ } else {
+ size = reuseSize
+ }
+
+ if tokens.n < maxPredefinedTokens {
+ if preSize := w.fixedSize(extraBits) + 7; usePrefs && preSize < size {
+ // Check if we get a reasonable size decrease.
+ if storable && ssize <= size {
+ w.writeStoredHeader(len(input), eof)
+ w.writeBytes(input)
+ return
+ }
+ w.writeFixedHeader(eof)
+ if !sync {
+ tokens.AddEOB()
+ }
+ w.writeTokens(tokens.Slice(), fixedLiteralEncoding.codes, fixedOffsetEncoding.codes)
+ return
+ }
+ }
+ // Check if we get a reasonable size decrease.
+ if storable && ssize <= size {
+ w.writeStoredHeader(len(input), eof)
+ w.writeBytes(input)
+ return
+ }
+ }
+
+ // We want a new block/table
+ if w.lastHeader == 0 {
+ if fillReuse && !sync {
+ w.fillTokens()
+ numLiterals, numOffsets = maxNumLit, maxNumDist
+ } else {
+ w.literalFreq[endBlockMarker] = 1
+ }
+
+ w.generate()
+ // Generate codegen and codegenFrequencies, which indicates how to encode
+ // the literalEncoding and the offsetEncoding.
+ w.generateCodegen(numLiterals, numOffsets, w.literalEncoding, w.offsetEncoding)
+ w.codegenEncoding.generate(w.codegenFreq[:], 7)
+
+ var numCodegens int
+ if fillReuse && !sync {
+ // Reindex for accurate size...
+ w.indexTokens(tokens, true)
+ }
+ size, numCodegens = w.dynamicSize(w.literalEncoding, w.offsetEncoding, extraBits)
+
+ // Store predefined, if we don't get a reasonable improvement.
+ if tokens.n < maxPredefinedTokens {
+ if preSize := w.fixedSize(extraBits); usePrefs && preSize <= size {
+ // Store bytes, if we don't get an improvement.
+ if storable && ssize <= preSize {
+ w.writeStoredHeader(len(input), eof)
+ w.writeBytes(input)
+ return
+ }
+ w.writeFixedHeader(eof)
+ if !sync {
+ tokens.AddEOB()
+ }
+ w.writeTokens(tokens.Slice(), fixedLiteralEncoding.codes, fixedOffsetEncoding.codes)
+ return
+ }
+ }
+
+ if storable && ssize <= size {
+ // Store bytes, if we don't get an improvement.
+ w.writeStoredHeader(len(input), eof)
+ w.writeBytes(input)
+ return
+ }
+
+ // Write Huffman table.
+ w.writeDynamicHeader(numLiterals, numOffsets, numCodegens, eof)
+ if !sync {
+ w.lastHeader, _ = w.headerSize()
+ }
+ w.lastHuffMan = false
+ }
+
+ if sync {
+ w.lastHeader = 0
+ }
+ // Write the tokens.
+ w.writeTokens(tokens.Slice(), w.literalEncoding.codes, w.offsetEncoding.codes)
+}
+
+func (w *huffmanBitWriter) fillTokens() {
+ for i, v := range w.literalFreq[:literalCount] {
+ if v == 0 {
+ w.literalFreq[i] = 1
+ }
+ }
+ for i, v := range w.offsetFreq[:offsetCodeCount] {
+ if v == 0 {
+ w.offsetFreq[i] = 1
+ }
+ }
+}
+
+// indexTokens indexes a slice of tokens, and updates
+// literalFreq and offsetFreq, and generates literalEncoding
+// and offsetEncoding.
+// The number of literal and offset tokens is returned.
+func (w *huffmanBitWriter) indexTokens(t *tokens, filled bool) (numLiterals, numOffsets int) {
+ //copy(w.literalFreq[:], t.litHist[:])
+ *(*[256]uint16)(w.literalFreq[:]) = t.litHist
+ //copy(w.literalFreq[256:], t.extraHist[:])
+ *(*[32]uint16)(w.literalFreq[256:]) = t.extraHist
+ w.offsetFreq = t.offHist
+
+ if t.n == 0 {
+ return
+ }
+ if filled {
+ return maxNumLit, maxNumDist
+ }
+ // get the number of literals
+ numLiterals = len(w.literalFreq)
+ for w.literalFreq[numLiterals-1] == 0 {
+ numLiterals--
+ }
+ // get the number of offsets
+ numOffsets = len(w.offsetFreq)
+ for numOffsets > 0 && w.offsetFreq[numOffsets-1] == 0 {
+ numOffsets--
+ }
+ if numOffsets == 0 {
+ // We haven't found a single match. If we want to go with the dynamic encoding,
+ // we should count at least one offset to be sure that the offset huffman tree could be encoded.
+ w.offsetFreq[0] = 1
+ numOffsets = 1
+ }
+ return
+}
+
+func (w *huffmanBitWriter) generate() {
+ w.literalEncoding.generate(w.literalFreq[:literalCount], 15)
+ w.offsetEncoding.generate(w.offsetFreq[:offsetCodeCount], 15)
+}
+
+// writeTokens writes a slice of tokens to the output.
+// codes for literal and offset encoding must be supplied.
+func (w *huffmanBitWriter) writeTokens(tokens []token, leCodes, oeCodes []hcode) {
+ if w.err != nil {
+ return
+ }
+ if len(tokens) == 0 {
+ return
+ }
+
+ // Only last token should be endBlockMarker.
+ var deferEOB bool
+ if tokens[len(tokens)-1] == endBlockMarker {
+ tokens = tokens[:len(tokens)-1]
+ deferEOB = true
+ }
+
+ // Create slices up to the next power of two to avoid bounds checks.
+ lits := leCodes[:256]
+ offs := oeCodes[:32]
+ lengths := leCodes[lengthCodesStart:]
+ lengths = lengths[:32]
+
+ // Go 1.16 LOVES having these on stack.
+ bits, nbits, nbytes := w.bits, w.nbits, w.nbytes
+
+ for _, t := range tokens {
+ if t < 256 {
+ //w.writeCode(lits[t.literal()])
+ c := lits[t]
+ bits |= c.code64() << (nbits & 63)
+ nbits += c.len()
+ if nbits >= 48 {
+ binary.LittleEndian.PutUint64(w.bytes[nbytes:], bits)
+ //*(*uint64)(unsafe.Pointer(&w.bytes[nbytes])) = bits
+ bits >>= 48
+ nbits -= 48
+ nbytes += 6
+ if nbytes >= bufferFlushSize {
+ if w.err != nil {
+ nbytes = 0
+ return
+ }
+ _, w.err = w.writer.Write(w.bytes[:nbytes])
+ nbytes = 0
+ }
+ }
+ continue
+ }
+
+ // Write the length
+ length := t.length()
+ lengthCode := lengthCode(length) & 31
+ if false {
+ w.writeCode(lengths[lengthCode])
+ } else {
+ // inlined
+ c := lengths[lengthCode]
+ bits |= c.code64() << (nbits & 63)
+ nbits += c.len()
+ if nbits >= 48 {
+ binary.LittleEndian.PutUint64(w.bytes[nbytes:], bits)
+ //*(*uint64)(unsafe.Pointer(&w.bytes[nbytes])) = bits
+ bits >>= 48
+ nbits -= 48
+ nbytes += 6
+ if nbytes >= bufferFlushSize {
+ if w.err != nil {
+ nbytes = 0
+ return
+ }
+ _, w.err = w.writer.Write(w.bytes[:nbytes])
+ nbytes = 0
+ }
+ }
+ }
+
+ if lengthCode >= lengthExtraBitsMinCode {
+ extraLengthBits := lengthExtraBits[lengthCode]
+ //w.writeBits(extraLength, extraLengthBits)
+ extraLength := int32(length - lengthBase[lengthCode])
+ bits |= uint64(extraLength) << (nbits & 63)
+ nbits += extraLengthBits
+ if nbits >= 48 {
+ binary.LittleEndian.PutUint64(w.bytes[nbytes:], bits)
+ //*(*uint64)(unsafe.Pointer(&w.bytes[nbytes])) = bits
+ bits >>= 48
+ nbits -= 48
+ nbytes += 6
+ if nbytes >= bufferFlushSize {
+ if w.err != nil {
+ nbytes = 0
+ return
+ }
+ _, w.err = w.writer.Write(w.bytes[:nbytes])
+ nbytes = 0
+ }
+ }
+ }
+ // Write the offset
+ offset := t.offset()
+ offsetCode := (offset >> 16) & 31
+ if false {
+ w.writeCode(offs[offsetCode])
+ } else {
+ // inlined
+ c := offs[offsetCode]
+ bits |= c.code64() << (nbits & 63)
+ nbits += c.len()
+ if nbits >= 48 {
+ binary.LittleEndian.PutUint64(w.bytes[nbytes:], bits)
+ //*(*uint64)(unsafe.Pointer(&w.bytes[nbytes])) = bits
+ bits >>= 48
+ nbits -= 48
+ nbytes += 6
+ if nbytes >= bufferFlushSize {
+ if w.err != nil {
+ nbytes = 0
+ return
+ }
+ _, w.err = w.writer.Write(w.bytes[:nbytes])
+ nbytes = 0
+ }
+ }
+ }
+
+ if offsetCode >= offsetExtraBitsMinCode {
+ offsetComb := offsetCombined[offsetCode]
+ //w.writeBits(extraOffset, extraOffsetBits)
+ bits |= uint64((offset-(offsetComb>>8))&matchOffsetOnlyMask) << (nbits & 63)
+ nbits += uint8(offsetComb)
+ if nbits >= 48 {
+ binary.LittleEndian.PutUint64(w.bytes[nbytes:], bits)
+ //*(*uint64)(unsafe.Pointer(&w.bytes[nbytes])) = bits
+ bits >>= 48
+ nbits -= 48
+ nbytes += 6
+ if nbytes >= bufferFlushSize {
+ if w.err != nil {
+ nbytes = 0
+ return
+ }
+ _, w.err = w.writer.Write(w.bytes[:nbytes])
+ nbytes = 0
+ }
+ }
+ }
+ }
+ // Restore...
+ w.bits, w.nbits, w.nbytes = bits, nbits, nbytes
+
+ if deferEOB {
+ w.writeCode(leCodes[endBlockMarker])
+ }
+}
+
+// huffOffset is a static offset encoder used for huffman only encoding.
+// It can be reused since we will not be encoding offset values.
+var huffOffset *huffmanEncoder
+
+func init() {
+ w := newHuffmanBitWriter(nil)
+ w.offsetFreq[0] = 1
+ huffOffset = newHuffmanEncoder(offsetCodeCount)
+ huffOffset.generate(w.offsetFreq[:offsetCodeCount], 15)
+}
+
+// writeBlockHuff encodes a block of bytes as either
+// Huffman encoded literals or uncompressed bytes if the
+// results only gains very little from compression.
+func (w *huffmanBitWriter) writeBlockHuff(eof bool, input []byte, sync bool) {
+ if w.err != nil {
+ return
+ }
+
+ // Clear histogram
+ for i := range w.literalFreq[:] {
+ w.literalFreq[i] = 0
+ }
+ if !w.lastHuffMan {
+ for i := range w.offsetFreq[:] {
+ w.offsetFreq[i] = 0
+ }
+ }
+
+ const numLiterals = endBlockMarker + 1
+ const numOffsets = 1
+
+ // Add everything as literals
+ // We have to estimate the header size.
+ // Assume header is around 70 bytes:
+ // https://stackoverflow.com/a/25454430
+ const guessHeaderSizeBits = 70 * 8
+ histogram(input, w.literalFreq[:numLiterals])
+ ssize, storable := w.storedSize(input)
+ if storable && len(input) > 1024 {
+ // Quick check for incompressible content.
+ abs := float64(0)
+ avg := float64(len(input)) / 256
+ max := float64(len(input) * 2)
+ for _, v := range w.literalFreq[:256] {
+ diff := float64(v) - avg
+ abs += diff * diff
+ if abs > max {
+ break
+ }
+ }
+ if abs < max {
+ if debugDeflate {
+ fmt.Println("stored", abs, "<", max)
+ }
+ // No chance we can compress this...
+ w.writeStoredHeader(len(input), eof)
+ w.writeBytes(input)
+ return
+ }
+ }
+ w.literalFreq[endBlockMarker] = 1
+ w.tmpLitEncoding.generate(w.literalFreq[:numLiterals], 15)
+ estBits := w.tmpLitEncoding.canReuseBits(w.literalFreq[:numLiterals])
+ if estBits < math.MaxInt32 {
+ estBits += w.lastHeader
+ if w.lastHeader == 0 {
+ estBits += guessHeaderSizeBits
+ }
+ estBits += estBits >> w.logNewTablePenalty
+ }
+
+ // Store bytes, if we don't get a reasonable improvement.
+ if storable && ssize <= estBits {
+ if debugDeflate {
+ fmt.Println("stored,", ssize, "<=", estBits)
+ }
+ w.writeStoredHeader(len(input), eof)
+ w.writeBytes(input)
+ return
+ }
+
+ if w.lastHeader > 0 {
+ reuseSize := w.literalEncoding.canReuseBits(w.literalFreq[:256])
+
+ if estBits < reuseSize {
+ if debugDeflate {
+ fmt.Println("NOT reusing, reuse:", reuseSize/8, "> new:", estBits/8, "header est:", w.lastHeader/8, "bytes")
+ }
+ // We owe an EOB
+ w.writeCode(w.literalEncoding.codes[endBlockMarker])
+ w.lastHeader = 0
+ } else if debugDeflate {
+ fmt.Println("reusing, reuse:", reuseSize/8, "> new:", estBits/8, "- header est:", w.lastHeader/8)
+ }
+ }
+
+ count := 0
+ if w.lastHeader == 0 {
+ // Use the temp encoding, so swap.
+ w.literalEncoding, w.tmpLitEncoding = w.tmpLitEncoding, w.literalEncoding
+ // Generate codegen and codegenFrequencies, which indicates how to encode
+ // the literalEncoding and the offsetEncoding.
+ w.generateCodegen(numLiterals, numOffsets, w.literalEncoding, huffOffset)
+ w.codegenEncoding.generate(w.codegenFreq[:], 7)
+ numCodegens := w.codegens()
+
+ // Huffman.
+ w.writeDynamicHeader(numLiterals, numOffsets, numCodegens, eof)
+ w.lastHuffMan = true
+ w.lastHeader, _ = w.headerSize()
+ if debugDeflate {
+ count += w.lastHeader
+ fmt.Println("header:", count/8)
+ }
+ }
+
+ encoding := w.literalEncoding.codes[:256]
+ // Go 1.16 LOVES having these on stack. At least 1.5x the speed.
+ bits, nbits, nbytes := w.bits, w.nbits, w.nbytes
+
+ if debugDeflate {
+ count -= int(nbytes)*8 + int(nbits)
+ }
+ // Unroll, write 3 codes/loop.
+ // Fastest number of unrolls.
+ for len(input) > 3 {
+ // We must have at least 48 bits free.
+ if nbits >= 8 {
+ n := nbits >> 3
+ binary.LittleEndian.PutUint64(w.bytes[nbytes:], bits)
+ bits >>= (n * 8) & 63
+ nbits -= n * 8
+ nbytes += n
+ }
+ if nbytes >= bufferFlushSize {
+ if w.err != nil {
+ nbytes = 0
+ return
+ }
+ if debugDeflate {
+ count += int(nbytes) * 8
+ }
+ _, w.err = w.writer.Write(w.bytes[:nbytes])
+ nbytes = 0
+ }
+ a, b := encoding[input[0]], encoding[input[1]]
+ bits |= a.code64() << (nbits & 63)
+ bits |= b.code64() << ((nbits + a.len()) & 63)
+ c := encoding[input[2]]
+ nbits += b.len() + a.len()
+ bits |= c.code64() << (nbits & 63)
+ nbits += c.len()
+ input = input[3:]
+ }
+
+ // Remaining...
+ for _, t := range input {
+ if nbits >= 48 {
+ binary.LittleEndian.PutUint64(w.bytes[nbytes:], bits)
+ //*(*uint64)(unsafe.Pointer(&w.bytes[nbytes])) = bits
+ bits >>= 48
+ nbits -= 48
+ nbytes += 6
+ if nbytes >= bufferFlushSize {
+ if w.err != nil {
+ nbytes = 0
+ return
+ }
+ if debugDeflate {
+ count += int(nbytes) * 8
+ }
+ _, w.err = w.writer.Write(w.bytes[:nbytes])
+ nbytes = 0
+ }
+ }
+ // Bitwriting inlined, ~30% speedup
+ c := encoding[t]
+ bits |= c.code64() << (nbits & 63)
+
+ nbits += c.len()
+ if debugDeflate {
+ count += int(c.len())
+ }
+ }
+ // Restore...
+ w.bits, w.nbits, w.nbytes = bits, nbits, nbytes
+
+ if debugDeflate {
+ nb := count + int(nbytes)*8 + int(nbits)
+ fmt.Println("wrote", nb, "bits,", nb/8, "bytes.")
+ }
+ // Flush if needed to have space.
+ if w.nbits >= 48 {
+ w.writeOutBits()
+ }
+
+ if eof || sync {
+ w.writeCode(w.literalEncoding.codes[endBlockMarker])
+ w.lastHeader = 0
+ w.lastHuffMan = false
+ }
+}
diff --git a/vendor/github.com/klauspost/compress/flate/huffman_code.go b/vendor/github.com/klauspost/compress/flate/huffman_code.go
new file mode 100644
index 0000000..be7b58b
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/flate/huffman_code.go
@@ -0,0 +1,417 @@
+// Copyright 2009 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 flate
+
+import (
+ "math"
+ "math/bits"
+)
+
+const (
+ maxBitsLimit = 16
+ // number of valid literals
+ literalCount = 286
+)
+
+// hcode is a huffman code with a bit code and bit length.
+type hcode uint32
+
+func (h hcode) len() uint8 {
+ return uint8(h)
+}
+
+func (h hcode) code64() uint64 {
+ return uint64(h >> 8)
+}
+
+func (h hcode) zero() bool {
+ return h == 0
+}
+
+type huffmanEncoder struct {
+ codes []hcode
+ bitCount [17]int32
+
+ // Allocate a reusable buffer with the longest possible frequency table.
+ // Possible lengths are codegenCodeCount, offsetCodeCount and literalCount.
+ // The largest of these is literalCount, so we allocate for that case.
+ freqcache [literalCount + 1]literalNode
+}
+
+type literalNode struct {
+ literal uint16
+ freq uint16
+}
+
+// A levelInfo describes the state of the constructed tree for a given depth.
+type levelInfo struct {
+ // Our level. for better printing
+ level int32
+
+ // The frequency of the last node at this level
+ lastFreq int32
+
+ // The frequency of the next character to add to this level
+ nextCharFreq int32
+
+ // The frequency of the next pair (from level below) to add to this level.
+ // Only valid if the "needed" value of the next lower level is 0.
+ nextPairFreq int32
+
+ // The number of chains remaining to generate for this level before moving
+ // up to the next level
+ needed int32
+}
+
+// set sets the code and length of an hcode.
+func (h *hcode) set(code uint16, length uint8) {
+ *h = hcode(length) | (hcode(code) << 8)
+}
+
+func newhcode(code uint16, length uint8) hcode {
+ return hcode(length) | (hcode(code) << 8)
+}
+
+func reverseBits(number uint16, bitLength byte) uint16 {
+ return bits.Reverse16(number << ((16 - bitLength) & 15))
+}
+
+func maxNode() literalNode { return literalNode{math.MaxUint16, math.MaxUint16} }
+
+func newHuffmanEncoder(size int) *huffmanEncoder {
+ // Make capacity to next power of two.
+ c := uint(bits.Len32(uint32(size - 1)))
+ return &huffmanEncoder{codes: make([]hcode, size, 1<= 3
+// The cases of 0, 1, and 2 literals are handled by special case code.
+//
+// list An array of the literals with non-zero frequencies
+//
+// and their associated frequencies. The array is in order of increasing
+// frequency, and has as its last element a special element with frequency
+// MaxInt32
+//
+// maxBits The maximum number of bits that should be used to encode any literal.
+//
+// Must be less than 16.
+//
+// return An integer array in which array[i] indicates the number of literals
+//
+// that should be encoded in i bits.
+func (h *huffmanEncoder) bitCounts(list []literalNode, maxBits int32) []int32 {
+ if maxBits >= maxBitsLimit {
+ panic("flate: maxBits too large")
+ }
+ n := int32(len(list))
+ list = list[0 : n+1]
+ list[n] = maxNode()
+
+ // The tree can't have greater depth than n - 1, no matter what. This
+ // saves a little bit of work in some small cases
+ if maxBits > n-1 {
+ maxBits = n - 1
+ }
+
+ // Create information about each of the levels.
+ // A bogus "Level 0" whose sole purpose is so that
+ // level1.prev.needed==0. This makes level1.nextPairFreq
+ // be a legitimate value that never gets chosen.
+ var levels [maxBitsLimit]levelInfo
+ // leafCounts[i] counts the number of literals at the left
+ // of ancestors of the rightmost node at level i.
+ // leafCounts[i][j] is the number of literals at the left
+ // of the level j ancestor.
+ var leafCounts [maxBitsLimit][maxBitsLimit]int32
+
+ // Descending to only have 1 bounds check.
+ l2f := int32(list[2].freq)
+ l1f := int32(list[1].freq)
+ l0f := int32(list[0].freq) + int32(list[1].freq)
+
+ for level := int32(1); level <= maxBits; level++ {
+ // For every level, the first two items are the first two characters.
+ // We initialize the levels as if we had already figured this out.
+ levels[level] = levelInfo{
+ level: level,
+ lastFreq: l1f,
+ nextCharFreq: l2f,
+ nextPairFreq: l0f,
+ }
+ leafCounts[level][level] = 2
+ if level == 1 {
+ levels[level].nextPairFreq = math.MaxInt32
+ }
+ }
+
+ // We need a total of 2*n - 2 items at top level and have already generated 2.
+ levels[maxBits].needed = 2*n - 4
+
+ level := uint32(maxBits)
+ for level < 16 {
+ l := &levels[level]
+ if l.nextPairFreq == math.MaxInt32 && l.nextCharFreq == math.MaxInt32 {
+ // We've run out of both leafs and pairs.
+ // End all calculations for this level.
+ // To make sure we never come back to this level or any lower level,
+ // set nextPairFreq impossibly large.
+ l.needed = 0
+ levels[level+1].nextPairFreq = math.MaxInt32
+ level++
+ continue
+ }
+
+ prevFreq := l.lastFreq
+ if l.nextCharFreq < l.nextPairFreq {
+ // The next item on this row is a leaf node.
+ n := leafCounts[level][level] + 1
+ l.lastFreq = l.nextCharFreq
+ // Lower leafCounts are the same of the previous node.
+ leafCounts[level][level] = n
+ e := list[n]
+ if e.literal < math.MaxUint16 {
+ l.nextCharFreq = int32(e.freq)
+ } else {
+ l.nextCharFreq = math.MaxInt32
+ }
+ } else {
+ // The next item on this row is a pair from the previous row.
+ // nextPairFreq isn't valid until we generate two
+ // more values in the level below
+ l.lastFreq = l.nextPairFreq
+ // Take leaf counts from the lower level, except counts[level] remains the same.
+ if true {
+ save := leafCounts[level][level]
+ leafCounts[level] = leafCounts[level-1]
+ leafCounts[level][level] = save
+ } else {
+ copy(leafCounts[level][:level], leafCounts[level-1][:level])
+ }
+ levels[l.level-1].needed = 2
+ }
+
+ if l.needed--; l.needed == 0 {
+ // We've done everything we need to do for this level.
+ // Continue calculating one level up. Fill in nextPairFreq
+ // of that level with the sum of the two nodes we've just calculated on
+ // this level.
+ if l.level == maxBits {
+ // All done!
+ break
+ }
+ levels[l.level+1].nextPairFreq = prevFreq + l.lastFreq
+ level++
+ } else {
+ // If we stole from below, move down temporarily to replenish it.
+ for levels[level-1].needed > 0 {
+ level--
+ }
+ }
+ }
+
+ // Somethings is wrong if at the end, the top level is null or hasn't used
+ // all of the leaves.
+ if leafCounts[maxBits][maxBits] != n {
+ panic("leafCounts[maxBits][maxBits] != n")
+ }
+
+ bitCount := h.bitCount[:maxBits+1]
+ bits := 1
+ counts := &leafCounts[maxBits]
+ for level := maxBits; level > 0; level-- {
+ // chain.leafCount gives the number of literals requiring at least "bits"
+ // bits to encode.
+ bitCount[bits] = counts[level] - counts[level-1]
+ bits++
+ }
+ return bitCount
+}
+
+// Look at the leaves and assign them a bit count and an encoding as specified
+// in RFC 1951 3.2.2
+func (h *huffmanEncoder) assignEncodingAndSize(bitCount []int32, list []literalNode) {
+ code := uint16(0)
+ for n, bits := range bitCount {
+ code <<= 1
+ if n == 0 || bits == 0 {
+ continue
+ }
+ // The literals list[len(list)-bits] .. list[len(list)-bits]
+ // are encoded using "bits" bits, and get the values
+ // code, code + 1, .... The code values are
+ // assigned in literal order (not frequency order).
+ chunk := list[len(list)-int(bits):]
+
+ sortByLiteral(chunk)
+ for _, node := range chunk {
+ h.codes[node.literal] = newhcode(reverseBits(code, uint8(n)), uint8(n))
+ code++
+ }
+ list = list[0 : len(list)-int(bits)]
+ }
+}
+
+// Update this Huffman Code object to be the minimum code for the specified frequency count.
+//
+// freq An array of frequencies, in which frequency[i] gives the frequency of literal i.
+// maxBits The maximum number of bits to use for any literal.
+func (h *huffmanEncoder) generate(freq []uint16, maxBits int32) {
+ list := h.freqcache[:len(freq)+1]
+ codes := h.codes[:len(freq)]
+ // Number of non-zero literals
+ count := 0
+ // Set list to be the set of all non-zero literals and their frequencies
+ for i, f := range freq {
+ if f != 0 {
+ list[count] = literalNode{uint16(i), f}
+ count++
+ } else {
+ codes[i] = 0
+ }
+ }
+ list[count] = literalNode{}
+
+ list = list[:count]
+ if count <= 2 {
+ // Handle the small cases here, because they are awkward for the general case code. With
+ // two or fewer literals, everything has bit length 1.
+ for i, node := range list {
+ // "list" is in order of increasing literal value.
+ h.codes[node.literal].set(uint16(i), 1)
+ }
+ return
+ }
+ sortByFreq(list)
+
+ // Get the number of literals for each bit count
+ bitCount := h.bitCounts(list, maxBits)
+ // And do the assignment
+ h.assignEncodingAndSize(bitCount, list)
+}
+
+// atLeastOne clamps the result between 1 and 15.
+func atLeastOne(v float32) float32 {
+ if v < 1 {
+ return 1
+ }
+ if v > 15 {
+ return 15
+ }
+ return v
+}
+
+func histogram(b []byte, h []uint16) {
+ if true && len(b) >= 8<<10 {
+ // Split for bigger inputs
+ histogramSplit(b, h)
+ } else {
+ h = h[:256]
+ for _, t := range b {
+ h[t]++
+ }
+ }
+}
+
+func histogramSplit(b []byte, h []uint16) {
+ // Tested, and slightly faster than 2-way.
+ // Writing to separate arrays and combining is also slightly slower.
+ h = h[:256]
+ for len(b)&3 != 0 {
+ h[b[0]]++
+ b = b[1:]
+ }
+ n := len(b) / 4
+ x, y, z, w := b[:n], b[n:], b[n+n:], b[n+n+n:]
+ y, z, w = y[:len(x)], z[:len(x)], w[:len(x)]
+ for i, t := range x {
+ v0 := &h[t]
+ v1 := &h[y[i]]
+ v3 := &h[w[i]]
+ v2 := &h[z[i]]
+ *v0++
+ *v1++
+ *v2++
+ *v3++
+ }
+}
diff --git a/vendor/github.com/klauspost/compress/flate/huffman_sortByFreq.go b/vendor/github.com/klauspost/compress/flate/huffman_sortByFreq.go
new file mode 100644
index 0000000..6c05ba8
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/flate/huffman_sortByFreq.go
@@ -0,0 +1,159 @@
+// Copyright 2009 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 flate
+
+// Sort sorts data.
+// It makes one call to data.Len to determine n, and O(n*log(n)) calls to
+// data.Less and data.Swap. The sort is not guaranteed to be stable.
+func sortByFreq(data []literalNode) {
+ n := len(data)
+ quickSortByFreq(data, 0, n, maxDepth(n))
+}
+
+func quickSortByFreq(data []literalNode, a, b, maxDepth int) {
+ for b-a > 12 { // Use ShellSort for slices <= 12 elements
+ if maxDepth == 0 {
+ heapSort(data, a, b)
+ return
+ }
+ maxDepth--
+ mlo, mhi := doPivotByFreq(data, a, b)
+ // Avoiding recursion on the larger subproblem guarantees
+ // a stack depth of at most lg(b-a).
+ if mlo-a < b-mhi {
+ quickSortByFreq(data, a, mlo, maxDepth)
+ a = mhi // i.e., quickSortByFreq(data, mhi, b)
+ } else {
+ quickSortByFreq(data, mhi, b, maxDepth)
+ b = mlo // i.e., quickSortByFreq(data, a, mlo)
+ }
+ }
+ if b-a > 1 {
+ // Do ShellSort pass with gap 6
+ // It could be written in this simplified form cause b-a <= 12
+ for i := a + 6; i < b; i++ {
+ if data[i].freq == data[i-6].freq && data[i].literal < data[i-6].literal || data[i].freq < data[i-6].freq {
+ data[i], data[i-6] = data[i-6], data[i]
+ }
+ }
+ insertionSortByFreq(data, a, b)
+ }
+}
+
+func doPivotByFreq(data []literalNode, lo, hi int) (midlo, midhi int) {
+ m := int(uint(lo+hi) >> 1) // Written like this to avoid integer overflow.
+ if hi-lo > 40 {
+ // Tukey's ``Ninther,'' median of three medians of three.
+ s := (hi - lo) / 8
+ medianOfThreeSortByFreq(data, lo, lo+s, lo+2*s)
+ medianOfThreeSortByFreq(data, m, m-s, m+s)
+ medianOfThreeSortByFreq(data, hi-1, hi-1-s, hi-1-2*s)
+ }
+ medianOfThreeSortByFreq(data, lo, m, hi-1)
+
+ // Invariants are:
+ // data[lo] = pivot (set up by ChoosePivot)
+ // data[lo < i < a] < pivot
+ // data[a <= i < b] <= pivot
+ // data[b <= i < c] unexamined
+ // data[c <= i < hi-1] > pivot
+ // data[hi-1] >= pivot
+ pivot := lo
+ a, c := lo+1, hi-1
+
+ for ; a < c && (data[a].freq == data[pivot].freq && data[a].literal < data[pivot].literal || data[a].freq < data[pivot].freq); a++ {
+ }
+ b := a
+ for {
+ for ; b < c && (data[pivot].freq == data[b].freq && data[pivot].literal > data[b].literal || data[pivot].freq > data[b].freq); b++ { // data[b] <= pivot
+ }
+ for ; b < c && (data[pivot].freq == data[c-1].freq && data[pivot].literal < data[c-1].literal || data[pivot].freq < data[c-1].freq); c-- { // data[c-1] > pivot
+ }
+ if b >= c {
+ break
+ }
+ // data[b] > pivot; data[c-1] <= pivot
+ data[b], data[c-1] = data[c-1], data[b]
+ b++
+ c--
+ }
+ // If hi-c<3 then there are duplicates (by property of median of nine).
+ // Let's be a bit more conservative, and set border to 5.
+ protect := hi-c < 5
+ if !protect && hi-c < (hi-lo)/4 {
+ // Lets test some points for equality to pivot
+ dups := 0
+ if data[pivot].freq == data[hi-1].freq && data[pivot].literal > data[hi-1].literal || data[pivot].freq > data[hi-1].freq { // data[hi-1] = pivot
+ data[c], data[hi-1] = data[hi-1], data[c]
+ c++
+ dups++
+ }
+ if data[b-1].freq == data[pivot].freq && data[b-1].literal > data[pivot].literal || data[b-1].freq > data[pivot].freq { // data[b-1] = pivot
+ b--
+ dups++
+ }
+ // m-lo = (hi-lo)/2 > 6
+ // b-lo > (hi-lo)*3/4-1 > 8
+ // ==> m < b ==> data[m] <= pivot
+ if data[m].freq == data[pivot].freq && data[m].literal > data[pivot].literal || data[m].freq > data[pivot].freq { // data[m] = pivot
+ data[m], data[b-1] = data[b-1], data[m]
+ b--
+ dups++
+ }
+ // if at least 2 points are equal to pivot, assume skewed distribution
+ protect = dups > 1
+ }
+ if protect {
+ // Protect against a lot of duplicates
+ // Add invariant:
+ // data[a <= i < b] unexamined
+ // data[b <= i < c] = pivot
+ for {
+ for ; a < b && (data[b-1].freq == data[pivot].freq && data[b-1].literal > data[pivot].literal || data[b-1].freq > data[pivot].freq); b-- { // data[b] == pivot
+ }
+ for ; a < b && (data[a].freq == data[pivot].freq && data[a].literal < data[pivot].literal || data[a].freq < data[pivot].freq); a++ { // data[a] < pivot
+ }
+ if a >= b {
+ break
+ }
+ // data[a] == pivot; data[b-1] < pivot
+ data[a], data[b-1] = data[b-1], data[a]
+ a++
+ b--
+ }
+ }
+ // Swap pivot into middle
+ data[pivot], data[b-1] = data[b-1], data[pivot]
+ return b - 1, c
+}
+
+// Insertion sort
+func insertionSortByFreq(data []literalNode, a, b int) {
+ for i := a + 1; i < b; i++ {
+ for j := i; j > a && (data[j].freq == data[j-1].freq && data[j].literal < data[j-1].literal || data[j].freq < data[j-1].freq); j-- {
+ data[j], data[j-1] = data[j-1], data[j]
+ }
+ }
+}
+
+// quickSortByFreq, loosely following Bentley and McIlroy,
+// ``Engineering a Sort Function,'' SP&E November 1993.
+
+// medianOfThreeSortByFreq moves the median of the three values data[m0], data[m1], data[m2] into data[m1].
+func medianOfThreeSortByFreq(data []literalNode, m1, m0, m2 int) {
+ // sort 3 elements
+ if data[m1].freq == data[m0].freq && data[m1].literal < data[m0].literal || data[m1].freq < data[m0].freq {
+ data[m1], data[m0] = data[m0], data[m1]
+ }
+ // data[m0] <= data[m1]
+ if data[m2].freq == data[m1].freq && data[m2].literal < data[m1].literal || data[m2].freq < data[m1].freq {
+ data[m2], data[m1] = data[m1], data[m2]
+ // data[m0] <= data[m2] && data[m1] < data[m2]
+ if data[m1].freq == data[m0].freq && data[m1].literal < data[m0].literal || data[m1].freq < data[m0].freq {
+ data[m1], data[m0] = data[m0], data[m1]
+ }
+ }
+ // now data[m0] <= data[m1] <= data[m2]
+}
diff --git a/vendor/github.com/klauspost/compress/flate/huffman_sortByLiteral.go b/vendor/github.com/klauspost/compress/flate/huffman_sortByLiteral.go
new file mode 100644
index 0000000..93f1aea
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/flate/huffman_sortByLiteral.go
@@ -0,0 +1,201 @@
+// Copyright 2009 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 flate
+
+// Sort sorts data.
+// It makes one call to data.Len to determine n, and O(n*log(n)) calls to
+// data.Less and data.Swap. The sort is not guaranteed to be stable.
+func sortByLiteral(data []literalNode) {
+ n := len(data)
+ quickSort(data, 0, n, maxDepth(n))
+}
+
+func quickSort(data []literalNode, a, b, maxDepth int) {
+ for b-a > 12 { // Use ShellSort for slices <= 12 elements
+ if maxDepth == 0 {
+ heapSort(data, a, b)
+ return
+ }
+ maxDepth--
+ mlo, mhi := doPivot(data, a, b)
+ // Avoiding recursion on the larger subproblem guarantees
+ // a stack depth of at most lg(b-a).
+ if mlo-a < b-mhi {
+ quickSort(data, a, mlo, maxDepth)
+ a = mhi // i.e., quickSort(data, mhi, b)
+ } else {
+ quickSort(data, mhi, b, maxDepth)
+ b = mlo // i.e., quickSort(data, a, mlo)
+ }
+ }
+ if b-a > 1 {
+ // Do ShellSort pass with gap 6
+ // It could be written in this simplified form cause b-a <= 12
+ for i := a + 6; i < b; i++ {
+ if data[i].literal < data[i-6].literal {
+ data[i], data[i-6] = data[i-6], data[i]
+ }
+ }
+ insertionSort(data, a, b)
+ }
+}
+func heapSort(data []literalNode, a, b int) {
+ first := a
+ lo := 0
+ hi := b - a
+
+ // Build heap with greatest element at top.
+ for i := (hi - 1) / 2; i >= 0; i-- {
+ siftDown(data, i, hi, first)
+ }
+
+ // Pop elements, largest first, into end of data.
+ for i := hi - 1; i >= 0; i-- {
+ data[first], data[first+i] = data[first+i], data[first]
+ siftDown(data, lo, i, first)
+ }
+}
+
+// siftDown implements the heap property on data[lo, hi).
+// first is an offset into the array where the root of the heap lies.
+func siftDown(data []literalNode, lo, hi, first int) {
+ root := lo
+ for {
+ child := 2*root + 1
+ if child >= hi {
+ break
+ }
+ if child+1 < hi && data[first+child].literal < data[first+child+1].literal {
+ child++
+ }
+ if data[first+root].literal > data[first+child].literal {
+ return
+ }
+ data[first+root], data[first+child] = data[first+child], data[first+root]
+ root = child
+ }
+}
+func doPivot(data []literalNode, lo, hi int) (midlo, midhi int) {
+ m := int(uint(lo+hi) >> 1) // Written like this to avoid integer overflow.
+ if hi-lo > 40 {
+ // Tukey's ``Ninther,'' median of three medians of three.
+ s := (hi - lo) / 8
+ medianOfThree(data, lo, lo+s, lo+2*s)
+ medianOfThree(data, m, m-s, m+s)
+ medianOfThree(data, hi-1, hi-1-s, hi-1-2*s)
+ }
+ medianOfThree(data, lo, m, hi-1)
+
+ // Invariants are:
+ // data[lo] = pivot (set up by ChoosePivot)
+ // data[lo < i < a] < pivot
+ // data[a <= i < b] <= pivot
+ // data[b <= i < c] unexamined
+ // data[c <= i < hi-1] > pivot
+ // data[hi-1] >= pivot
+ pivot := lo
+ a, c := lo+1, hi-1
+
+ for ; a < c && data[a].literal < data[pivot].literal; a++ {
+ }
+ b := a
+ for {
+ for ; b < c && data[pivot].literal > data[b].literal; b++ { // data[b] <= pivot
+ }
+ for ; b < c && data[pivot].literal < data[c-1].literal; c-- { // data[c-1] > pivot
+ }
+ if b >= c {
+ break
+ }
+ // data[b] > pivot; data[c-1] <= pivot
+ data[b], data[c-1] = data[c-1], data[b]
+ b++
+ c--
+ }
+ // If hi-c<3 then there are duplicates (by property of median of nine).
+ // Let's be a bit more conservative, and set border to 5.
+ protect := hi-c < 5
+ if !protect && hi-c < (hi-lo)/4 {
+ // Lets test some points for equality to pivot
+ dups := 0
+ if data[pivot].literal > data[hi-1].literal { // data[hi-1] = pivot
+ data[c], data[hi-1] = data[hi-1], data[c]
+ c++
+ dups++
+ }
+ if data[b-1].literal > data[pivot].literal { // data[b-1] = pivot
+ b--
+ dups++
+ }
+ // m-lo = (hi-lo)/2 > 6
+ // b-lo > (hi-lo)*3/4-1 > 8
+ // ==> m < b ==> data[m] <= pivot
+ if data[m].literal > data[pivot].literal { // data[m] = pivot
+ data[m], data[b-1] = data[b-1], data[m]
+ b--
+ dups++
+ }
+ // if at least 2 points are equal to pivot, assume skewed distribution
+ protect = dups > 1
+ }
+ if protect {
+ // Protect against a lot of duplicates
+ // Add invariant:
+ // data[a <= i < b] unexamined
+ // data[b <= i < c] = pivot
+ for {
+ for ; a < b && data[b-1].literal > data[pivot].literal; b-- { // data[b] == pivot
+ }
+ for ; a < b && data[a].literal < data[pivot].literal; a++ { // data[a] < pivot
+ }
+ if a >= b {
+ break
+ }
+ // data[a] == pivot; data[b-1] < pivot
+ data[a], data[b-1] = data[b-1], data[a]
+ a++
+ b--
+ }
+ }
+ // Swap pivot into middle
+ data[pivot], data[b-1] = data[b-1], data[pivot]
+ return b - 1, c
+}
+
+// Insertion sort
+func insertionSort(data []literalNode, a, b int) {
+ for i := a + 1; i < b; i++ {
+ for j := i; j > a && data[j].literal < data[j-1].literal; j-- {
+ data[j], data[j-1] = data[j-1], data[j]
+ }
+ }
+}
+
+// maxDepth returns a threshold at which quicksort should switch
+// to heapsort. It returns 2*ceil(lg(n+1)).
+func maxDepth(n int) int {
+ var depth int
+ for i := n; i > 0; i >>= 1 {
+ depth++
+ }
+ return depth * 2
+}
+
+// medianOfThree moves the median of the three values data[m0], data[m1], data[m2] into data[m1].
+func medianOfThree(data []literalNode, m1, m0, m2 int) {
+ // sort 3 elements
+ if data[m1].literal < data[m0].literal {
+ data[m1], data[m0] = data[m0], data[m1]
+ }
+ // data[m0] <= data[m1]
+ if data[m2].literal < data[m1].literal {
+ data[m2], data[m1] = data[m1], data[m2]
+ // data[m0] <= data[m2] && data[m1] < data[m2]
+ if data[m1].literal < data[m0].literal {
+ data[m1], data[m0] = data[m0], data[m1]
+ }
+ }
+ // now data[m0] <= data[m1] <= data[m2]
+}
diff --git a/vendor/github.com/klauspost/compress/flate/inflate.go b/vendor/github.com/klauspost/compress/flate/inflate.go
new file mode 100644
index 0000000..2f410d6
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/flate/inflate.go
@@ -0,0 +1,829 @@
+// Copyright 2009 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 flate implements the DEFLATE compressed data format, described in
+// RFC 1951. The gzip and zlib packages implement access to DEFLATE-based file
+// formats.
+package flate
+
+import (
+ "bufio"
+ "compress/flate"
+ "fmt"
+ "io"
+ "math/bits"
+ "sync"
+)
+
+const (
+ maxCodeLen = 16 // max length of Huffman code
+ maxCodeLenMask = 15 // mask for max length of Huffman code
+ // The next three numbers come from the RFC section 3.2.7, with the
+ // additional proviso in section 3.2.5 which implies that distance codes
+ // 30 and 31 should never occur in compressed data.
+ maxNumLit = 286
+ maxNumDist = 30
+ numCodes = 19 // number of codes in Huffman meta-code
+
+ debugDecode = false
+)
+
+// Value of length - 3 and extra bits.
+type lengthExtra struct {
+ length, extra uint8
+}
+
+var decCodeToLen = [32]lengthExtra{{length: 0x0, extra: 0x0}, {length: 0x1, extra: 0x0}, {length: 0x2, extra: 0x0}, {length: 0x3, extra: 0x0}, {length: 0x4, extra: 0x0}, {length: 0x5, extra: 0x0}, {length: 0x6, extra: 0x0}, {length: 0x7, extra: 0x0}, {length: 0x8, extra: 0x1}, {length: 0xa, extra: 0x1}, {length: 0xc, extra: 0x1}, {length: 0xe, extra: 0x1}, {length: 0x10, extra: 0x2}, {length: 0x14, extra: 0x2}, {length: 0x18, extra: 0x2}, {length: 0x1c, extra: 0x2}, {length: 0x20, extra: 0x3}, {length: 0x28, extra: 0x3}, {length: 0x30, extra: 0x3}, {length: 0x38, extra: 0x3}, {length: 0x40, extra: 0x4}, {length: 0x50, extra: 0x4}, {length: 0x60, extra: 0x4}, {length: 0x70, extra: 0x4}, {length: 0x80, extra: 0x5}, {length: 0xa0, extra: 0x5}, {length: 0xc0, extra: 0x5}, {length: 0xe0, extra: 0x5}, {length: 0xff, extra: 0x0}, {length: 0x0, extra: 0x0}, {length: 0x0, extra: 0x0}, {length: 0x0, extra: 0x0}}
+
+var bitMask32 = [32]uint32{
+ 0, 1, 3, 7, 0xF, 0x1F, 0x3F, 0x7F, 0xFF,
+ 0x1FF, 0x3FF, 0x7FF, 0xFFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF,
+ 0x1ffff, 0x3ffff, 0x7FFFF, 0xfFFFF, 0x1fFFFF, 0x3fFFFF, 0x7fFFFF, 0xffFFFF,
+ 0x1ffFFFF, 0x3ffFFFF, 0x7ffFFFF, 0xfffFFFF, 0x1fffFFFF, 0x3fffFFFF, 0x7fffFFFF,
+} // up to 32 bits
+
+// Initialize the fixedHuffmanDecoder only once upon first use.
+var fixedOnce sync.Once
+var fixedHuffmanDecoder huffmanDecoder
+
+// A CorruptInputError reports the presence of corrupt input at a given offset.
+type CorruptInputError = flate.CorruptInputError
+
+// An InternalError reports an error in the flate code itself.
+type InternalError string
+
+func (e InternalError) Error() string { return "flate: internal error: " + string(e) }
+
+// A ReadError reports an error encountered while reading input.
+//
+// Deprecated: No longer returned.
+type ReadError = flate.ReadError
+
+// A WriteError reports an error encountered while writing output.
+//
+// Deprecated: No longer returned.
+type WriteError = flate.WriteError
+
+// Resetter resets a ReadCloser returned by NewReader or NewReaderDict to
+// to switch to a new underlying Reader. This permits reusing a ReadCloser
+// instead of allocating a new one.
+type Resetter interface {
+ // Reset discards any buffered data and resets the Resetter as if it was
+ // newly initialized with the given reader.
+ Reset(r io.Reader, dict []byte) error
+}
+
+// The data structure for decoding Huffman tables is based on that of
+// zlib. There is a lookup table of a fixed bit width (huffmanChunkBits),
+// For codes smaller than the table width, there are multiple entries
+// (each combination of trailing bits has the same value). For codes
+// larger than the table width, the table contains a link to an overflow
+// table. The width of each entry in the link table is the maximum code
+// size minus the chunk width.
+//
+// Note that you can do a lookup in the table even without all bits
+// filled. Since the extra bits are zero, and the DEFLATE Huffman codes
+// have the property that shorter codes come before longer ones, the
+// bit length estimate in the result is a lower bound on the actual
+// number of bits.
+//
+// See the following:
+// http://www.gzip.org/algorithm.txt
+
+// chunk & 15 is number of bits
+// chunk >> 4 is value, including table link
+
+const (
+ huffmanChunkBits = 9
+ huffmanNumChunks = 1 << huffmanChunkBits
+ huffmanCountMask = 15
+ huffmanValueShift = 4
+)
+
+type huffmanDecoder struct {
+ maxRead int // the maximum number of bits we can read and not overread
+ chunks *[huffmanNumChunks]uint16 // chunks as described above
+ links [][]uint16 // overflow links
+ linkMask uint32 // mask the width of the link table
+}
+
+// Initialize Huffman decoding tables from array of code lengths.
+// Following this function, h is guaranteed to be initialized into a complete
+// tree (i.e., neither over-subscribed nor under-subscribed). The exception is a
+// degenerate case where the tree has only a single symbol with length 1. Empty
+// trees are permitted.
+func (h *huffmanDecoder) init(lengths []int) bool {
+ // Sanity enables additional runtime tests during Huffman
+ // table construction. It's intended to be used during
+ // development to supplement the currently ad-hoc unit tests.
+ const sanity = false
+
+ if h.chunks == nil {
+ h.chunks = new([huffmanNumChunks]uint16)
+ }
+
+ if h.maxRead != 0 {
+ *h = huffmanDecoder{chunks: h.chunks, links: h.links}
+ }
+
+ // Count number of codes of each length,
+ // compute maxRead and max length.
+ var count [maxCodeLen]int
+ var min, max int
+ for _, n := range lengths {
+ if n == 0 {
+ continue
+ }
+ if min == 0 || n < min {
+ min = n
+ }
+ if n > max {
+ max = n
+ }
+ count[n&maxCodeLenMask]++
+ }
+
+ // Empty tree. The decompressor.huffSym function will fail later if the tree
+ // is used. Technically, an empty tree is only valid for the HDIST tree and
+ // not the HCLEN and HLIT tree. However, a stream with an empty HCLEN tree
+ // is guaranteed to fail since it will attempt to use the tree to decode the
+ // codes for the HLIT and HDIST trees. Similarly, an empty HLIT tree is
+ // guaranteed to fail later since the compressed data section must be
+ // composed of at least one symbol (the end-of-block marker).
+ if max == 0 {
+ return true
+ }
+
+ code := 0
+ var nextcode [maxCodeLen]int
+ for i := min; i <= max; i++ {
+ code <<= 1
+ nextcode[i&maxCodeLenMask] = code
+ code += count[i&maxCodeLenMask]
+ }
+
+ // Check that the coding is complete (i.e., that we've
+ // assigned all 2-to-the-max possible bit sequences).
+ // Exception: To be compatible with zlib, we also need to
+ // accept degenerate single-code codings. See also
+ // TestDegenerateHuffmanCoding.
+ if code != 1< huffmanChunkBits {
+ numLinks := 1 << (uint(max) - huffmanChunkBits)
+ h.linkMask = uint32(numLinks - 1)
+
+ // create link tables
+ link := nextcode[huffmanChunkBits+1] >> 1
+ if cap(h.links) < huffmanNumChunks-link {
+ h.links = make([][]uint16, huffmanNumChunks-link)
+ } else {
+ h.links = h.links[:huffmanNumChunks-link]
+ }
+ for j := uint(link); j < huffmanNumChunks; j++ {
+ reverse := int(bits.Reverse16(uint16(j)))
+ reverse >>= uint(16 - huffmanChunkBits)
+ off := j - uint(link)
+ if sanity && h.chunks[reverse] != 0 {
+ panic("impossible: overwriting existing chunk")
+ }
+ h.chunks[reverse] = uint16(off<>= uint(16 - n)
+ if n <= huffmanChunkBits {
+ for off := reverse; off < len(h.chunks); off += 1 << uint(n) {
+ // We should never need to overwrite
+ // an existing chunk. Also, 0 is
+ // never a valid chunk, because the
+ // lower 4 "count" bits should be
+ // between 1 and 15.
+ if sanity && h.chunks[off] != 0 {
+ panic("impossible: overwriting existing chunk")
+ }
+ h.chunks[off] = chunk
+ }
+ } else {
+ j := reverse & (huffmanNumChunks - 1)
+ if sanity && h.chunks[j]&huffmanCountMask != huffmanChunkBits+1 {
+ // Longer codes should have been
+ // associated with a link table above.
+ panic("impossible: not an indirect chunk")
+ }
+ value := h.chunks[j] >> huffmanValueShift
+ linktab := h.links[value]
+ reverse >>= huffmanChunkBits
+ for off := reverse; off < len(linktab); off += 1 << uint(n-huffmanChunkBits) {
+ if sanity && linktab[off] != 0 {
+ panic("impossible: overwriting existing chunk")
+ }
+ linktab[off] = chunk
+ }
+ }
+ }
+
+ if sanity {
+ // Above we've sanity checked that we never overwrote
+ // an existing entry. Here we additionally check that
+ // we filled the tables completely.
+ for i, chunk := range h.chunks {
+ if chunk == 0 {
+ // As an exception, in the degenerate
+ // single-code case, we allow odd
+ // chunks to be missing.
+ if code == 1 && i%2 == 1 {
+ continue
+ }
+ panic("impossible: missing chunk")
+ }
+ }
+ for _, linktab := range h.links {
+ for _, chunk := range linktab {
+ if chunk == 0 {
+ panic("impossible: missing chunk")
+ }
+ }
+ }
+ }
+
+ return true
+}
+
+// Reader is the actual read interface needed by NewReader.
+// If the passed in io.Reader does not also have ReadByte,
+// the NewReader will introduce its own buffering.
+type Reader interface {
+ io.Reader
+ io.ByteReader
+}
+
+type step uint8
+
+const (
+ copyData step = iota + 1
+ nextBlock
+ huffmanBytesBuffer
+ huffmanBytesReader
+ huffmanBufioReader
+ huffmanStringsReader
+ huffmanGenericReader
+)
+
+// Decompress state.
+type decompressor struct {
+ // Input source.
+ r Reader
+ roffset int64
+
+ // Huffman decoders for literal/length, distance.
+ h1, h2 huffmanDecoder
+
+ // Length arrays used to define Huffman codes.
+ bits *[maxNumLit + maxNumDist]int
+ codebits *[numCodes]int
+
+ // Output history, buffer.
+ dict dictDecoder
+
+ // Next step in the decompression,
+ // and decompression state.
+ step step
+ stepState int
+ err error
+ toRead []byte
+ hl, hd *huffmanDecoder
+ copyLen int
+ copyDist int
+
+ // Temporary buffer (avoids repeated allocation).
+ buf [4]byte
+
+ // Input bits, in top of b.
+ b uint32
+
+ nb uint
+ final bool
+}
+
+func (f *decompressor) nextBlock() {
+ for f.nb < 1+2 {
+ if f.err = f.moreBits(); f.err != nil {
+ return
+ }
+ }
+ f.final = f.b&1 == 1
+ f.b >>= 1
+ typ := f.b & 3
+ f.b >>= 2
+ f.nb -= 1 + 2
+ switch typ {
+ case 0:
+ f.dataBlock()
+ if debugDecode {
+ fmt.Println("stored block")
+ }
+ case 1:
+ // compressed, fixed Huffman tables
+ f.hl = &fixedHuffmanDecoder
+ f.hd = nil
+ f.huffmanBlockDecoder()
+ if debugDecode {
+ fmt.Println("predefinied huffman block")
+ }
+ case 2:
+ // compressed, dynamic Huffman tables
+ if f.err = f.readHuffman(); f.err != nil {
+ break
+ }
+ f.hl = &f.h1
+ f.hd = &f.h2
+ f.huffmanBlockDecoder()
+ if debugDecode {
+ fmt.Println("dynamic huffman block")
+ }
+ default:
+ // 3 is reserved.
+ if debugDecode {
+ fmt.Println("reserved data block encountered")
+ }
+ f.err = CorruptInputError(f.roffset)
+ }
+}
+
+func (f *decompressor) Read(b []byte) (int, error) {
+ for {
+ if len(f.toRead) > 0 {
+ n := copy(b, f.toRead)
+ f.toRead = f.toRead[n:]
+ if len(f.toRead) == 0 {
+ return n, f.err
+ }
+ return n, nil
+ }
+ if f.err != nil {
+ return 0, f.err
+ }
+
+ f.doStep()
+
+ if f.err != nil && len(f.toRead) == 0 {
+ f.toRead = f.dict.readFlush() // Flush what's left in case of error
+ }
+ }
+}
+
+// WriteTo implements the io.WriteTo interface for io.Copy and friends.
+func (f *decompressor) WriteTo(w io.Writer) (int64, error) {
+ total := int64(0)
+ flushed := false
+ for {
+ if len(f.toRead) > 0 {
+ n, err := w.Write(f.toRead)
+ total += int64(n)
+ if err != nil {
+ f.err = err
+ return total, err
+ }
+ if n != len(f.toRead) {
+ return total, io.ErrShortWrite
+ }
+ f.toRead = f.toRead[:0]
+ }
+ if f.err != nil && flushed {
+ if f.err == io.EOF {
+ return total, nil
+ }
+ return total, f.err
+ }
+ if f.err == nil {
+ f.doStep()
+ }
+ if len(f.toRead) == 0 && f.err != nil && !flushed {
+ f.toRead = f.dict.readFlush() // Flush what's left in case of error
+ flushed = true
+ }
+ }
+}
+
+func (f *decompressor) Close() error {
+ if f.err == io.EOF {
+ return nil
+ }
+ return f.err
+}
+
+// RFC 1951 section 3.2.7.
+// Compression with dynamic Huffman codes
+
+var codeOrder = [...]int{16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}
+
+func (f *decompressor) readHuffman() error {
+ // HLIT[5], HDIST[5], HCLEN[4].
+ for f.nb < 5+5+4 {
+ if err := f.moreBits(); err != nil {
+ return err
+ }
+ }
+ nlit := int(f.b&0x1F) + 257
+ if nlit > maxNumLit {
+ if debugDecode {
+ fmt.Println("nlit > maxNumLit", nlit)
+ }
+ return CorruptInputError(f.roffset)
+ }
+ f.b >>= 5
+ ndist := int(f.b&0x1F) + 1
+ if ndist > maxNumDist {
+ if debugDecode {
+ fmt.Println("ndist > maxNumDist", ndist)
+ }
+ return CorruptInputError(f.roffset)
+ }
+ f.b >>= 5
+ nclen := int(f.b&0xF) + 4
+ // numCodes is 19, so nclen is always valid.
+ f.b >>= 4
+ f.nb -= 5 + 5 + 4
+
+ // (HCLEN+4)*3 bits: code lengths in the magic codeOrder order.
+ for i := 0; i < nclen; i++ {
+ for f.nb < 3 {
+ if err := f.moreBits(); err != nil {
+ return err
+ }
+ }
+ f.codebits[codeOrder[i]] = int(f.b & 0x7)
+ f.b >>= 3
+ f.nb -= 3
+ }
+ for i := nclen; i < len(codeOrder); i++ {
+ f.codebits[codeOrder[i]] = 0
+ }
+ if !f.h1.init(f.codebits[0:]) {
+ if debugDecode {
+ fmt.Println("init codebits failed")
+ }
+ return CorruptInputError(f.roffset)
+ }
+
+ // HLIT + 257 code lengths, HDIST + 1 code lengths,
+ // using the code length Huffman code.
+ for i, n := 0, nlit+ndist; i < n; {
+ x, err := f.huffSym(&f.h1)
+ if err != nil {
+ return err
+ }
+ if x < 16 {
+ // Actual length.
+ f.bits[i] = x
+ i++
+ continue
+ }
+ // Repeat previous length or zero.
+ var rep int
+ var nb uint
+ var b int
+ switch x {
+ default:
+ return InternalError("unexpected length code")
+ case 16:
+ rep = 3
+ nb = 2
+ if i == 0 {
+ if debugDecode {
+ fmt.Println("i==0")
+ }
+ return CorruptInputError(f.roffset)
+ }
+ b = f.bits[i-1]
+ case 17:
+ rep = 3
+ nb = 3
+ b = 0
+ case 18:
+ rep = 11
+ nb = 7
+ b = 0
+ }
+ for f.nb < nb {
+ if err := f.moreBits(); err != nil {
+ if debugDecode {
+ fmt.Println("morebits:", err)
+ }
+ return err
+ }
+ }
+ rep += int(f.b & uint32(1<<(nb®SizeMaskUint32)-1))
+ f.b >>= nb & regSizeMaskUint32
+ f.nb -= nb
+ if i+rep > n {
+ if debugDecode {
+ fmt.Println("i+rep > n", i, rep, n)
+ }
+ return CorruptInputError(f.roffset)
+ }
+ for j := 0; j < rep; j++ {
+ f.bits[i] = b
+ i++
+ }
+ }
+
+ if !f.h1.init(f.bits[0:nlit]) || !f.h2.init(f.bits[nlit:nlit+ndist]) {
+ if debugDecode {
+ fmt.Println("init2 failed")
+ }
+ return CorruptInputError(f.roffset)
+ }
+
+ // As an optimization, we can initialize the maxRead bits to read at a time
+ // for the HLIT tree to the length of the EOB marker since we know that
+ // every block must terminate with one. This preserves the property that
+ // we never read any extra bytes after the end of the DEFLATE stream.
+ if f.h1.maxRead < f.bits[endBlockMarker] {
+ f.h1.maxRead = f.bits[endBlockMarker]
+ }
+ if !f.final {
+ // If not the final block, the smallest block possible is
+ // a predefined table, BTYPE=01, with a single EOB marker.
+ // This will take up 3 + 7 bits.
+ f.h1.maxRead += 10
+ }
+
+ return nil
+}
+
+// Copy a single uncompressed data block from input to output.
+func (f *decompressor) dataBlock() {
+ // Uncompressed.
+ // Discard current half-byte.
+ left := (f.nb) & 7
+ f.nb -= left
+ f.b >>= left
+
+ offBytes := f.nb >> 3
+ // Unfilled values will be overwritten.
+ f.buf[0] = uint8(f.b)
+ f.buf[1] = uint8(f.b >> 8)
+ f.buf[2] = uint8(f.b >> 16)
+ f.buf[3] = uint8(f.b >> 24)
+
+ f.roffset += int64(offBytes)
+ f.nb, f.b = 0, 0
+
+ // Length then ones-complement of length.
+ nr, err := io.ReadFull(f.r, f.buf[offBytes:4])
+ f.roffset += int64(nr)
+ if err != nil {
+ f.err = noEOF(err)
+ return
+ }
+ n := uint16(f.buf[0]) | uint16(f.buf[1])<<8
+ nn := uint16(f.buf[2]) | uint16(f.buf[3])<<8
+ if nn != ^n {
+ if debugDecode {
+ ncomp := ^n
+ fmt.Println("uint16(nn) != uint16(^n)", nn, ncomp)
+ }
+ f.err = CorruptInputError(f.roffset)
+ return
+ }
+
+ if n == 0 {
+ f.toRead = f.dict.readFlush()
+ f.finishBlock()
+ return
+ }
+
+ f.copyLen = int(n)
+ f.copyData()
+}
+
+// copyData copies f.copyLen bytes from the underlying reader into f.hist.
+// It pauses for reads when f.hist is full.
+func (f *decompressor) copyData() {
+ buf := f.dict.writeSlice()
+ if len(buf) > f.copyLen {
+ buf = buf[:f.copyLen]
+ }
+
+ cnt, err := io.ReadFull(f.r, buf)
+ f.roffset += int64(cnt)
+ f.copyLen -= cnt
+ f.dict.writeMark(cnt)
+ if err != nil {
+ f.err = noEOF(err)
+ return
+ }
+
+ if f.dict.availWrite() == 0 || f.copyLen > 0 {
+ f.toRead = f.dict.readFlush()
+ f.step = copyData
+ return
+ }
+ f.finishBlock()
+}
+
+func (f *decompressor) finishBlock() {
+ if f.final {
+ if f.dict.availRead() > 0 {
+ f.toRead = f.dict.readFlush()
+ }
+ f.err = io.EOF
+ }
+ f.step = nextBlock
+}
+
+func (f *decompressor) doStep() {
+ switch f.step {
+ case copyData:
+ f.copyData()
+ case nextBlock:
+ f.nextBlock()
+ case huffmanBytesBuffer:
+ f.huffmanBytesBuffer()
+ case huffmanBytesReader:
+ f.huffmanBytesReader()
+ case huffmanBufioReader:
+ f.huffmanBufioReader()
+ case huffmanStringsReader:
+ f.huffmanStringsReader()
+ case huffmanGenericReader:
+ f.huffmanGenericReader()
+ default:
+ panic("BUG: unexpected step state")
+ }
+}
+
+// noEOF returns err, unless err == io.EOF, in which case it returns io.ErrUnexpectedEOF.
+func noEOF(e error) error {
+ if e == io.EOF {
+ return io.ErrUnexpectedEOF
+ }
+ return e
+}
+
+func (f *decompressor) moreBits() error {
+ c, err := f.r.ReadByte()
+ if err != nil {
+ return noEOF(err)
+ }
+ f.roffset++
+ f.b |= uint32(c) << (f.nb & regSizeMaskUint32)
+ f.nb += 8
+ return nil
+}
+
+// Read the next Huffman-encoded symbol from f according to h.
+func (f *decompressor) huffSym(h *huffmanDecoder) (int, error) {
+ // Since a huffmanDecoder can be empty or be composed of a degenerate tree
+ // with single element, huffSym must error on these two edge cases. In both
+ // cases, the chunks slice will be 0 for the invalid sequence, leading it
+ // satisfy the n == 0 check below.
+ n := uint(h.maxRead)
+ // Optimization. Compiler isn't smart enough to keep f.b,f.nb in registers,
+ // but is smart enough to keep local variables in registers, so use nb and b,
+ // inline call to moreBits and reassign b,nb back to f on return.
+ nb, b := f.nb, f.b
+ for {
+ for nb < n {
+ c, err := f.r.ReadByte()
+ if err != nil {
+ f.b = b
+ f.nb = nb
+ return 0, noEOF(err)
+ }
+ f.roffset++
+ b |= uint32(c) << (nb & regSizeMaskUint32)
+ nb += 8
+ }
+ chunk := h.chunks[b&(huffmanNumChunks-1)]
+ n = uint(chunk & huffmanCountMask)
+ if n > huffmanChunkBits {
+ chunk = h.links[chunk>>huffmanValueShift][(b>>huffmanChunkBits)&h.linkMask]
+ n = uint(chunk & huffmanCountMask)
+ }
+ if n <= nb {
+ if n == 0 {
+ f.b = b
+ f.nb = nb
+ if debugDecode {
+ fmt.Println("huffsym: n==0")
+ }
+ f.err = CorruptInputError(f.roffset)
+ return 0, f.err
+ }
+ f.b = b >> (n & regSizeMaskUint32)
+ f.nb = nb - n
+ return int(chunk >> huffmanValueShift), nil
+ }
+ }
+}
+
+func makeReader(r io.Reader) Reader {
+ if rr, ok := r.(Reader); ok {
+ return rr
+ }
+ return bufio.NewReader(r)
+}
+
+func fixedHuffmanDecoderInit() {
+ fixedOnce.Do(func() {
+ // These come from the RFC section 3.2.6.
+ var bits [288]int
+ for i := 0; i < 144; i++ {
+ bits[i] = 8
+ }
+ for i := 144; i < 256; i++ {
+ bits[i] = 9
+ }
+ for i := 256; i < 280; i++ {
+ bits[i] = 7
+ }
+ for i := 280; i < 288; i++ {
+ bits[i] = 8
+ }
+ fixedHuffmanDecoder.init(bits[:])
+ })
+}
+
+func (f *decompressor) Reset(r io.Reader, dict []byte) error {
+ *f = decompressor{
+ r: makeReader(r),
+ bits: f.bits,
+ codebits: f.codebits,
+ h1: f.h1,
+ h2: f.h2,
+ dict: f.dict,
+ step: nextBlock,
+ }
+ f.dict.init(maxMatchOffset, dict)
+ return nil
+}
+
+// NewReader returns a new ReadCloser that can be used
+// to read the uncompressed version of r.
+// If r does not also implement io.ByteReader,
+// the decompressor may read more data than necessary from r.
+// It is the caller's responsibility to call Close on the ReadCloser
+// when finished reading.
+//
+// The ReadCloser returned by NewReader also implements Resetter.
+func NewReader(r io.Reader) io.ReadCloser {
+ fixedHuffmanDecoderInit()
+
+ var f decompressor
+ f.r = makeReader(r)
+ f.bits = new([maxNumLit + maxNumDist]int)
+ f.codebits = new([numCodes]int)
+ f.step = nextBlock
+ f.dict.init(maxMatchOffset, nil)
+ return &f
+}
+
+// NewReaderDict is like NewReader but initializes the reader
+// with a preset dictionary. The returned Reader behaves as if
+// the uncompressed data stream started with the given dictionary,
+// which has already been read. NewReaderDict is typically used
+// to read data compressed by NewWriterDict.
+//
+// The ReadCloser returned by NewReader also implements Resetter.
+func NewReaderDict(r io.Reader, dict []byte) io.ReadCloser {
+ fixedHuffmanDecoderInit()
+
+ var f decompressor
+ f.r = makeReader(r)
+ f.bits = new([maxNumLit + maxNumDist]int)
+ f.codebits = new([numCodes]int)
+ f.step = nextBlock
+ f.dict.init(maxMatchOffset, dict)
+ return &f
+}
diff --git a/vendor/github.com/klauspost/compress/flate/inflate_gen.go b/vendor/github.com/klauspost/compress/flate/inflate_gen.go
new file mode 100644
index 0000000..2b2f993
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/flate/inflate_gen.go
@@ -0,0 +1,1283 @@
+// Code generated by go generate gen_inflate.go. DO NOT EDIT.
+
+package flate
+
+import (
+ "bufio"
+ "bytes"
+ "fmt"
+ "math/bits"
+ "strings"
+)
+
+// Decode a single Huffman block from f.
+// hl and hd are the Huffman states for the lit/length values
+// and the distance values, respectively. If hd == nil, using the
+// fixed distance encoding associated with fixed Huffman blocks.
+func (f *decompressor) huffmanBytesBuffer() {
+ const (
+ stateInit = iota // Zero value must be stateInit
+ stateDict
+ )
+ fr := f.r.(*bytes.Buffer)
+
+ // Optimization. Compiler isn't smart enough to keep f.b,f.nb in registers,
+ // but is smart enough to keep local variables in registers, so use nb and b,
+ // inline call to moreBits and reassign b,nb back to f on return.
+ fnb, fb, dict := f.nb, f.b, &f.dict
+
+ switch f.stepState {
+ case stateInit:
+ goto readLiteral
+ case stateDict:
+ goto copyHistory
+ }
+
+readLiteral:
+ // Read literal and/or (length, distance) according to RFC section 3.2.3.
+ {
+ var v int
+ {
+ // Inlined v, err := f.huffSym(f.hl)
+ // Since a huffmanDecoder can be empty or be composed of a degenerate tree
+ // with single element, huffSym must error on these two edge cases. In both
+ // cases, the chunks slice will be 0 for the invalid sequence, leading it
+ // satisfy the n == 0 check below.
+ n := uint(f.hl.maxRead)
+ for {
+ for fnb < n {
+ c, err := fr.ReadByte()
+ if err != nil {
+ f.b, f.nb = fb, fnb
+ f.err = noEOF(err)
+ return
+ }
+ f.roffset++
+ fb |= uint32(c) << (fnb & regSizeMaskUint32)
+ fnb += 8
+ }
+ chunk := f.hl.chunks[fb&(huffmanNumChunks-1)]
+ n = uint(chunk & huffmanCountMask)
+ if n > huffmanChunkBits {
+ chunk = f.hl.links[chunk>>huffmanValueShift][(fb>>huffmanChunkBits)&f.hl.linkMask]
+ n = uint(chunk & huffmanCountMask)
+ }
+ if n <= fnb {
+ if n == 0 {
+ f.b, f.nb = fb, fnb
+ if debugDecode {
+ fmt.Println("huffsym: n==0")
+ }
+ f.err = CorruptInputError(f.roffset)
+ return
+ }
+ fb = fb >> (n & regSizeMaskUint32)
+ fnb = fnb - n
+ v = int(chunk >> huffmanValueShift)
+ break
+ }
+ }
+ }
+
+ var length int
+ switch {
+ case v < 256:
+ dict.writeByte(byte(v))
+ if dict.availWrite() == 0 {
+ f.toRead = dict.readFlush()
+ f.step = huffmanBytesBuffer
+ f.stepState = stateInit
+ f.b, f.nb = fb, fnb
+ return
+ }
+ goto readLiteral
+ case v == 256:
+ f.b, f.nb = fb, fnb
+ f.finishBlock()
+ return
+ // otherwise, reference to older data
+ case v < 265:
+ length = v - (257 - 3)
+ case v < maxNumLit:
+ val := decCodeToLen[(v - 257)]
+ length = int(val.length) + 3
+ n := uint(val.extra)
+ for fnb < n {
+ c, err := fr.ReadByte()
+ if err != nil {
+ f.b, f.nb = fb, fnb
+ if debugDecode {
+ fmt.Println("morebits n>0:", err)
+ }
+ f.err = err
+ return
+ }
+ f.roffset++
+ fb |= uint32(c) << (fnb & regSizeMaskUint32)
+ fnb += 8
+ }
+ length += int(fb & bitMask32[n])
+ fb >>= n & regSizeMaskUint32
+ fnb -= n
+ default:
+ if debugDecode {
+ fmt.Println(v, ">= maxNumLit")
+ }
+ f.err = CorruptInputError(f.roffset)
+ f.b, f.nb = fb, fnb
+ return
+ }
+
+ var dist uint32
+ if f.hd == nil {
+ for fnb < 5 {
+ c, err := fr.ReadByte()
+ if err != nil {
+ f.b, f.nb = fb, fnb
+ if debugDecode {
+ fmt.Println("morebits f.nb<5:", err)
+ }
+ f.err = err
+ return
+ }
+ f.roffset++
+ fb |= uint32(c) << (fnb & regSizeMaskUint32)
+ fnb += 8
+ }
+ dist = uint32(bits.Reverse8(uint8(fb & 0x1F << 3)))
+ fb >>= 5
+ fnb -= 5
+ } else {
+ // Since a huffmanDecoder can be empty or be composed of a degenerate tree
+ // with single element, huffSym must error on these two edge cases. In both
+ // cases, the chunks slice will be 0 for the invalid sequence, leading it
+ // satisfy the n == 0 check below.
+ n := uint(f.hd.maxRead)
+ // Optimization. Compiler isn't smart enough to keep f.b,f.nb in registers,
+ // but is smart enough to keep local variables in registers, so use nb and b,
+ // inline call to moreBits and reassign b,nb back to f on return.
+ for {
+ for fnb < n {
+ c, err := fr.ReadByte()
+ if err != nil {
+ f.b, f.nb = fb, fnb
+ f.err = noEOF(err)
+ return
+ }
+ f.roffset++
+ fb |= uint32(c) << (fnb & regSizeMaskUint32)
+ fnb += 8
+ }
+ chunk := f.hd.chunks[fb&(huffmanNumChunks-1)]
+ n = uint(chunk & huffmanCountMask)
+ if n > huffmanChunkBits {
+ chunk = f.hd.links[chunk>>huffmanValueShift][(fb>>huffmanChunkBits)&f.hd.linkMask]
+ n = uint(chunk & huffmanCountMask)
+ }
+ if n <= fnb {
+ if n == 0 {
+ f.b, f.nb = fb, fnb
+ if debugDecode {
+ fmt.Println("huffsym: n==0")
+ }
+ f.err = CorruptInputError(f.roffset)
+ return
+ }
+ fb = fb >> (n & regSizeMaskUint32)
+ fnb = fnb - n
+ dist = uint32(chunk >> huffmanValueShift)
+ break
+ }
+ }
+ }
+
+ switch {
+ case dist < 4:
+ dist++
+ case dist < maxNumDist:
+ nb := uint(dist-2) >> 1
+ // have 1 bit in bottom of dist, need nb more.
+ extra := (dist & 1) << (nb & regSizeMaskUint32)
+ for fnb < nb {
+ c, err := fr.ReadByte()
+ if err != nil {
+ f.b, f.nb = fb, fnb
+ if debugDecode {
+ fmt.Println("morebits f.nb>= nb & regSizeMaskUint32
+ fnb -= nb
+ dist = 1<<((nb+1)®SizeMaskUint32) + 1 + extra
+ // slower: dist = bitMask32[nb+1] + 2 + extra
+ default:
+ f.b, f.nb = fb, fnb
+ if debugDecode {
+ fmt.Println("dist too big:", dist, maxNumDist)
+ }
+ f.err = CorruptInputError(f.roffset)
+ return
+ }
+
+ // No check on length; encoding can be prescient.
+ if dist > uint32(dict.histSize()) {
+ f.b, f.nb = fb, fnb
+ if debugDecode {
+ fmt.Println("dist > dict.histSize():", dist, dict.histSize())
+ }
+ f.err = CorruptInputError(f.roffset)
+ return
+ }
+
+ f.copyLen, f.copyDist = length, int(dist)
+ goto copyHistory
+ }
+
+copyHistory:
+ // Perform a backwards copy according to RFC section 3.2.3.
+ {
+ cnt := dict.tryWriteCopy(f.copyDist, f.copyLen)
+ if cnt == 0 {
+ cnt = dict.writeCopy(f.copyDist, f.copyLen)
+ }
+ f.copyLen -= cnt
+
+ if dict.availWrite() == 0 || f.copyLen > 0 {
+ f.toRead = dict.readFlush()
+ f.step = huffmanBytesBuffer // We need to continue this work
+ f.stepState = stateDict
+ f.b, f.nb = fb, fnb
+ return
+ }
+ goto readLiteral
+ }
+ // Not reached
+}
+
+// Decode a single Huffman block from f.
+// hl and hd are the Huffman states for the lit/length values
+// and the distance values, respectively. If hd == nil, using the
+// fixed distance encoding associated with fixed Huffman blocks.
+func (f *decompressor) huffmanBytesReader() {
+ const (
+ stateInit = iota // Zero value must be stateInit
+ stateDict
+ )
+ fr := f.r.(*bytes.Reader)
+
+ // Optimization. Compiler isn't smart enough to keep f.b,f.nb in registers,
+ // but is smart enough to keep local variables in registers, so use nb and b,
+ // inline call to moreBits and reassign b,nb back to f on return.
+ fnb, fb, dict := f.nb, f.b, &f.dict
+
+ switch f.stepState {
+ case stateInit:
+ goto readLiteral
+ case stateDict:
+ goto copyHistory
+ }
+
+readLiteral:
+ // Read literal and/or (length, distance) according to RFC section 3.2.3.
+ {
+ var v int
+ {
+ // Inlined v, err := f.huffSym(f.hl)
+ // Since a huffmanDecoder can be empty or be composed of a degenerate tree
+ // with single element, huffSym must error on these two edge cases. In both
+ // cases, the chunks slice will be 0 for the invalid sequence, leading it
+ // satisfy the n == 0 check below.
+ n := uint(f.hl.maxRead)
+ for {
+ for fnb < n {
+ c, err := fr.ReadByte()
+ if err != nil {
+ f.b, f.nb = fb, fnb
+ f.err = noEOF(err)
+ return
+ }
+ f.roffset++
+ fb |= uint32(c) << (fnb & regSizeMaskUint32)
+ fnb += 8
+ }
+ chunk := f.hl.chunks[fb&(huffmanNumChunks-1)]
+ n = uint(chunk & huffmanCountMask)
+ if n > huffmanChunkBits {
+ chunk = f.hl.links[chunk>>huffmanValueShift][(fb>>huffmanChunkBits)&f.hl.linkMask]
+ n = uint(chunk & huffmanCountMask)
+ }
+ if n <= fnb {
+ if n == 0 {
+ f.b, f.nb = fb, fnb
+ if debugDecode {
+ fmt.Println("huffsym: n==0")
+ }
+ f.err = CorruptInputError(f.roffset)
+ return
+ }
+ fb = fb >> (n & regSizeMaskUint32)
+ fnb = fnb - n
+ v = int(chunk >> huffmanValueShift)
+ break
+ }
+ }
+ }
+
+ var length int
+ switch {
+ case v < 256:
+ dict.writeByte(byte(v))
+ if dict.availWrite() == 0 {
+ f.toRead = dict.readFlush()
+ f.step = huffmanBytesReader
+ f.stepState = stateInit
+ f.b, f.nb = fb, fnb
+ return
+ }
+ goto readLiteral
+ case v == 256:
+ f.b, f.nb = fb, fnb
+ f.finishBlock()
+ return
+ // otherwise, reference to older data
+ case v < 265:
+ length = v - (257 - 3)
+ case v < maxNumLit:
+ val := decCodeToLen[(v - 257)]
+ length = int(val.length) + 3
+ n := uint(val.extra)
+ for fnb < n {
+ c, err := fr.ReadByte()
+ if err != nil {
+ f.b, f.nb = fb, fnb
+ if debugDecode {
+ fmt.Println("morebits n>0:", err)
+ }
+ f.err = err
+ return
+ }
+ f.roffset++
+ fb |= uint32(c) << (fnb & regSizeMaskUint32)
+ fnb += 8
+ }
+ length += int(fb & bitMask32[n])
+ fb >>= n & regSizeMaskUint32
+ fnb -= n
+ default:
+ if debugDecode {
+ fmt.Println(v, ">= maxNumLit")
+ }
+ f.err = CorruptInputError(f.roffset)
+ f.b, f.nb = fb, fnb
+ return
+ }
+
+ var dist uint32
+ if f.hd == nil {
+ for fnb < 5 {
+ c, err := fr.ReadByte()
+ if err != nil {
+ f.b, f.nb = fb, fnb
+ if debugDecode {
+ fmt.Println("morebits f.nb<5:", err)
+ }
+ f.err = err
+ return
+ }
+ f.roffset++
+ fb |= uint32(c) << (fnb & regSizeMaskUint32)
+ fnb += 8
+ }
+ dist = uint32(bits.Reverse8(uint8(fb & 0x1F << 3)))
+ fb >>= 5
+ fnb -= 5
+ } else {
+ // Since a huffmanDecoder can be empty or be composed of a degenerate tree
+ // with single element, huffSym must error on these two edge cases. In both
+ // cases, the chunks slice will be 0 for the invalid sequence, leading it
+ // satisfy the n == 0 check below.
+ n := uint(f.hd.maxRead)
+ // Optimization. Compiler isn't smart enough to keep f.b,f.nb in registers,
+ // but is smart enough to keep local variables in registers, so use nb and b,
+ // inline call to moreBits and reassign b,nb back to f on return.
+ for {
+ for fnb < n {
+ c, err := fr.ReadByte()
+ if err != nil {
+ f.b, f.nb = fb, fnb
+ f.err = noEOF(err)
+ return
+ }
+ f.roffset++
+ fb |= uint32(c) << (fnb & regSizeMaskUint32)
+ fnb += 8
+ }
+ chunk := f.hd.chunks[fb&(huffmanNumChunks-1)]
+ n = uint(chunk & huffmanCountMask)
+ if n > huffmanChunkBits {
+ chunk = f.hd.links[chunk>>huffmanValueShift][(fb>>huffmanChunkBits)&f.hd.linkMask]
+ n = uint(chunk & huffmanCountMask)
+ }
+ if n <= fnb {
+ if n == 0 {
+ f.b, f.nb = fb, fnb
+ if debugDecode {
+ fmt.Println("huffsym: n==0")
+ }
+ f.err = CorruptInputError(f.roffset)
+ return
+ }
+ fb = fb >> (n & regSizeMaskUint32)
+ fnb = fnb - n
+ dist = uint32(chunk >> huffmanValueShift)
+ break
+ }
+ }
+ }
+
+ switch {
+ case dist < 4:
+ dist++
+ case dist < maxNumDist:
+ nb := uint(dist-2) >> 1
+ // have 1 bit in bottom of dist, need nb more.
+ extra := (dist & 1) << (nb & regSizeMaskUint32)
+ for fnb < nb {
+ c, err := fr.ReadByte()
+ if err != nil {
+ f.b, f.nb = fb, fnb
+ if debugDecode {
+ fmt.Println("morebits f.nb>= nb & regSizeMaskUint32
+ fnb -= nb
+ dist = 1<<((nb+1)®SizeMaskUint32) + 1 + extra
+ // slower: dist = bitMask32[nb+1] + 2 + extra
+ default:
+ f.b, f.nb = fb, fnb
+ if debugDecode {
+ fmt.Println("dist too big:", dist, maxNumDist)
+ }
+ f.err = CorruptInputError(f.roffset)
+ return
+ }
+
+ // No check on length; encoding can be prescient.
+ if dist > uint32(dict.histSize()) {
+ f.b, f.nb = fb, fnb
+ if debugDecode {
+ fmt.Println("dist > dict.histSize():", dist, dict.histSize())
+ }
+ f.err = CorruptInputError(f.roffset)
+ return
+ }
+
+ f.copyLen, f.copyDist = length, int(dist)
+ goto copyHistory
+ }
+
+copyHistory:
+ // Perform a backwards copy according to RFC section 3.2.3.
+ {
+ cnt := dict.tryWriteCopy(f.copyDist, f.copyLen)
+ if cnt == 0 {
+ cnt = dict.writeCopy(f.copyDist, f.copyLen)
+ }
+ f.copyLen -= cnt
+
+ if dict.availWrite() == 0 || f.copyLen > 0 {
+ f.toRead = dict.readFlush()
+ f.step = huffmanBytesReader // We need to continue this work
+ f.stepState = stateDict
+ f.b, f.nb = fb, fnb
+ return
+ }
+ goto readLiteral
+ }
+ // Not reached
+}
+
+// Decode a single Huffman block from f.
+// hl and hd are the Huffman states for the lit/length values
+// and the distance values, respectively. If hd == nil, using the
+// fixed distance encoding associated with fixed Huffman blocks.
+func (f *decompressor) huffmanBufioReader() {
+ const (
+ stateInit = iota // Zero value must be stateInit
+ stateDict
+ )
+ fr := f.r.(*bufio.Reader)
+
+ // Optimization. Compiler isn't smart enough to keep f.b,f.nb in registers,
+ // but is smart enough to keep local variables in registers, so use nb and b,
+ // inline call to moreBits and reassign b,nb back to f on return.
+ fnb, fb, dict := f.nb, f.b, &f.dict
+
+ switch f.stepState {
+ case stateInit:
+ goto readLiteral
+ case stateDict:
+ goto copyHistory
+ }
+
+readLiteral:
+ // Read literal and/or (length, distance) according to RFC section 3.2.3.
+ {
+ var v int
+ {
+ // Inlined v, err := f.huffSym(f.hl)
+ // Since a huffmanDecoder can be empty or be composed of a degenerate tree
+ // with single element, huffSym must error on these two edge cases. In both
+ // cases, the chunks slice will be 0 for the invalid sequence, leading it
+ // satisfy the n == 0 check below.
+ n := uint(f.hl.maxRead)
+ for {
+ for fnb < n {
+ c, err := fr.ReadByte()
+ if err != nil {
+ f.b, f.nb = fb, fnb
+ f.err = noEOF(err)
+ return
+ }
+ f.roffset++
+ fb |= uint32(c) << (fnb & regSizeMaskUint32)
+ fnb += 8
+ }
+ chunk := f.hl.chunks[fb&(huffmanNumChunks-1)]
+ n = uint(chunk & huffmanCountMask)
+ if n > huffmanChunkBits {
+ chunk = f.hl.links[chunk>>huffmanValueShift][(fb>>huffmanChunkBits)&f.hl.linkMask]
+ n = uint(chunk & huffmanCountMask)
+ }
+ if n <= fnb {
+ if n == 0 {
+ f.b, f.nb = fb, fnb
+ if debugDecode {
+ fmt.Println("huffsym: n==0")
+ }
+ f.err = CorruptInputError(f.roffset)
+ return
+ }
+ fb = fb >> (n & regSizeMaskUint32)
+ fnb = fnb - n
+ v = int(chunk >> huffmanValueShift)
+ break
+ }
+ }
+ }
+
+ var length int
+ switch {
+ case v < 256:
+ dict.writeByte(byte(v))
+ if dict.availWrite() == 0 {
+ f.toRead = dict.readFlush()
+ f.step = huffmanBufioReader
+ f.stepState = stateInit
+ f.b, f.nb = fb, fnb
+ return
+ }
+ goto readLiteral
+ case v == 256:
+ f.b, f.nb = fb, fnb
+ f.finishBlock()
+ return
+ // otherwise, reference to older data
+ case v < 265:
+ length = v - (257 - 3)
+ case v < maxNumLit:
+ val := decCodeToLen[(v - 257)]
+ length = int(val.length) + 3
+ n := uint(val.extra)
+ for fnb < n {
+ c, err := fr.ReadByte()
+ if err != nil {
+ f.b, f.nb = fb, fnb
+ if debugDecode {
+ fmt.Println("morebits n>0:", err)
+ }
+ f.err = err
+ return
+ }
+ f.roffset++
+ fb |= uint32(c) << (fnb & regSizeMaskUint32)
+ fnb += 8
+ }
+ length += int(fb & bitMask32[n])
+ fb >>= n & regSizeMaskUint32
+ fnb -= n
+ default:
+ if debugDecode {
+ fmt.Println(v, ">= maxNumLit")
+ }
+ f.err = CorruptInputError(f.roffset)
+ f.b, f.nb = fb, fnb
+ return
+ }
+
+ var dist uint32
+ if f.hd == nil {
+ for fnb < 5 {
+ c, err := fr.ReadByte()
+ if err != nil {
+ f.b, f.nb = fb, fnb
+ if debugDecode {
+ fmt.Println("morebits f.nb<5:", err)
+ }
+ f.err = err
+ return
+ }
+ f.roffset++
+ fb |= uint32(c) << (fnb & regSizeMaskUint32)
+ fnb += 8
+ }
+ dist = uint32(bits.Reverse8(uint8(fb & 0x1F << 3)))
+ fb >>= 5
+ fnb -= 5
+ } else {
+ // Since a huffmanDecoder can be empty or be composed of a degenerate tree
+ // with single element, huffSym must error on these two edge cases. In both
+ // cases, the chunks slice will be 0 for the invalid sequence, leading it
+ // satisfy the n == 0 check below.
+ n := uint(f.hd.maxRead)
+ // Optimization. Compiler isn't smart enough to keep f.b,f.nb in registers,
+ // but is smart enough to keep local variables in registers, so use nb and b,
+ // inline call to moreBits and reassign b,nb back to f on return.
+ for {
+ for fnb < n {
+ c, err := fr.ReadByte()
+ if err != nil {
+ f.b, f.nb = fb, fnb
+ f.err = noEOF(err)
+ return
+ }
+ f.roffset++
+ fb |= uint32(c) << (fnb & regSizeMaskUint32)
+ fnb += 8
+ }
+ chunk := f.hd.chunks[fb&(huffmanNumChunks-1)]
+ n = uint(chunk & huffmanCountMask)
+ if n > huffmanChunkBits {
+ chunk = f.hd.links[chunk>>huffmanValueShift][(fb>>huffmanChunkBits)&f.hd.linkMask]
+ n = uint(chunk & huffmanCountMask)
+ }
+ if n <= fnb {
+ if n == 0 {
+ f.b, f.nb = fb, fnb
+ if debugDecode {
+ fmt.Println("huffsym: n==0")
+ }
+ f.err = CorruptInputError(f.roffset)
+ return
+ }
+ fb = fb >> (n & regSizeMaskUint32)
+ fnb = fnb - n
+ dist = uint32(chunk >> huffmanValueShift)
+ break
+ }
+ }
+ }
+
+ switch {
+ case dist < 4:
+ dist++
+ case dist < maxNumDist:
+ nb := uint(dist-2) >> 1
+ // have 1 bit in bottom of dist, need nb more.
+ extra := (dist & 1) << (nb & regSizeMaskUint32)
+ for fnb < nb {
+ c, err := fr.ReadByte()
+ if err != nil {
+ f.b, f.nb = fb, fnb
+ if debugDecode {
+ fmt.Println("morebits f.nb>= nb & regSizeMaskUint32
+ fnb -= nb
+ dist = 1<<((nb+1)®SizeMaskUint32) + 1 + extra
+ // slower: dist = bitMask32[nb+1] + 2 + extra
+ default:
+ f.b, f.nb = fb, fnb
+ if debugDecode {
+ fmt.Println("dist too big:", dist, maxNumDist)
+ }
+ f.err = CorruptInputError(f.roffset)
+ return
+ }
+
+ // No check on length; encoding can be prescient.
+ if dist > uint32(dict.histSize()) {
+ f.b, f.nb = fb, fnb
+ if debugDecode {
+ fmt.Println("dist > dict.histSize():", dist, dict.histSize())
+ }
+ f.err = CorruptInputError(f.roffset)
+ return
+ }
+
+ f.copyLen, f.copyDist = length, int(dist)
+ goto copyHistory
+ }
+
+copyHistory:
+ // Perform a backwards copy according to RFC section 3.2.3.
+ {
+ cnt := dict.tryWriteCopy(f.copyDist, f.copyLen)
+ if cnt == 0 {
+ cnt = dict.writeCopy(f.copyDist, f.copyLen)
+ }
+ f.copyLen -= cnt
+
+ if dict.availWrite() == 0 || f.copyLen > 0 {
+ f.toRead = dict.readFlush()
+ f.step = huffmanBufioReader // We need to continue this work
+ f.stepState = stateDict
+ f.b, f.nb = fb, fnb
+ return
+ }
+ goto readLiteral
+ }
+ // Not reached
+}
+
+// Decode a single Huffman block from f.
+// hl and hd are the Huffman states for the lit/length values
+// and the distance values, respectively. If hd == nil, using the
+// fixed distance encoding associated with fixed Huffman blocks.
+func (f *decompressor) huffmanStringsReader() {
+ const (
+ stateInit = iota // Zero value must be stateInit
+ stateDict
+ )
+ fr := f.r.(*strings.Reader)
+
+ // Optimization. Compiler isn't smart enough to keep f.b,f.nb in registers,
+ // but is smart enough to keep local variables in registers, so use nb and b,
+ // inline call to moreBits and reassign b,nb back to f on return.
+ fnb, fb, dict := f.nb, f.b, &f.dict
+
+ switch f.stepState {
+ case stateInit:
+ goto readLiteral
+ case stateDict:
+ goto copyHistory
+ }
+
+readLiteral:
+ // Read literal and/or (length, distance) according to RFC section 3.2.3.
+ {
+ var v int
+ {
+ // Inlined v, err := f.huffSym(f.hl)
+ // Since a huffmanDecoder can be empty or be composed of a degenerate tree
+ // with single element, huffSym must error on these two edge cases. In both
+ // cases, the chunks slice will be 0 for the invalid sequence, leading it
+ // satisfy the n == 0 check below.
+ n := uint(f.hl.maxRead)
+ for {
+ for fnb < n {
+ c, err := fr.ReadByte()
+ if err != nil {
+ f.b, f.nb = fb, fnb
+ f.err = noEOF(err)
+ return
+ }
+ f.roffset++
+ fb |= uint32(c) << (fnb & regSizeMaskUint32)
+ fnb += 8
+ }
+ chunk := f.hl.chunks[fb&(huffmanNumChunks-1)]
+ n = uint(chunk & huffmanCountMask)
+ if n > huffmanChunkBits {
+ chunk = f.hl.links[chunk>>huffmanValueShift][(fb>>huffmanChunkBits)&f.hl.linkMask]
+ n = uint(chunk & huffmanCountMask)
+ }
+ if n <= fnb {
+ if n == 0 {
+ f.b, f.nb = fb, fnb
+ if debugDecode {
+ fmt.Println("huffsym: n==0")
+ }
+ f.err = CorruptInputError(f.roffset)
+ return
+ }
+ fb = fb >> (n & regSizeMaskUint32)
+ fnb = fnb - n
+ v = int(chunk >> huffmanValueShift)
+ break
+ }
+ }
+ }
+
+ var length int
+ switch {
+ case v < 256:
+ dict.writeByte(byte(v))
+ if dict.availWrite() == 0 {
+ f.toRead = dict.readFlush()
+ f.step = huffmanStringsReader
+ f.stepState = stateInit
+ f.b, f.nb = fb, fnb
+ return
+ }
+ goto readLiteral
+ case v == 256:
+ f.b, f.nb = fb, fnb
+ f.finishBlock()
+ return
+ // otherwise, reference to older data
+ case v < 265:
+ length = v - (257 - 3)
+ case v < maxNumLit:
+ val := decCodeToLen[(v - 257)]
+ length = int(val.length) + 3
+ n := uint(val.extra)
+ for fnb < n {
+ c, err := fr.ReadByte()
+ if err != nil {
+ f.b, f.nb = fb, fnb
+ if debugDecode {
+ fmt.Println("morebits n>0:", err)
+ }
+ f.err = err
+ return
+ }
+ f.roffset++
+ fb |= uint32(c) << (fnb & regSizeMaskUint32)
+ fnb += 8
+ }
+ length += int(fb & bitMask32[n])
+ fb >>= n & regSizeMaskUint32
+ fnb -= n
+ default:
+ if debugDecode {
+ fmt.Println(v, ">= maxNumLit")
+ }
+ f.err = CorruptInputError(f.roffset)
+ f.b, f.nb = fb, fnb
+ return
+ }
+
+ var dist uint32
+ if f.hd == nil {
+ for fnb < 5 {
+ c, err := fr.ReadByte()
+ if err != nil {
+ f.b, f.nb = fb, fnb
+ if debugDecode {
+ fmt.Println("morebits f.nb<5:", err)
+ }
+ f.err = err
+ return
+ }
+ f.roffset++
+ fb |= uint32(c) << (fnb & regSizeMaskUint32)
+ fnb += 8
+ }
+ dist = uint32(bits.Reverse8(uint8(fb & 0x1F << 3)))
+ fb >>= 5
+ fnb -= 5
+ } else {
+ // Since a huffmanDecoder can be empty or be composed of a degenerate tree
+ // with single element, huffSym must error on these two edge cases. In both
+ // cases, the chunks slice will be 0 for the invalid sequence, leading it
+ // satisfy the n == 0 check below.
+ n := uint(f.hd.maxRead)
+ // Optimization. Compiler isn't smart enough to keep f.b,f.nb in registers,
+ // but is smart enough to keep local variables in registers, so use nb and b,
+ // inline call to moreBits and reassign b,nb back to f on return.
+ for {
+ for fnb < n {
+ c, err := fr.ReadByte()
+ if err != nil {
+ f.b, f.nb = fb, fnb
+ f.err = noEOF(err)
+ return
+ }
+ f.roffset++
+ fb |= uint32(c) << (fnb & regSizeMaskUint32)
+ fnb += 8
+ }
+ chunk := f.hd.chunks[fb&(huffmanNumChunks-1)]
+ n = uint(chunk & huffmanCountMask)
+ if n > huffmanChunkBits {
+ chunk = f.hd.links[chunk>>huffmanValueShift][(fb>>huffmanChunkBits)&f.hd.linkMask]
+ n = uint(chunk & huffmanCountMask)
+ }
+ if n <= fnb {
+ if n == 0 {
+ f.b, f.nb = fb, fnb
+ if debugDecode {
+ fmt.Println("huffsym: n==0")
+ }
+ f.err = CorruptInputError(f.roffset)
+ return
+ }
+ fb = fb >> (n & regSizeMaskUint32)
+ fnb = fnb - n
+ dist = uint32(chunk >> huffmanValueShift)
+ break
+ }
+ }
+ }
+
+ switch {
+ case dist < 4:
+ dist++
+ case dist < maxNumDist:
+ nb := uint(dist-2) >> 1
+ // have 1 bit in bottom of dist, need nb more.
+ extra := (dist & 1) << (nb & regSizeMaskUint32)
+ for fnb < nb {
+ c, err := fr.ReadByte()
+ if err != nil {
+ f.b, f.nb = fb, fnb
+ if debugDecode {
+ fmt.Println("morebits f.nb>= nb & regSizeMaskUint32
+ fnb -= nb
+ dist = 1<<((nb+1)®SizeMaskUint32) + 1 + extra
+ // slower: dist = bitMask32[nb+1] + 2 + extra
+ default:
+ f.b, f.nb = fb, fnb
+ if debugDecode {
+ fmt.Println("dist too big:", dist, maxNumDist)
+ }
+ f.err = CorruptInputError(f.roffset)
+ return
+ }
+
+ // No check on length; encoding can be prescient.
+ if dist > uint32(dict.histSize()) {
+ f.b, f.nb = fb, fnb
+ if debugDecode {
+ fmt.Println("dist > dict.histSize():", dist, dict.histSize())
+ }
+ f.err = CorruptInputError(f.roffset)
+ return
+ }
+
+ f.copyLen, f.copyDist = length, int(dist)
+ goto copyHistory
+ }
+
+copyHistory:
+ // Perform a backwards copy according to RFC section 3.2.3.
+ {
+ cnt := dict.tryWriteCopy(f.copyDist, f.copyLen)
+ if cnt == 0 {
+ cnt = dict.writeCopy(f.copyDist, f.copyLen)
+ }
+ f.copyLen -= cnt
+
+ if dict.availWrite() == 0 || f.copyLen > 0 {
+ f.toRead = dict.readFlush()
+ f.step = huffmanStringsReader // We need to continue this work
+ f.stepState = stateDict
+ f.b, f.nb = fb, fnb
+ return
+ }
+ goto readLiteral
+ }
+ // Not reached
+}
+
+// Decode a single Huffman block from f.
+// hl and hd are the Huffman states for the lit/length values
+// and the distance values, respectively. If hd == nil, using the
+// fixed distance encoding associated with fixed Huffman blocks.
+func (f *decompressor) huffmanGenericReader() {
+ const (
+ stateInit = iota // Zero value must be stateInit
+ stateDict
+ )
+ fr := f.r.(Reader)
+
+ // Optimization. Compiler isn't smart enough to keep f.b,f.nb in registers,
+ // but is smart enough to keep local variables in registers, so use nb and b,
+ // inline call to moreBits and reassign b,nb back to f on return.
+ fnb, fb, dict := f.nb, f.b, &f.dict
+
+ switch f.stepState {
+ case stateInit:
+ goto readLiteral
+ case stateDict:
+ goto copyHistory
+ }
+
+readLiteral:
+ // Read literal and/or (length, distance) according to RFC section 3.2.3.
+ {
+ var v int
+ {
+ // Inlined v, err := f.huffSym(f.hl)
+ // Since a huffmanDecoder can be empty or be composed of a degenerate tree
+ // with single element, huffSym must error on these two edge cases. In both
+ // cases, the chunks slice will be 0 for the invalid sequence, leading it
+ // satisfy the n == 0 check below.
+ n := uint(f.hl.maxRead)
+ for {
+ for fnb < n {
+ c, err := fr.ReadByte()
+ if err != nil {
+ f.b, f.nb = fb, fnb
+ f.err = noEOF(err)
+ return
+ }
+ f.roffset++
+ fb |= uint32(c) << (fnb & regSizeMaskUint32)
+ fnb += 8
+ }
+ chunk := f.hl.chunks[fb&(huffmanNumChunks-1)]
+ n = uint(chunk & huffmanCountMask)
+ if n > huffmanChunkBits {
+ chunk = f.hl.links[chunk>>huffmanValueShift][(fb>>huffmanChunkBits)&f.hl.linkMask]
+ n = uint(chunk & huffmanCountMask)
+ }
+ if n <= fnb {
+ if n == 0 {
+ f.b, f.nb = fb, fnb
+ if debugDecode {
+ fmt.Println("huffsym: n==0")
+ }
+ f.err = CorruptInputError(f.roffset)
+ return
+ }
+ fb = fb >> (n & regSizeMaskUint32)
+ fnb = fnb - n
+ v = int(chunk >> huffmanValueShift)
+ break
+ }
+ }
+ }
+
+ var length int
+ switch {
+ case v < 256:
+ dict.writeByte(byte(v))
+ if dict.availWrite() == 0 {
+ f.toRead = dict.readFlush()
+ f.step = huffmanGenericReader
+ f.stepState = stateInit
+ f.b, f.nb = fb, fnb
+ return
+ }
+ goto readLiteral
+ case v == 256:
+ f.b, f.nb = fb, fnb
+ f.finishBlock()
+ return
+ // otherwise, reference to older data
+ case v < 265:
+ length = v - (257 - 3)
+ case v < maxNumLit:
+ val := decCodeToLen[(v - 257)]
+ length = int(val.length) + 3
+ n := uint(val.extra)
+ for fnb < n {
+ c, err := fr.ReadByte()
+ if err != nil {
+ f.b, f.nb = fb, fnb
+ if debugDecode {
+ fmt.Println("morebits n>0:", err)
+ }
+ f.err = err
+ return
+ }
+ f.roffset++
+ fb |= uint32(c) << (fnb & regSizeMaskUint32)
+ fnb += 8
+ }
+ length += int(fb & bitMask32[n])
+ fb >>= n & regSizeMaskUint32
+ fnb -= n
+ default:
+ if debugDecode {
+ fmt.Println(v, ">= maxNumLit")
+ }
+ f.err = CorruptInputError(f.roffset)
+ f.b, f.nb = fb, fnb
+ return
+ }
+
+ var dist uint32
+ if f.hd == nil {
+ for fnb < 5 {
+ c, err := fr.ReadByte()
+ if err != nil {
+ f.b, f.nb = fb, fnb
+ if debugDecode {
+ fmt.Println("morebits f.nb<5:", err)
+ }
+ f.err = err
+ return
+ }
+ f.roffset++
+ fb |= uint32(c) << (fnb & regSizeMaskUint32)
+ fnb += 8
+ }
+ dist = uint32(bits.Reverse8(uint8(fb & 0x1F << 3)))
+ fb >>= 5
+ fnb -= 5
+ } else {
+ // Since a huffmanDecoder can be empty or be composed of a degenerate tree
+ // with single element, huffSym must error on these two edge cases. In both
+ // cases, the chunks slice will be 0 for the invalid sequence, leading it
+ // satisfy the n == 0 check below.
+ n := uint(f.hd.maxRead)
+ // Optimization. Compiler isn't smart enough to keep f.b,f.nb in registers,
+ // but is smart enough to keep local variables in registers, so use nb and b,
+ // inline call to moreBits and reassign b,nb back to f on return.
+ for {
+ for fnb < n {
+ c, err := fr.ReadByte()
+ if err != nil {
+ f.b, f.nb = fb, fnb
+ f.err = noEOF(err)
+ return
+ }
+ f.roffset++
+ fb |= uint32(c) << (fnb & regSizeMaskUint32)
+ fnb += 8
+ }
+ chunk := f.hd.chunks[fb&(huffmanNumChunks-1)]
+ n = uint(chunk & huffmanCountMask)
+ if n > huffmanChunkBits {
+ chunk = f.hd.links[chunk>>huffmanValueShift][(fb>>huffmanChunkBits)&f.hd.linkMask]
+ n = uint(chunk & huffmanCountMask)
+ }
+ if n <= fnb {
+ if n == 0 {
+ f.b, f.nb = fb, fnb
+ if debugDecode {
+ fmt.Println("huffsym: n==0")
+ }
+ f.err = CorruptInputError(f.roffset)
+ return
+ }
+ fb = fb >> (n & regSizeMaskUint32)
+ fnb = fnb - n
+ dist = uint32(chunk >> huffmanValueShift)
+ break
+ }
+ }
+ }
+
+ switch {
+ case dist < 4:
+ dist++
+ case dist < maxNumDist:
+ nb := uint(dist-2) >> 1
+ // have 1 bit in bottom of dist, need nb more.
+ extra := (dist & 1) << (nb & regSizeMaskUint32)
+ for fnb < nb {
+ c, err := fr.ReadByte()
+ if err != nil {
+ f.b, f.nb = fb, fnb
+ if debugDecode {
+ fmt.Println("morebits f.nb>= nb & regSizeMaskUint32
+ fnb -= nb
+ dist = 1<<((nb+1)®SizeMaskUint32) + 1 + extra
+ // slower: dist = bitMask32[nb+1] + 2 + extra
+ default:
+ f.b, f.nb = fb, fnb
+ if debugDecode {
+ fmt.Println("dist too big:", dist, maxNumDist)
+ }
+ f.err = CorruptInputError(f.roffset)
+ return
+ }
+
+ // No check on length; encoding can be prescient.
+ if dist > uint32(dict.histSize()) {
+ f.b, f.nb = fb, fnb
+ if debugDecode {
+ fmt.Println("dist > dict.histSize():", dist, dict.histSize())
+ }
+ f.err = CorruptInputError(f.roffset)
+ return
+ }
+
+ f.copyLen, f.copyDist = length, int(dist)
+ goto copyHistory
+ }
+
+copyHistory:
+ // Perform a backwards copy according to RFC section 3.2.3.
+ {
+ cnt := dict.tryWriteCopy(f.copyDist, f.copyLen)
+ if cnt == 0 {
+ cnt = dict.writeCopy(f.copyDist, f.copyLen)
+ }
+ f.copyLen -= cnt
+
+ if dict.availWrite() == 0 || f.copyLen > 0 {
+ f.toRead = dict.readFlush()
+ f.step = huffmanGenericReader // We need to continue this work
+ f.stepState = stateDict
+ f.b, f.nb = fb, fnb
+ return
+ }
+ goto readLiteral
+ }
+ // Not reached
+}
+
+func (f *decompressor) huffmanBlockDecoder() {
+ switch f.r.(type) {
+ case *bytes.Buffer:
+ f.huffmanBytesBuffer()
+ case *bytes.Reader:
+ f.huffmanBytesReader()
+ case *bufio.Reader:
+ f.huffmanBufioReader()
+ case *strings.Reader:
+ f.huffmanStringsReader()
+ case Reader:
+ f.huffmanGenericReader()
+ default:
+ f.huffmanGenericReader()
+ }
+}
diff --git a/vendor/github.com/klauspost/compress/flate/level1.go b/vendor/github.com/klauspost/compress/flate/level1.go
new file mode 100644
index 0000000..703b9a8
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/flate/level1.go
@@ -0,0 +1,241 @@
+package flate
+
+import (
+ "encoding/binary"
+ "fmt"
+ "math/bits"
+)
+
+// fastGen maintains the table for matches,
+// and the previous byte block for level 2.
+// This is the generic implementation.
+type fastEncL1 struct {
+ fastGen
+ table [tableSize]tableEntry
+}
+
+// EncodeL1 uses a similar algorithm to level 1
+func (e *fastEncL1) Encode(dst *tokens, src []byte) {
+ const (
+ inputMargin = 12 - 1
+ minNonLiteralBlockSize = 1 + 1 + inputMargin
+ hashBytes = 5
+ )
+ if debugDeflate && e.cur < 0 {
+ panic(fmt.Sprint("e.cur < 0: ", e.cur))
+ }
+
+ // Protect against e.cur wraparound.
+ for e.cur >= bufferReset {
+ if len(e.hist) == 0 {
+ for i := range e.table[:] {
+ e.table[i] = tableEntry{}
+ }
+ e.cur = maxMatchOffset
+ break
+ }
+ // Shift down everything in the table that isn't already too far away.
+ minOff := e.cur + int32(len(e.hist)) - maxMatchOffset
+ for i := range e.table[:] {
+ v := e.table[i].offset
+ if v <= minOff {
+ v = 0
+ } else {
+ v = v - e.cur + maxMatchOffset
+ }
+ e.table[i].offset = v
+ }
+ e.cur = maxMatchOffset
+ }
+
+ s := e.addBlock(src)
+
+ // This check isn't in the Snappy implementation, but there, the caller
+ // instead of the callee handles this case.
+ if len(src) < minNonLiteralBlockSize {
+ // We do not fill the token table.
+ // This will be picked up by caller.
+ dst.n = uint16(len(src))
+ return
+ }
+
+ // Override src
+ src = e.hist
+ nextEmit := s
+
+ // sLimit is when to stop looking for offset/length copies. The inputMargin
+ // lets us use a fast path for emitLiteral in the main loop, while we are
+ // looking for copies.
+ sLimit := int32(len(src) - inputMargin)
+
+ // nextEmit is where in src the next emitLiteral should start from.
+ cv := load6432(src, s)
+
+ for {
+ const skipLog = 5
+ const doEvery = 2
+
+ nextS := s
+ var candidate tableEntry
+ for {
+ nextHash := hashLen(cv, tableBits, hashBytes)
+ candidate = e.table[nextHash]
+ nextS = s + doEvery + (s-nextEmit)>>skipLog
+ if nextS > sLimit {
+ goto emitRemainder
+ }
+
+ now := load6432(src, nextS)
+ e.table[nextHash] = tableEntry{offset: s + e.cur}
+ nextHash = hashLen(now, tableBits, hashBytes)
+
+ offset := s - (candidate.offset - e.cur)
+ if offset < maxMatchOffset && uint32(cv) == load3232(src, candidate.offset-e.cur) {
+ e.table[nextHash] = tableEntry{offset: nextS + e.cur}
+ break
+ }
+
+ // Do one right away...
+ cv = now
+ s = nextS
+ nextS++
+ candidate = e.table[nextHash]
+ now >>= 8
+ e.table[nextHash] = tableEntry{offset: s + e.cur}
+
+ offset = s - (candidate.offset - e.cur)
+ if offset < maxMatchOffset && uint32(cv) == load3232(src, candidate.offset-e.cur) {
+ e.table[nextHash] = tableEntry{offset: nextS + e.cur}
+ break
+ }
+ cv = now
+ s = nextS
+ }
+
+ // A 4-byte match has been found. We'll later see if more than 4 bytes
+ // match. But, prior to the match, src[nextEmit:s] are unmatched. Emit
+ // them as literal bytes.
+ for {
+ // Invariant: we have a 4-byte match at s, and no need to emit any
+ // literal bytes prior to s.
+
+ // Extend the 4-byte match as long as possible.
+ t := candidate.offset - e.cur
+ var l = int32(4)
+ if false {
+ l = e.matchlenLong(s+4, t+4, src) + 4
+ } else {
+ // inlined:
+ a := src[s+4:]
+ b := src[t+4:]
+ for len(a) >= 8 {
+ if diff := binary.LittleEndian.Uint64(a) ^ binary.LittleEndian.Uint64(b); diff != 0 {
+ l += int32(bits.TrailingZeros64(diff) >> 3)
+ break
+ }
+ l += 8
+ a = a[8:]
+ b = b[8:]
+ }
+ if len(a) < 8 {
+ b = b[:len(a)]
+ for i := range a {
+ if a[i] != b[i] {
+ break
+ }
+ l++
+ }
+ }
+ }
+
+ // Extend backwards
+ for t > 0 && s > nextEmit && src[t-1] == src[s-1] {
+ s--
+ t--
+ l++
+ }
+ if nextEmit < s {
+ if false {
+ emitLiteral(dst, src[nextEmit:s])
+ } else {
+ for _, v := range src[nextEmit:s] {
+ dst.tokens[dst.n] = token(v)
+ dst.litHist[v]++
+ dst.n++
+ }
+ }
+ }
+
+ // Save the match found
+ if false {
+ dst.AddMatchLong(l, uint32(s-t-baseMatchOffset))
+ } else {
+ // Inlined...
+ xoffset := uint32(s - t - baseMatchOffset)
+ xlength := l
+ oc := offsetCode(xoffset)
+ xoffset |= oc << 16
+ for xlength > 0 {
+ xl := xlength
+ if xl > 258 {
+ if xl > 258+baseMatchLength {
+ xl = 258
+ } else {
+ xl = 258 - baseMatchLength
+ }
+ }
+ xlength -= xl
+ xl -= baseMatchLength
+ dst.extraHist[lengthCodes1[uint8(xl)]]++
+ dst.offHist[oc]++
+ dst.tokens[dst.n] = token(matchType | uint32(xl)<= s {
+ s = nextS + 1
+ }
+ if s >= sLimit {
+ // Index first pair after match end.
+ if int(s+l+8) < len(src) {
+ cv := load6432(src, s)
+ e.table[hashLen(cv, tableBits, hashBytes)] = tableEntry{offset: s + e.cur}
+ }
+ goto emitRemainder
+ }
+
+ // We could immediately start working at s now, but to improve
+ // compression we first update the hash table at s-2 and at s. If
+ // another emitCopy is not our next move, also calculate nextHash
+ // at s+1. At least on GOARCH=amd64, these three hash calculations
+ // are faster as one load64 call (with some shifts) instead of
+ // three load32 calls.
+ x := load6432(src, s-2)
+ o := e.cur + s - 2
+ prevHash := hashLen(x, tableBits, hashBytes)
+ e.table[prevHash] = tableEntry{offset: o}
+ x >>= 16
+ currHash := hashLen(x, tableBits, hashBytes)
+ candidate = e.table[currHash]
+ e.table[currHash] = tableEntry{offset: o + 2}
+
+ offset := s - (candidate.offset - e.cur)
+ if offset > maxMatchOffset || uint32(x) != load3232(src, candidate.offset-e.cur) {
+ cv = x >> 8
+ s++
+ break
+ }
+ }
+ }
+
+emitRemainder:
+ if int(nextEmit) < len(src) {
+ // If nothing was added, don't encode literals.
+ if dst.n == 0 {
+ return
+ }
+ emitLiteral(dst, src[nextEmit:])
+ }
+}
diff --git a/vendor/github.com/klauspost/compress/flate/level2.go b/vendor/github.com/klauspost/compress/flate/level2.go
new file mode 100644
index 0000000..876dfbe
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/flate/level2.go
@@ -0,0 +1,214 @@
+package flate
+
+import "fmt"
+
+// fastGen maintains the table for matches,
+// and the previous byte block for level 2.
+// This is the generic implementation.
+type fastEncL2 struct {
+ fastGen
+ table [bTableSize]tableEntry
+}
+
+// EncodeL2 uses a similar algorithm to level 1, but is capable
+// of matching across blocks giving better compression at a small slowdown.
+func (e *fastEncL2) Encode(dst *tokens, src []byte) {
+ const (
+ inputMargin = 12 - 1
+ minNonLiteralBlockSize = 1 + 1 + inputMargin
+ hashBytes = 5
+ )
+
+ if debugDeflate && e.cur < 0 {
+ panic(fmt.Sprint("e.cur < 0: ", e.cur))
+ }
+
+ // Protect against e.cur wraparound.
+ for e.cur >= bufferReset {
+ if len(e.hist) == 0 {
+ for i := range e.table[:] {
+ e.table[i] = tableEntry{}
+ }
+ e.cur = maxMatchOffset
+ break
+ }
+ // Shift down everything in the table that isn't already too far away.
+ minOff := e.cur + int32(len(e.hist)) - maxMatchOffset
+ for i := range e.table[:] {
+ v := e.table[i].offset
+ if v <= minOff {
+ v = 0
+ } else {
+ v = v - e.cur + maxMatchOffset
+ }
+ e.table[i].offset = v
+ }
+ e.cur = maxMatchOffset
+ }
+
+ s := e.addBlock(src)
+
+ // This check isn't in the Snappy implementation, but there, the caller
+ // instead of the callee handles this case.
+ if len(src) < minNonLiteralBlockSize {
+ // We do not fill the token table.
+ // This will be picked up by caller.
+ dst.n = uint16(len(src))
+ return
+ }
+
+ // Override src
+ src = e.hist
+ nextEmit := s
+
+ // sLimit is when to stop looking for offset/length copies. The inputMargin
+ // lets us use a fast path for emitLiteral in the main loop, while we are
+ // looking for copies.
+ sLimit := int32(len(src) - inputMargin)
+
+ // nextEmit is where in src the next emitLiteral should start from.
+ cv := load6432(src, s)
+ for {
+ // When should we start skipping if we haven't found matches in a long while.
+ const skipLog = 5
+ const doEvery = 2
+
+ nextS := s
+ var candidate tableEntry
+ for {
+ nextHash := hashLen(cv, bTableBits, hashBytes)
+ s = nextS
+ nextS = s + doEvery + (s-nextEmit)>>skipLog
+ if nextS > sLimit {
+ goto emitRemainder
+ }
+ candidate = e.table[nextHash]
+ now := load6432(src, nextS)
+ e.table[nextHash] = tableEntry{offset: s + e.cur}
+ nextHash = hashLen(now, bTableBits, hashBytes)
+
+ offset := s - (candidate.offset - e.cur)
+ if offset < maxMatchOffset && uint32(cv) == load3232(src, candidate.offset-e.cur) {
+ e.table[nextHash] = tableEntry{offset: nextS + e.cur}
+ break
+ }
+
+ // Do one right away...
+ cv = now
+ s = nextS
+ nextS++
+ candidate = e.table[nextHash]
+ now >>= 8
+ e.table[nextHash] = tableEntry{offset: s + e.cur}
+
+ offset = s - (candidate.offset - e.cur)
+ if offset < maxMatchOffset && uint32(cv) == load3232(src, candidate.offset-e.cur) {
+ break
+ }
+ cv = now
+ }
+
+ // A 4-byte match has been found. We'll later see if more than 4 bytes
+ // match. But, prior to the match, src[nextEmit:s] are unmatched. Emit
+ // them as literal bytes.
+
+ // Call emitCopy, and then see if another emitCopy could be our next
+ // move. Repeat until we find no match for the input immediately after
+ // what was consumed by the last emitCopy call.
+ //
+ // If we exit this loop normally then we need to call emitLiteral next,
+ // though we don't yet know how big the literal will be. We handle that
+ // by proceeding to the next iteration of the main loop. We also can
+ // exit this loop via goto if we get close to exhausting the input.
+ for {
+ // Invariant: we have a 4-byte match at s, and no need to emit any
+ // literal bytes prior to s.
+
+ // Extend the 4-byte match as long as possible.
+ t := candidate.offset - e.cur
+ l := e.matchlenLong(s+4, t+4, src) + 4
+
+ // Extend backwards
+ for t > 0 && s > nextEmit && src[t-1] == src[s-1] {
+ s--
+ t--
+ l++
+ }
+ if nextEmit < s {
+ if false {
+ emitLiteral(dst, src[nextEmit:s])
+ } else {
+ for _, v := range src[nextEmit:s] {
+ dst.tokens[dst.n] = token(v)
+ dst.litHist[v]++
+ dst.n++
+ }
+ }
+ }
+
+ dst.AddMatchLong(l, uint32(s-t-baseMatchOffset))
+ s += l
+ nextEmit = s
+ if nextS >= s {
+ s = nextS + 1
+ }
+
+ if s >= sLimit {
+ // Index first pair after match end.
+ if int(s+l+8) < len(src) {
+ cv := load6432(src, s)
+ e.table[hashLen(cv, bTableBits, hashBytes)] = tableEntry{offset: s + e.cur}
+ }
+ goto emitRemainder
+ }
+
+ // Store every second hash in-between, but offset by 1.
+ for i := s - l + 2; i < s-5; i += 7 {
+ x := load6432(src, i)
+ nextHash := hashLen(x, bTableBits, hashBytes)
+ e.table[nextHash] = tableEntry{offset: e.cur + i}
+ // Skip one
+ x >>= 16
+ nextHash = hashLen(x, bTableBits, hashBytes)
+ e.table[nextHash] = tableEntry{offset: e.cur + i + 2}
+ // Skip one
+ x >>= 16
+ nextHash = hashLen(x, bTableBits, hashBytes)
+ e.table[nextHash] = tableEntry{offset: e.cur + i + 4}
+ }
+
+ // We could immediately start working at s now, but to improve
+ // compression we first update the hash table at s-2 to s. If
+ // another emitCopy is not our next move, also calculate nextHash
+ // at s+1. At least on GOARCH=amd64, these three hash calculations
+ // are faster as one load64 call (with some shifts) instead of
+ // three load32 calls.
+ x := load6432(src, s-2)
+ o := e.cur + s - 2
+ prevHash := hashLen(x, bTableBits, hashBytes)
+ prevHash2 := hashLen(x>>8, bTableBits, hashBytes)
+ e.table[prevHash] = tableEntry{offset: o}
+ e.table[prevHash2] = tableEntry{offset: o + 1}
+ currHash := hashLen(x>>16, bTableBits, hashBytes)
+ candidate = e.table[currHash]
+ e.table[currHash] = tableEntry{offset: o + 2}
+
+ offset := s - (candidate.offset - e.cur)
+ if offset > maxMatchOffset || uint32(x>>16) != load3232(src, candidate.offset-e.cur) {
+ cv = x >> 24
+ s++
+ break
+ }
+ }
+ }
+
+emitRemainder:
+ if int(nextEmit) < len(src) {
+ // If nothing was added, don't encode literals.
+ if dst.n == 0 {
+ return
+ }
+
+ emitLiteral(dst, src[nextEmit:])
+ }
+}
diff --git a/vendor/github.com/klauspost/compress/flate/level3.go b/vendor/github.com/klauspost/compress/flate/level3.go
new file mode 100644
index 0000000..7aa2b72
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/flate/level3.go
@@ -0,0 +1,241 @@
+package flate
+
+import "fmt"
+
+// fastEncL3
+type fastEncL3 struct {
+ fastGen
+ table [1 << 16]tableEntryPrev
+}
+
+// Encode uses a similar algorithm to level 2, will check up to two candidates.
+func (e *fastEncL3) Encode(dst *tokens, src []byte) {
+ const (
+ inputMargin = 12 - 1
+ minNonLiteralBlockSize = 1 + 1 + inputMargin
+ tableBits = 16
+ tableSize = 1 << tableBits
+ hashBytes = 5
+ )
+
+ if debugDeflate && e.cur < 0 {
+ panic(fmt.Sprint("e.cur < 0: ", e.cur))
+ }
+
+ // Protect against e.cur wraparound.
+ for e.cur >= bufferReset {
+ if len(e.hist) == 0 {
+ for i := range e.table[:] {
+ e.table[i] = tableEntryPrev{}
+ }
+ e.cur = maxMatchOffset
+ break
+ }
+ // Shift down everything in the table that isn't already too far away.
+ minOff := e.cur + int32(len(e.hist)) - maxMatchOffset
+ for i := range e.table[:] {
+ v := e.table[i]
+ if v.Cur.offset <= minOff {
+ v.Cur.offset = 0
+ } else {
+ v.Cur.offset = v.Cur.offset - e.cur + maxMatchOffset
+ }
+ if v.Prev.offset <= minOff {
+ v.Prev.offset = 0
+ } else {
+ v.Prev.offset = v.Prev.offset - e.cur + maxMatchOffset
+ }
+ e.table[i] = v
+ }
+ e.cur = maxMatchOffset
+ }
+
+ s := e.addBlock(src)
+
+ // Skip if too small.
+ if len(src) < minNonLiteralBlockSize {
+ // We do not fill the token table.
+ // This will be picked up by caller.
+ dst.n = uint16(len(src))
+ return
+ }
+
+ // Override src
+ src = e.hist
+ nextEmit := s
+
+ // sLimit is when to stop looking for offset/length copies. The inputMargin
+ // lets us use a fast path for emitLiteral in the main loop, while we are
+ // looking for copies.
+ sLimit := int32(len(src) - inputMargin)
+
+ // nextEmit is where in src the next emitLiteral should start from.
+ cv := load6432(src, s)
+ for {
+ const skipLog = 7
+ nextS := s
+ var candidate tableEntry
+ for {
+ nextHash := hashLen(cv, tableBits, hashBytes)
+ s = nextS
+ nextS = s + 1 + (s-nextEmit)>>skipLog
+ if nextS > sLimit {
+ goto emitRemainder
+ }
+ candidates := e.table[nextHash]
+ now := load6432(src, nextS)
+
+ // Safe offset distance until s + 4...
+ minOffset := e.cur + s - (maxMatchOffset - 4)
+ e.table[nextHash] = tableEntryPrev{Prev: candidates.Cur, Cur: tableEntry{offset: s + e.cur}}
+
+ // Check both candidates
+ candidate = candidates.Cur
+ if candidate.offset < minOffset {
+ cv = now
+ // Previous will also be invalid, we have nothing.
+ continue
+ }
+
+ if uint32(cv) == load3232(src, candidate.offset-e.cur) {
+ if candidates.Prev.offset < minOffset || uint32(cv) != load3232(src, candidates.Prev.offset-e.cur) {
+ break
+ }
+ // Both match and are valid, pick longest.
+ offset := s - (candidate.offset - e.cur)
+ o2 := s - (candidates.Prev.offset - e.cur)
+ l1, l2 := matchLen(src[s+4:], src[s-offset+4:]), matchLen(src[s+4:], src[s-o2+4:])
+ if l2 > l1 {
+ candidate = candidates.Prev
+ }
+ break
+ } else {
+ // We only check if value mismatches.
+ // Offset will always be invalid in other cases.
+ candidate = candidates.Prev
+ if candidate.offset > minOffset && uint32(cv) == load3232(src, candidate.offset-e.cur) {
+ break
+ }
+ }
+ cv = now
+ }
+
+ // Call emitCopy, and then see if another emitCopy could be our next
+ // move. Repeat until we find no match for the input immediately after
+ // what was consumed by the last emitCopy call.
+ //
+ // If we exit this loop normally then we need to call emitLiteral next,
+ // though we don't yet know how big the literal will be. We handle that
+ // by proceeding to the next iteration of the main loop. We also can
+ // exit this loop via goto if we get close to exhausting the input.
+ for {
+ // Invariant: we have a 4-byte match at s, and no need to emit any
+ // literal bytes prior to s.
+
+ // Extend the 4-byte match as long as possible.
+ //
+ t := candidate.offset - e.cur
+ l := e.matchlenLong(s+4, t+4, src) + 4
+
+ // Extend backwards
+ for t > 0 && s > nextEmit && src[t-1] == src[s-1] {
+ s--
+ t--
+ l++
+ }
+ if nextEmit < s {
+ if false {
+ emitLiteral(dst, src[nextEmit:s])
+ } else {
+ for _, v := range src[nextEmit:s] {
+ dst.tokens[dst.n] = token(v)
+ dst.litHist[v]++
+ dst.n++
+ }
+ }
+ }
+
+ dst.AddMatchLong(l, uint32(s-t-baseMatchOffset))
+ s += l
+ nextEmit = s
+ if nextS >= s {
+ s = nextS + 1
+ }
+
+ if s >= sLimit {
+ t += l
+ // Index first pair after match end.
+ if int(t+8) < len(src) && t > 0 {
+ cv = load6432(src, t)
+ nextHash := hashLen(cv, tableBits, hashBytes)
+ e.table[nextHash] = tableEntryPrev{
+ Prev: e.table[nextHash].Cur,
+ Cur: tableEntry{offset: e.cur + t},
+ }
+ }
+ goto emitRemainder
+ }
+
+ // Store every 5th hash in-between.
+ for i := s - l + 2; i < s-5; i += 6 {
+ nextHash := hashLen(load6432(src, i), tableBits, hashBytes)
+ e.table[nextHash] = tableEntryPrev{
+ Prev: e.table[nextHash].Cur,
+ Cur: tableEntry{offset: e.cur + i}}
+ }
+ // We could immediately start working at s now, but to improve
+ // compression we first update the hash table at s-2 to s.
+ x := load6432(src, s-2)
+ prevHash := hashLen(x, tableBits, hashBytes)
+
+ e.table[prevHash] = tableEntryPrev{
+ Prev: e.table[prevHash].Cur,
+ Cur: tableEntry{offset: e.cur + s - 2},
+ }
+ x >>= 8
+ prevHash = hashLen(x, tableBits, hashBytes)
+
+ e.table[prevHash] = tableEntryPrev{
+ Prev: e.table[prevHash].Cur,
+ Cur: tableEntry{offset: e.cur + s - 1},
+ }
+ x >>= 8
+ currHash := hashLen(x, tableBits, hashBytes)
+ candidates := e.table[currHash]
+ cv = x
+ e.table[currHash] = tableEntryPrev{
+ Prev: candidates.Cur,
+ Cur: tableEntry{offset: s + e.cur},
+ }
+
+ // Check both candidates
+ candidate = candidates.Cur
+ minOffset := e.cur + s - (maxMatchOffset - 4)
+
+ if candidate.offset > minOffset {
+ if uint32(cv) == load3232(src, candidate.offset-e.cur) {
+ // Found a match...
+ continue
+ }
+ candidate = candidates.Prev
+ if candidate.offset > minOffset && uint32(cv) == load3232(src, candidate.offset-e.cur) {
+ // Match at prev...
+ continue
+ }
+ }
+ cv = x >> 8
+ s++
+ break
+ }
+ }
+
+emitRemainder:
+ if int(nextEmit) < len(src) {
+ // If nothing was added, don't encode literals.
+ if dst.n == 0 {
+ return
+ }
+
+ emitLiteral(dst, src[nextEmit:])
+ }
+}
diff --git a/vendor/github.com/klauspost/compress/flate/level4.go b/vendor/github.com/klauspost/compress/flate/level4.go
new file mode 100644
index 0000000..23c08b3
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/flate/level4.go
@@ -0,0 +1,221 @@
+package flate
+
+import "fmt"
+
+type fastEncL4 struct {
+ fastGen
+ table [tableSize]tableEntry
+ bTable [tableSize]tableEntry
+}
+
+func (e *fastEncL4) Encode(dst *tokens, src []byte) {
+ const (
+ inputMargin = 12 - 1
+ minNonLiteralBlockSize = 1 + 1 + inputMargin
+ hashShortBytes = 4
+ )
+ if debugDeflate && e.cur < 0 {
+ panic(fmt.Sprint("e.cur < 0: ", e.cur))
+ }
+ // Protect against e.cur wraparound.
+ for e.cur >= bufferReset {
+ if len(e.hist) == 0 {
+ for i := range e.table[:] {
+ e.table[i] = tableEntry{}
+ }
+ for i := range e.bTable[:] {
+ e.bTable[i] = tableEntry{}
+ }
+ e.cur = maxMatchOffset
+ break
+ }
+ // Shift down everything in the table that isn't already too far away.
+ minOff := e.cur + int32(len(e.hist)) - maxMatchOffset
+ for i := range e.table[:] {
+ v := e.table[i].offset
+ if v <= minOff {
+ v = 0
+ } else {
+ v = v - e.cur + maxMatchOffset
+ }
+ e.table[i].offset = v
+ }
+ for i := range e.bTable[:] {
+ v := e.bTable[i].offset
+ if v <= minOff {
+ v = 0
+ } else {
+ v = v - e.cur + maxMatchOffset
+ }
+ e.bTable[i].offset = v
+ }
+ e.cur = maxMatchOffset
+ }
+
+ s := e.addBlock(src)
+
+ // This check isn't in the Snappy implementation, but there, the caller
+ // instead of the callee handles this case.
+ if len(src) < minNonLiteralBlockSize {
+ // We do not fill the token table.
+ // This will be picked up by caller.
+ dst.n = uint16(len(src))
+ return
+ }
+
+ // Override src
+ src = e.hist
+ nextEmit := s
+
+ // sLimit is when to stop looking for offset/length copies. The inputMargin
+ // lets us use a fast path for emitLiteral in the main loop, while we are
+ // looking for copies.
+ sLimit := int32(len(src) - inputMargin)
+
+ // nextEmit is where in src the next emitLiteral should start from.
+ cv := load6432(src, s)
+ for {
+ const skipLog = 6
+ const doEvery = 1
+
+ nextS := s
+ var t int32
+ for {
+ nextHashS := hashLen(cv, tableBits, hashShortBytes)
+ nextHashL := hash7(cv, tableBits)
+
+ s = nextS
+ nextS = s + doEvery + (s-nextEmit)>>skipLog
+ if nextS > sLimit {
+ goto emitRemainder
+ }
+ // Fetch a short+long candidate
+ sCandidate := e.table[nextHashS]
+ lCandidate := e.bTable[nextHashL]
+ next := load6432(src, nextS)
+ entry := tableEntry{offset: s + e.cur}
+ e.table[nextHashS] = entry
+ e.bTable[nextHashL] = entry
+
+ t = lCandidate.offset - e.cur
+ if s-t < maxMatchOffset && uint32(cv) == load3232(src, lCandidate.offset-e.cur) {
+ // We got a long match. Use that.
+ break
+ }
+
+ t = sCandidate.offset - e.cur
+ if s-t < maxMatchOffset && uint32(cv) == load3232(src, sCandidate.offset-e.cur) {
+ // Found a 4 match...
+ lCandidate = e.bTable[hash7(next, tableBits)]
+
+ // If the next long is a candidate, check if we should use that instead...
+ lOff := nextS - (lCandidate.offset - e.cur)
+ if lOff < maxMatchOffset && load3232(src, lCandidate.offset-e.cur) == uint32(next) {
+ l1, l2 := matchLen(src[s+4:], src[t+4:]), matchLen(src[nextS+4:], src[nextS-lOff+4:])
+ if l2 > l1 {
+ s = nextS
+ t = lCandidate.offset - e.cur
+ }
+ }
+ break
+ }
+ cv = next
+ }
+
+ // A 4-byte match has been found. We'll later see if more than 4 bytes
+ // match. But, prior to the match, src[nextEmit:s] are unmatched. Emit
+ // them as literal bytes.
+
+ // Extend the 4-byte match as long as possible.
+ l := e.matchlenLong(s+4, t+4, src) + 4
+
+ // Extend backwards
+ for t > 0 && s > nextEmit && src[t-1] == src[s-1] {
+ s--
+ t--
+ l++
+ }
+ if nextEmit < s {
+ if false {
+ emitLiteral(dst, src[nextEmit:s])
+ } else {
+ for _, v := range src[nextEmit:s] {
+ dst.tokens[dst.n] = token(v)
+ dst.litHist[v]++
+ dst.n++
+ }
+ }
+ }
+ if debugDeflate {
+ if t >= s {
+ panic("s-t")
+ }
+ if (s - t) > maxMatchOffset {
+ panic(fmt.Sprintln("mmo", t))
+ }
+ if l < baseMatchLength {
+ panic("bml")
+ }
+ }
+
+ dst.AddMatchLong(l, uint32(s-t-baseMatchOffset))
+ s += l
+ nextEmit = s
+ if nextS >= s {
+ s = nextS + 1
+ }
+
+ if s >= sLimit {
+ // Index first pair after match end.
+ if int(s+8) < len(src) {
+ cv := load6432(src, s)
+ e.table[hashLen(cv, tableBits, hashShortBytes)] = tableEntry{offset: s + e.cur}
+ e.bTable[hash7(cv, tableBits)] = tableEntry{offset: s + e.cur}
+ }
+ goto emitRemainder
+ }
+
+ // Store every 3rd hash in-between
+ if true {
+ i := nextS
+ if i < s-1 {
+ cv := load6432(src, i)
+ t := tableEntry{offset: i + e.cur}
+ t2 := tableEntry{offset: t.offset + 1}
+ e.bTable[hash7(cv, tableBits)] = t
+ e.bTable[hash7(cv>>8, tableBits)] = t2
+ e.table[hashLen(cv>>8, tableBits, hashShortBytes)] = t2
+
+ i += 3
+ for ; i < s-1; i += 3 {
+ cv := load6432(src, i)
+ t := tableEntry{offset: i + e.cur}
+ t2 := tableEntry{offset: t.offset + 1}
+ e.bTable[hash7(cv, tableBits)] = t
+ e.bTable[hash7(cv>>8, tableBits)] = t2
+ e.table[hashLen(cv>>8, tableBits, hashShortBytes)] = t2
+ }
+ }
+ }
+
+ // We could immediately start working at s now, but to improve
+ // compression we first update the hash table at s-1 and at s.
+ x := load6432(src, s-1)
+ o := e.cur + s - 1
+ prevHashS := hashLen(x, tableBits, hashShortBytes)
+ prevHashL := hash7(x, tableBits)
+ e.table[prevHashS] = tableEntry{offset: o}
+ e.bTable[prevHashL] = tableEntry{offset: o}
+ cv = x >> 8
+ }
+
+emitRemainder:
+ if int(nextEmit) < len(src) {
+ // If nothing was added, don't encode literals.
+ if dst.n == 0 {
+ return
+ }
+
+ emitLiteral(dst, src[nextEmit:])
+ }
+}
diff --git a/vendor/github.com/klauspost/compress/flate/level5.go b/vendor/github.com/klauspost/compress/flate/level5.go
new file mode 100644
index 0000000..1f61ec1
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/flate/level5.go
@@ -0,0 +1,708 @@
+package flate
+
+import "fmt"
+
+type fastEncL5 struct {
+ fastGen
+ table [tableSize]tableEntry
+ bTable [tableSize]tableEntryPrev
+}
+
+func (e *fastEncL5) Encode(dst *tokens, src []byte) {
+ const (
+ inputMargin = 12 - 1
+ minNonLiteralBlockSize = 1 + 1 + inputMargin
+ hashShortBytes = 4
+ )
+ if debugDeflate && e.cur < 0 {
+ panic(fmt.Sprint("e.cur < 0: ", e.cur))
+ }
+
+ // Protect against e.cur wraparound.
+ for e.cur >= bufferReset {
+ if len(e.hist) == 0 {
+ for i := range e.table[:] {
+ e.table[i] = tableEntry{}
+ }
+ for i := range e.bTable[:] {
+ e.bTable[i] = tableEntryPrev{}
+ }
+ e.cur = maxMatchOffset
+ break
+ }
+ // Shift down everything in the table that isn't already too far away.
+ minOff := e.cur + int32(len(e.hist)) - maxMatchOffset
+ for i := range e.table[:] {
+ v := e.table[i].offset
+ if v <= minOff {
+ v = 0
+ } else {
+ v = v - e.cur + maxMatchOffset
+ }
+ e.table[i].offset = v
+ }
+ for i := range e.bTable[:] {
+ v := e.bTable[i]
+ if v.Cur.offset <= minOff {
+ v.Cur.offset = 0
+ v.Prev.offset = 0
+ } else {
+ v.Cur.offset = v.Cur.offset - e.cur + maxMatchOffset
+ if v.Prev.offset <= minOff {
+ v.Prev.offset = 0
+ } else {
+ v.Prev.offset = v.Prev.offset - e.cur + maxMatchOffset
+ }
+ }
+ e.bTable[i] = v
+ }
+ e.cur = maxMatchOffset
+ }
+
+ s := e.addBlock(src)
+
+ // This check isn't in the Snappy implementation, but there, the caller
+ // instead of the callee handles this case.
+ if len(src) < minNonLiteralBlockSize {
+ // We do not fill the token table.
+ // This will be picked up by caller.
+ dst.n = uint16(len(src))
+ return
+ }
+
+ // Override src
+ src = e.hist
+ nextEmit := s
+
+ // sLimit is when to stop looking for offset/length copies. The inputMargin
+ // lets us use a fast path for emitLiteral in the main loop, while we are
+ // looking for copies.
+ sLimit := int32(len(src) - inputMargin)
+
+ // nextEmit is where in src the next emitLiteral should start from.
+ cv := load6432(src, s)
+ for {
+ const skipLog = 6
+ const doEvery = 1
+
+ nextS := s
+ var l int32
+ var t int32
+ for {
+ nextHashS := hashLen(cv, tableBits, hashShortBytes)
+ nextHashL := hash7(cv, tableBits)
+
+ s = nextS
+ nextS = s + doEvery + (s-nextEmit)>>skipLog
+ if nextS > sLimit {
+ goto emitRemainder
+ }
+ // Fetch a short+long candidate
+ sCandidate := e.table[nextHashS]
+ lCandidate := e.bTable[nextHashL]
+ next := load6432(src, nextS)
+ entry := tableEntry{offset: s + e.cur}
+ e.table[nextHashS] = entry
+ eLong := &e.bTable[nextHashL]
+ eLong.Cur, eLong.Prev = entry, eLong.Cur
+
+ nextHashS = hashLen(next, tableBits, hashShortBytes)
+ nextHashL = hash7(next, tableBits)
+
+ t = lCandidate.Cur.offset - e.cur
+ if s-t < maxMatchOffset {
+ if uint32(cv) == load3232(src, lCandidate.Cur.offset-e.cur) {
+ // Store the next match
+ e.table[nextHashS] = tableEntry{offset: nextS + e.cur}
+ eLong := &e.bTable[nextHashL]
+ eLong.Cur, eLong.Prev = tableEntry{offset: nextS + e.cur}, eLong.Cur
+
+ t2 := lCandidate.Prev.offset - e.cur
+ if s-t2 < maxMatchOffset && uint32(cv) == load3232(src, lCandidate.Prev.offset-e.cur) {
+ l = e.matchlen(s+4, t+4, src) + 4
+ ml1 := e.matchlen(s+4, t2+4, src) + 4
+ if ml1 > l {
+ t = t2
+ l = ml1
+ break
+ }
+ }
+ break
+ }
+ t = lCandidate.Prev.offset - e.cur
+ if s-t < maxMatchOffset && uint32(cv) == load3232(src, lCandidate.Prev.offset-e.cur) {
+ // Store the next match
+ e.table[nextHashS] = tableEntry{offset: nextS + e.cur}
+ eLong := &e.bTable[nextHashL]
+ eLong.Cur, eLong.Prev = tableEntry{offset: nextS + e.cur}, eLong.Cur
+ break
+ }
+ }
+
+ t = sCandidate.offset - e.cur
+ if s-t < maxMatchOffset && uint32(cv) == load3232(src, sCandidate.offset-e.cur) {
+ // Found a 4 match...
+ l = e.matchlen(s+4, t+4, src) + 4
+ lCandidate = e.bTable[nextHashL]
+ // Store the next match
+
+ e.table[nextHashS] = tableEntry{offset: nextS + e.cur}
+ eLong := &e.bTable[nextHashL]
+ eLong.Cur, eLong.Prev = tableEntry{offset: nextS + e.cur}, eLong.Cur
+
+ // If the next long is a candidate, use that...
+ t2 := lCandidate.Cur.offset - e.cur
+ if nextS-t2 < maxMatchOffset {
+ if load3232(src, lCandidate.Cur.offset-e.cur) == uint32(next) {
+ ml := e.matchlen(nextS+4, t2+4, src) + 4
+ if ml > l {
+ t = t2
+ s = nextS
+ l = ml
+ break
+ }
+ }
+ // If the previous long is a candidate, use that...
+ t2 = lCandidate.Prev.offset - e.cur
+ if nextS-t2 < maxMatchOffset && load3232(src, lCandidate.Prev.offset-e.cur) == uint32(next) {
+ ml := e.matchlen(nextS+4, t2+4, src) + 4
+ if ml > l {
+ t = t2
+ s = nextS
+ l = ml
+ break
+ }
+ }
+ }
+ break
+ }
+ cv = next
+ }
+
+ // A 4-byte match has been found. We'll later see if more than 4 bytes
+ // match. But, prior to the match, src[nextEmit:s] are unmatched. Emit
+ // them as literal bytes.
+
+ if l == 0 {
+ // Extend the 4-byte match as long as possible.
+ l = e.matchlenLong(s+4, t+4, src) + 4
+ } else if l == maxMatchLength {
+ l += e.matchlenLong(s+l, t+l, src)
+ }
+
+ // Try to locate a better match by checking the end of best match...
+ if sAt := s + l; l < 30 && sAt < sLimit {
+ // Allow some bytes at the beginning to mismatch.
+ // Sweet spot is 2/3 bytes depending on input.
+ // 3 is only a little better when it is but sometimes a lot worse.
+ // The skipped bytes are tested in Extend backwards,
+ // and still picked up as part of the match if they do.
+ const skipBeginning = 2
+ eLong := e.bTable[hash7(load6432(src, sAt), tableBits)].Cur.offset
+ t2 := eLong - e.cur - l + skipBeginning
+ s2 := s + skipBeginning
+ off := s2 - t2
+ if t2 >= 0 && off < maxMatchOffset && off > 0 {
+ if l2 := e.matchlenLong(s2, t2, src); l2 > l {
+ t = t2
+ l = l2
+ s = s2
+ }
+ }
+ }
+
+ // Extend backwards
+ for t > 0 && s > nextEmit && src[t-1] == src[s-1] {
+ s--
+ t--
+ l++
+ }
+ if nextEmit < s {
+ if false {
+ emitLiteral(dst, src[nextEmit:s])
+ } else {
+ for _, v := range src[nextEmit:s] {
+ dst.tokens[dst.n] = token(v)
+ dst.litHist[v]++
+ dst.n++
+ }
+ }
+ }
+ if debugDeflate {
+ if t >= s {
+ panic(fmt.Sprintln("s-t", s, t))
+ }
+ if (s - t) > maxMatchOffset {
+ panic(fmt.Sprintln("mmo", s-t))
+ }
+ if l < baseMatchLength {
+ panic("bml")
+ }
+ }
+
+ dst.AddMatchLong(l, uint32(s-t-baseMatchOffset))
+ s += l
+ nextEmit = s
+ if nextS >= s {
+ s = nextS + 1
+ }
+
+ if s >= sLimit {
+ goto emitRemainder
+ }
+
+ // Store every 3rd hash in-between.
+ if true {
+ const hashEvery = 3
+ i := s - l + 1
+ if i < s-1 {
+ cv := load6432(src, i)
+ t := tableEntry{offset: i + e.cur}
+ e.table[hashLen(cv, tableBits, hashShortBytes)] = t
+ eLong := &e.bTable[hash7(cv, tableBits)]
+ eLong.Cur, eLong.Prev = t, eLong.Cur
+
+ // Do an long at i+1
+ cv >>= 8
+ t = tableEntry{offset: t.offset + 1}
+ eLong = &e.bTable[hash7(cv, tableBits)]
+ eLong.Cur, eLong.Prev = t, eLong.Cur
+
+ // We only have enough bits for a short entry at i+2
+ cv >>= 8
+ t = tableEntry{offset: t.offset + 1}
+ e.table[hashLen(cv, tableBits, hashShortBytes)] = t
+
+ // Skip one - otherwise we risk hitting 's'
+ i += 4
+ for ; i < s-1; i += hashEvery {
+ cv := load6432(src, i)
+ t := tableEntry{offset: i + e.cur}
+ t2 := tableEntry{offset: t.offset + 1}
+ eLong := &e.bTable[hash7(cv, tableBits)]
+ eLong.Cur, eLong.Prev = t, eLong.Cur
+ e.table[hashLen(cv>>8, tableBits, hashShortBytes)] = t2
+ }
+ }
+ }
+
+ // We could immediately start working at s now, but to improve
+ // compression we first update the hash table at s-1 and at s.
+ x := load6432(src, s-1)
+ o := e.cur + s - 1
+ prevHashS := hashLen(x, tableBits, hashShortBytes)
+ prevHashL := hash7(x, tableBits)
+ e.table[prevHashS] = tableEntry{offset: o}
+ eLong := &e.bTable[prevHashL]
+ eLong.Cur, eLong.Prev = tableEntry{offset: o}, eLong.Cur
+ cv = x >> 8
+ }
+
+emitRemainder:
+ if int(nextEmit) < len(src) {
+ // If nothing was added, don't encode literals.
+ if dst.n == 0 {
+ return
+ }
+
+ emitLiteral(dst, src[nextEmit:])
+ }
+}
+
+// fastEncL5Window is a level 5 encoder,
+// but with a custom window size.
+type fastEncL5Window struct {
+ hist []byte
+ cur int32
+ maxOffset int32
+ table [tableSize]tableEntry
+ bTable [tableSize]tableEntryPrev
+}
+
+func (e *fastEncL5Window) Encode(dst *tokens, src []byte) {
+ const (
+ inputMargin = 12 - 1
+ minNonLiteralBlockSize = 1 + 1 + inputMargin
+ hashShortBytes = 4
+ )
+ maxMatchOffset := e.maxOffset
+ if debugDeflate && e.cur < 0 {
+ panic(fmt.Sprint("e.cur < 0: ", e.cur))
+ }
+
+ // Protect against e.cur wraparound.
+ for e.cur >= bufferReset {
+ if len(e.hist) == 0 {
+ for i := range e.table[:] {
+ e.table[i] = tableEntry{}
+ }
+ for i := range e.bTable[:] {
+ e.bTable[i] = tableEntryPrev{}
+ }
+ e.cur = maxMatchOffset
+ break
+ }
+ // Shift down everything in the table that isn't already too far away.
+ minOff := e.cur + int32(len(e.hist)) - maxMatchOffset
+ for i := range e.table[:] {
+ v := e.table[i].offset
+ if v <= minOff {
+ v = 0
+ } else {
+ v = v - e.cur + maxMatchOffset
+ }
+ e.table[i].offset = v
+ }
+ for i := range e.bTable[:] {
+ v := e.bTable[i]
+ if v.Cur.offset <= minOff {
+ v.Cur.offset = 0
+ v.Prev.offset = 0
+ } else {
+ v.Cur.offset = v.Cur.offset - e.cur + maxMatchOffset
+ if v.Prev.offset <= minOff {
+ v.Prev.offset = 0
+ } else {
+ v.Prev.offset = v.Prev.offset - e.cur + maxMatchOffset
+ }
+ }
+ e.bTable[i] = v
+ }
+ e.cur = maxMatchOffset
+ }
+
+ s := e.addBlock(src)
+
+ // This check isn't in the Snappy implementation, but there, the caller
+ // instead of the callee handles this case.
+ if len(src) < minNonLiteralBlockSize {
+ // We do not fill the token table.
+ // This will be picked up by caller.
+ dst.n = uint16(len(src))
+ return
+ }
+
+ // Override src
+ src = e.hist
+ nextEmit := s
+
+ // sLimit is when to stop looking for offset/length copies. The inputMargin
+ // lets us use a fast path for emitLiteral in the main loop, while we are
+ // looking for copies.
+ sLimit := int32(len(src) - inputMargin)
+
+ // nextEmit is where in src the next emitLiteral should start from.
+ cv := load6432(src, s)
+ for {
+ const skipLog = 6
+ const doEvery = 1
+
+ nextS := s
+ var l int32
+ var t int32
+ for {
+ nextHashS := hashLen(cv, tableBits, hashShortBytes)
+ nextHashL := hash7(cv, tableBits)
+
+ s = nextS
+ nextS = s + doEvery + (s-nextEmit)>>skipLog
+ if nextS > sLimit {
+ goto emitRemainder
+ }
+ // Fetch a short+long candidate
+ sCandidate := e.table[nextHashS]
+ lCandidate := e.bTable[nextHashL]
+ next := load6432(src, nextS)
+ entry := tableEntry{offset: s + e.cur}
+ e.table[nextHashS] = entry
+ eLong := &e.bTable[nextHashL]
+ eLong.Cur, eLong.Prev = entry, eLong.Cur
+
+ nextHashS = hashLen(next, tableBits, hashShortBytes)
+ nextHashL = hash7(next, tableBits)
+
+ t = lCandidate.Cur.offset - e.cur
+ if s-t < maxMatchOffset {
+ if uint32(cv) == load3232(src, lCandidate.Cur.offset-e.cur) {
+ // Store the next match
+ e.table[nextHashS] = tableEntry{offset: nextS + e.cur}
+ eLong := &e.bTable[nextHashL]
+ eLong.Cur, eLong.Prev = tableEntry{offset: nextS + e.cur}, eLong.Cur
+
+ t2 := lCandidate.Prev.offset - e.cur
+ if s-t2 < maxMatchOffset && uint32(cv) == load3232(src, lCandidate.Prev.offset-e.cur) {
+ l = e.matchlen(s+4, t+4, src) + 4
+ ml1 := e.matchlen(s+4, t2+4, src) + 4
+ if ml1 > l {
+ t = t2
+ l = ml1
+ break
+ }
+ }
+ break
+ }
+ t = lCandidate.Prev.offset - e.cur
+ if s-t < maxMatchOffset && uint32(cv) == load3232(src, lCandidate.Prev.offset-e.cur) {
+ // Store the next match
+ e.table[nextHashS] = tableEntry{offset: nextS + e.cur}
+ eLong := &e.bTable[nextHashL]
+ eLong.Cur, eLong.Prev = tableEntry{offset: nextS + e.cur}, eLong.Cur
+ break
+ }
+ }
+
+ t = sCandidate.offset - e.cur
+ if s-t < maxMatchOffset && uint32(cv) == load3232(src, sCandidate.offset-e.cur) {
+ // Found a 4 match...
+ l = e.matchlen(s+4, t+4, src) + 4
+ lCandidate = e.bTable[nextHashL]
+ // Store the next match
+
+ e.table[nextHashS] = tableEntry{offset: nextS + e.cur}
+ eLong := &e.bTable[nextHashL]
+ eLong.Cur, eLong.Prev = tableEntry{offset: nextS + e.cur}, eLong.Cur
+
+ // If the next long is a candidate, use that...
+ t2 := lCandidate.Cur.offset - e.cur
+ if nextS-t2 < maxMatchOffset {
+ if load3232(src, lCandidate.Cur.offset-e.cur) == uint32(next) {
+ ml := e.matchlen(nextS+4, t2+4, src) + 4
+ if ml > l {
+ t = t2
+ s = nextS
+ l = ml
+ break
+ }
+ }
+ // If the previous long is a candidate, use that...
+ t2 = lCandidate.Prev.offset - e.cur
+ if nextS-t2 < maxMatchOffset && load3232(src, lCandidate.Prev.offset-e.cur) == uint32(next) {
+ ml := e.matchlen(nextS+4, t2+4, src) + 4
+ if ml > l {
+ t = t2
+ s = nextS
+ l = ml
+ break
+ }
+ }
+ }
+ break
+ }
+ cv = next
+ }
+
+ // A 4-byte match has been found. We'll later see if more than 4 bytes
+ // match. But, prior to the match, src[nextEmit:s] are unmatched. Emit
+ // them as literal bytes.
+
+ if l == 0 {
+ // Extend the 4-byte match as long as possible.
+ l = e.matchlenLong(s+4, t+4, src) + 4
+ } else if l == maxMatchLength {
+ l += e.matchlenLong(s+l, t+l, src)
+ }
+
+ // Try to locate a better match by checking the end of best match...
+ if sAt := s + l; l < 30 && sAt < sLimit {
+ // Allow some bytes at the beginning to mismatch.
+ // Sweet spot is 2/3 bytes depending on input.
+ // 3 is only a little better when it is but sometimes a lot worse.
+ // The skipped bytes are tested in Extend backwards,
+ // and still picked up as part of the match if they do.
+ const skipBeginning = 2
+ eLong := e.bTable[hash7(load6432(src, sAt), tableBits)].Cur.offset
+ t2 := eLong - e.cur - l + skipBeginning
+ s2 := s + skipBeginning
+ off := s2 - t2
+ if t2 >= 0 && off < maxMatchOffset && off > 0 {
+ if l2 := e.matchlenLong(s2, t2, src); l2 > l {
+ t = t2
+ l = l2
+ s = s2
+ }
+ }
+ }
+
+ // Extend backwards
+ for t > 0 && s > nextEmit && src[t-1] == src[s-1] {
+ s--
+ t--
+ l++
+ }
+ if nextEmit < s {
+ if false {
+ emitLiteral(dst, src[nextEmit:s])
+ } else {
+ for _, v := range src[nextEmit:s] {
+ dst.tokens[dst.n] = token(v)
+ dst.litHist[v]++
+ dst.n++
+ }
+ }
+ }
+ if debugDeflate {
+ if t >= s {
+ panic(fmt.Sprintln("s-t", s, t))
+ }
+ if (s - t) > maxMatchOffset {
+ panic(fmt.Sprintln("mmo", s-t))
+ }
+ if l < baseMatchLength {
+ panic("bml")
+ }
+ }
+
+ dst.AddMatchLong(l, uint32(s-t-baseMatchOffset))
+ s += l
+ nextEmit = s
+ if nextS >= s {
+ s = nextS + 1
+ }
+
+ if s >= sLimit {
+ goto emitRemainder
+ }
+
+ // Store every 3rd hash in-between.
+ if true {
+ const hashEvery = 3
+ i := s - l + 1
+ if i < s-1 {
+ cv := load6432(src, i)
+ t := tableEntry{offset: i + e.cur}
+ e.table[hashLen(cv, tableBits, hashShortBytes)] = t
+ eLong := &e.bTable[hash7(cv, tableBits)]
+ eLong.Cur, eLong.Prev = t, eLong.Cur
+
+ // Do an long at i+1
+ cv >>= 8
+ t = tableEntry{offset: t.offset + 1}
+ eLong = &e.bTable[hash7(cv, tableBits)]
+ eLong.Cur, eLong.Prev = t, eLong.Cur
+
+ // We only have enough bits for a short entry at i+2
+ cv >>= 8
+ t = tableEntry{offset: t.offset + 1}
+ e.table[hashLen(cv, tableBits, hashShortBytes)] = t
+
+ // Skip one - otherwise we risk hitting 's'
+ i += 4
+ for ; i < s-1; i += hashEvery {
+ cv := load6432(src, i)
+ t := tableEntry{offset: i + e.cur}
+ t2 := tableEntry{offset: t.offset + 1}
+ eLong := &e.bTable[hash7(cv, tableBits)]
+ eLong.Cur, eLong.Prev = t, eLong.Cur
+ e.table[hashLen(cv>>8, tableBits, hashShortBytes)] = t2
+ }
+ }
+ }
+
+ // We could immediately start working at s now, but to improve
+ // compression we first update the hash table at s-1 and at s.
+ x := load6432(src, s-1)
+ o := e.cur + s - 1
+ prevHashS := hashLen(x, tableBits, hashShortBytes)
+ prevHashL := hash7(x, tableBits)
+ e.table[prevHashS] = tableEntry{offset: o}
+ eLong := &e.bTable[prevHashL]
+ eLong.Cur, eLong.Prev = tableEntry{offset: o}, eLong.Cur
+ cv = x >> 8
+ }
+
+emitRemainder:
+ if int(nextEmit) < len(src) {
+ // If nothing was added, don't encode literals.
+ if dst.n == 0 {
+ return
+ }
+
+ emitLiteral(dst, src[nextEmit:])
+ }
+}
+
+// Reset the encoding table.
+func (e *fastEncL5Window) Reset() {
+ // We keep the same allocs, since we are compressing the same block sizes.
+ if cap(e.hist) < allocHistory {
+ e.hist = make([]byte, 0, allocHistory)
+ }
+
+ // We offset current position so everything will be out of reach.
+ // If we are above the buffer reset it will be cleared anyway since len(hist) == 0.
+ if e.cur <= int32(bufferReset) {
+ e.cur += e.maxOffset + int32(len(e.hist))
+ }
+ e.hist = e.hist[:0]
+}
+
+func (e *fastEncL5Window) addBlock(src []byte) int32 {
+ // check if we have space already
+ maxMatchOffset := e.maxOffset
+
+ if len(e.hist)+len(src) > cap(e.hist) {
+ if cap(e.hist) == 0 {
+ e.hist = make([]byte, 0, allocHistory)
+ } else {
+ if cap(e.hist) < int(maxMatchOffset*2) {
+ panic("unexpected buffer size")
+ }
+ // Move down
+ offset := int32(len(e.hist)) - maxMatchOffset
+ copy(e.hist[0:maxMatchOffset], e.hist[offset:])
+ e.cur += offset
+ e.hist = e.hist[:maxMatchOffset]
+ }
+ }
+ s := int32(len(e.hist))
+ e.hist = append(e.hist, src...)
+ return s
+}
+
+// matchlen will return the match length between offsets and t in src.
+// The maximum length returned is maxMatchLength - 4.
+// It is assumed that s > t, that t >=0 and s < len(src).
+func (e *fastEncL5Window) matchlen(s, t int32, src []byte) int32 {
+ if debugDecode {
+ if t >= s {
+ panic(fmt.Sprint("t >=s:", t, s))
+ }
+ if int(s) >= len(src) {
+ panic(fmt.Sprint("s >= len(src):", s, len(src)))
+ }
+ if t < 0 {
+ panic(fmt.Sprint("t < 0:", t))
+ }
+ if s-t > e.maxOffset {
+ panic(fmt.Sprint(s, "-", t, "(", s-t, ") > maxMatchLength (", maxMatchOffset, ")"))
+ }
+ }
+ s1 := int(s) + maxMatchLength - 4
+ if s1 > len(src) {
+ s1 = len(src)
+ }
+
+ // Extend the match to be as long as possible.
+ return int32(matchLen(src[s:s1], src[t:]))
+}
+
+// matchlenLong will return the match length between offsets and t in src.
+// It is assumed that s > t, that t >=0 and s < len(src).
+func (e *fastEncL5Window) matchlenLong(s, t int32, src []byte) int32 {
+ if debugDeflate {
+ if t >= s {
+ panic(fmt.Sprint("t >=s:", t, s))
+ }
+ if int(s) >= len(src) {
+ panic(fmt.Sprint("s >= len(src):", s, len(src)))
+ }
+ if t < 0 {
+ panic(fmt.Sprint("t < 0:", t))
+ }
+ if s-t > e.maxOffset {
+ panic(fmt.Sprint(s, "-", t, "(", s-t, ") > maxMatchLength (", maxMatchOffset, ")"))
+ }
+ }
+ // Extend the match to be as long as possible.
+ return int32(matchLen(src[s:], src[t:]))
+}
diff --git a/vendor/github.com/klauspost/compress/flate/level6.go b/vendor/github.com/klauspost/compress/flate/level6.go
new file mode 100644
index 0000000..f1e9d98
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/flate/level6.go
@@ -0,0 +1,325 @@
+package flate
+
+import "fmt"
+
+type fastEncL6 struct {
+ fastGen
+ table [tableSize]tableEntry
+ bTable [tableSize]tableEntryPrev
+}
+
+func (e *fastEncL6) Encode(dst *tokens, src []byte) {
+ const (
+ inputMargin = 12 - 1
+ minNonLiteralBlockSize = 1 + 1 + inputMargin
+ hashShortBytes = 4
+ )
+ if debugDeflate && e.cur < 0 {
+ panic(fmt.Sprint("e.cur < 0: ", e.cur))
+ }
+
+ // Protect against e.cur wraparound.
+ for e.cur >= bufferReset {
+ if len(e.hist) == 0 {
+ for i := range e.table[:] {
+ e.table[i] = tableEntry{}
+ }
+ for i := range e.bTable[:] {
+ e.bTable[i] = tableEntryPrev{}
+ }
+ e.cur = maxMatchOffset
+ break
+ }
+ // Shift down everything in the table that isn't already too far away.
+ minOff := e.cur + int32(len(e.hist)) - maxMatchOffset
+ for i := range e.table[:] {
+ v := e.table[i].offset
+ if v <= minOff {
+ v = 0
+ } else {
+ v = v - e.cur + maxMatchOffset
+ }
+ e.table[i].offset = v
+ }
+ for i := range e.bTable[:] {
+ v := e.bTable[i]
+ if v.Cur.offset <= minOff {
+ v.Cur.offset = 0
+ v.Prev.offset = 0
+ } else {
+ v.Cur.offset = v.Cur.offset - e.cur + maxMatchOffset
+ if v.Prev.offset <= minOff {
+ v.Prev.offset = 0
+ } else {
+ v.Prev.offset = v.Prev.offset - e.cur + maxMatchOffset
+ }
+ }
+ e.bTable[i] = v
+ }
+ e.cur = maxMatchOffset
+ }
+
+ s := e.addBlock(src)
+
+ // This check isn't in the Snappy implementation, but there, the caller
+ // instead of the callee handles this case.
+ if len(src) < minNonLiteralBlockSize {
+ // We do not fill the token table.
+ // This will be picked up by caller.
+ dst.n = uint16(len(src))
+ return
+ }
+
+ // Override src
+ src = e.hist
+ nextEmit := s
+
+ // sLimit is when to stop looking for offset/length copies. The inputMargin
+ // lets us use a fast path for emitLiteral in the main loop, while we are
+ // looking for copies.
+ sLimit := int32(len(src) - inputMargin)
+
+ // nextEmit is where in src the next emitLiteral should start from.
+ cv := load6432(src, s)
+ // Repeat MUST be > 1 and within range
+ repeat := int32(1)
+ for {
+ const skipLog = 7
+ const doEvery = 1
+
+ nextS := s
+ var l int32
+ var t int32
+ for {
+ nextHashS := hashLen(cv, tableBits, hashShortBytes)
+ nextHashL := hash7(cv, tableBits)
+ s = nextS
+ nextS = s + doEvery + (s-nextEmit)>>skipLog
+ if nextS > sLimit {
+ goto emitRemainder
+ }
+ // Fetch a short+long candidate
+ sCandidate := e.table[nextHashS]
+ lCandidate := e.bTable[nextHashL]
+ next := load6432(src, nextS)
+ entry := tableEntry{offset: s + e.cur}
+ e.table[nextHashS] = entry
+ eLong := &e.bTable[nextHashL]
+ eLong.Cur, eLong.Prev = entry, eLong.Cur
+
+ // Calculate hashes of 'next'
+ nextHashS = hashLen(next, tableBits, hashShortBytes)
+ nextHashL = hash7(next, tableBits)
+
+ t = lCandidate.Cur.offset - e.cur
+ if s-t < maxMatchOffset {
+ if uint32(cv) == load3232(src, lCandidate.Cur.offset-e.cur) {
+ // Long candidate matches at least 4 bytes.
+
+ // Store the next match
+ e.table[nextHashS] = tableEntry{offset: nextS + e.cur}
+ eLong := &e.bTable[nextHashL]
+ eLong.Cur, eLong.Prev = tableEntry{offset: nextS + e.cur}, eLong.Cur
+
+ // Check the previous long candidate as well.
+ t2 := lCandidate.Prev.offset - e.cur
+ if s-t2 < maxMatchOffset && uint32(cv) == load3232(src, lCandidate.Prev.offset-e.cur) {
+ l = e.matchlen(s+4, t+4, src) + 4
+ ml1 := e.matchlen(s+4, t2+4, src) + 4
+ if ml1 > l {
+ t = t2
+ l = ml1
+ break
+ }
+ }
+ break
+ }
+ // Current value did not match, but check if previous long value does.
+ t = lCandidate.Prev.offset - e.cur
+ if s-t < maxMatchOffset && uint32(cv) == load3232(src, lCandidate.Prev.offset-e.cur) {
+ // Store the next match
+ e.table[nextHashS] = tableEntry{offset: nextS + e.cur}
+ eLong := &e.bTable[nextHashL]
+ eLong.Cur, eLong.Prev = tableEntry{offset: nextS + e.cur}, eLong.Cur
+ break
+ }
+ }
+
+ t = sCandidate.offset - e.cur
+ if s-t < maxMatchOffset && uint32(cv) == load3232(src, sCandidate.offset-e.cur) {
+ // Found a 4 match...
+ l = e.matchlen(s+4, t+4, src) + 4
+
+ // Look up next long candidate (at nextS)
+ lCandidate = e.bTable[nextHashL]
+
+ // Store the next match
+ e.table[nextHashS] = tableEntry{offset: nextS + e.cur}
+ eLong := &e.bTable[nextHashL]
+ eLong.Cur, eLong.Prev = tableEntry{offset: nextS + e.cur}, eLong.Cur
+
+ // Check repeat at s + repOff
+ const repOff = 1
+ t2 := s - repeat + repOff
+ if load3232(src, t2) == uint32(cv>>(8*repOff)) {
+ ml := e.matchlen(s+4+repOff, t2+4, src) + 4
+ if ml > l {
+ t = t2
+ l = ml
+ s += repOff
+ // Not worth checking more.
+ break
+ }
+ }
+
+ // If the next long is a candidate, use that...
+ t2 = lCandidate.Cur.offset - e.cur
+ if nextS-t2 < maxMatchOffset {
+ if load3232(src, lCandidate.Cur.offset-e.cur) == uint32(next) {
+ ml := e.matchlen(nextS+4, t2+4, src) + 4
+ if ml > l {
+ t = t2
+ s = nextS
+ l = ml
+ // This is ok, but check previous as well.
+ }
+ }
+ // If the previous long is a candidate, use that...
+ t2 = lCandidate.Prev.offset - e.cur
+ if nextS-t2 < maxMatchOffset && load3232(src, lCandidate.Prev.offset-e.cur) == uint32(next) {
+ ml := e.matchlen(nextS+4, t2+4, src) + 4
+ if ml > l {
+ t = t2
+ s = nextS
+ l = ml
+ break
+ }
+ }
+ }
+ break
+ }
+ cv = next
+ }
+
+ // A 4-byte match has been found. We'll later see if more than 4 bytes
+ // match. But, prior to the match, src[nextEmit:s] are unmatched. Emit
+ // them as literal bytes.
+
+ // Extend the 4-byte match as long as possible.
+ if l == 0 {
+ l = e.matchlenLong(s+4, t+4, src) + 4
+ } else if l == maxMatchLength {
+ l += e.matchlenLong(s+l, t+l, src)
+ }
+
+ // Try to locate a better match by checking the end-of-match...
+ if sAt := s + l; sAt < sLimit {
+ // Allow some bytes at the beginning to mismatch.
+ // Sweet spot is 2/3 bytes depending on input.
+ // 3 is only a little better when it is but sometimes a lot worse.
+ // The skipped bytes are tested in Extend backwards,
+ // and still picked up as part of the match if they do.
+ const skipBeginning = 2
+ eLong := &e.bTable[hash7(load6432(src, sAt), tableBits)]
+ // Test current
+ t2 := eLong.Cur.offset - e.cur - l + skipBeginning
+ s2 := s + skipBeginning
+ off := s2 - t2
+ if off < maxMatchOffset {
+ if off > 0 && t2 >= 0 {
+ if l2 := e.matchlenLong(s2, t2, src); l2 > l {
+ t = t2
+ l = l2
+ s = s2
+ }
+ }
+ // Test next:
+ t2 = eLong.Prev.offset - e.cur - l + skipBeginning
+ off := s2 - t2
+ if off > 0 && off < maxMatchOffset && t2 >= 0 {
+ if l2 := e.matchlenLong(s2, t2, src); l2 > l {
+ t = t2
+ l = l2
+ s = s2
+ }
+ }
+ }
+ }
+
+ // Extend backwards
+ for t > 0 && s > nextEmit && src[t-1] == src[s-1] {
+ s--
+ t--
+ l++
+ }
+ if nextEmit < s {
+ if false {
+ emitLiteral(dst, src[nextEmit:s])
+ } else {
+ for _, v := range src[nextEmit:s] {
+ dst.tokens[dst.n] = token(v)
+ dst.litHist[v]++
+ dst.n++
+ }
+ }
+ }
+ if false {
+ if t >= s {
+ panic(fmt.Sprintln("s-t", s, t))
+ }
+ if (s - t) > maxMatchOffset {
+ panic(fmt.Sprintln("mmo", s-t))
+ }
+ if l < baseMatchLength {
+ panic("bml")
+ }
+ }
+
+ dst.AddMatchLong(l, uint32(s-t-baseMatchOffset))
+ repeat = s - t
+ s += l
+ nextEmit = s
+ if nextS >= s {
+ s = nextS + 1
+ }
+
+ if s >= sLimit {
+ // Index after match end.
+ for i := nextS + 1; i < int32(len(src))-8; i += 2 {
+ cv := load6432(src, i)
+ e.table[hashLen(cv, tableBits, hashShortBytes)] = tableEntry{offset: i + e.cur}
+ eLong := &e.bTable[hash7(cv, tableBits)]
+ eLong.Cur, eLong.Prev = tableEntry{offset: i + e.cur}, eLong.Cur
+ }
+ goto emitRemainder
+ }
+
+ // Store every long hash in-between and every second short.
+ if true {
+ for i := nextS + 1; i < s-1; i += 2 {
+ cv := load6432(src, i)
+ t := tableEntry{offset: i + e.cur}
+ t2 := tableEntry{offset: t.offset + 1}
+ eLong := &e.bTable[hash7(cv, tableBits)]
+ eLong2 := &e.bTable[hash7(cv>>8, tableBits)]
+ e.table[hashLen(cv, tableBits, hashShortBytes)] = t
+ eLong.Cur, eLong.Prev = t, eLong.Cur
+ eLong2.Cur, eLong2.Prev = t2, eLong2.Cur
+ }
+ }
+
+ // We could immediately start working at s now, but to improve
+ // compression we first update the hash table at s-1 and at s.
+ cv = load6432(src, s)
+ }
+
+emitRemainder:
+ if int(nextEmit) < len(src) {
+ // If nothing was added, don't encode literals.
+ if dst.n == 0 {
+ return
+ }
+
+ emitLiteral(dst, src[nextEmit:])
+ }
+}
diff --git a/vendor/github.com/klauspost/compress/flate/matchlen_amd64.go b/vendor/github.com/klauspost/compress/flate/matchlen_amd64.go
new file mode 100644
index 0000000..4bd3885
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/flate/matchlen_amd64.go
@@ -0,0 +1,16 @@
+//go:build amd64 && !appengine && !noasm && gc
+// +build amd64,!appengine,!noasm,gc
+
+// Copyright 2019+ Klaus Post. All rights reserved.
+// License information can be found in the LICENSE file.
+
+package flate
+
+// matchLen returns how many bytes match in a and b
+//
+// It assumes that:
+//
+// len(a) <= len(b) and len(a) > 0
+//
+//go:noescape
+func matchLen(a []byte, b []byte) int
diff --git a/vendor/github.com/klauspost/compress/flate/matchlen_amd64.s b/vendor/github.com/klauspost/compress/flate/matchlen_amd64.s
new file mode 100644
index 0000000..9a7655c
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/flate/matchlen_amd64.s
@@ -0,0 +1,68 @@
+// Copied from S2 implementation.
+
+//go:build !appengine && !noasm && gc && !noasm
+
+#include "textflag.h"
+
+// func matchLen(a []byte, b []byte) int
+// Requires: BMI
+TEXT ·matchLen(SB), NOSPLIT, $0-56
+ MOVQ a_base+0(FP), AX
+ MOVQ b_base+24(FP), CX
+ MOVQ a_len+8(FP), DX
+
+ // matchLen
+ XORL SI, SI
+ CMPL DX, $0x08
+ JB matchlen_match4_standalone
+
+matchlen_loopback_standalone:
+ MOVQ (AX)(SI*1), BX
+ XORQ (CX)(SI*1), BX
+ TESTQ BX, BX
+ JZ matchlen_loop_standalone
+
+#ifdef GOAMD64_v3
+ TZCNTQ BX, BX
+#else
+ BSFQ BX, BX
+#endif
+ SARQ $0x03, BX
+ LEAL (SI)(BX*1), SI
+ JMP gen_match_len_end
+
+matchlen_loop_standalone:
+ LEAL -8(DX), DX
+ LEAL 8(SI), SI
+ CMPL DX, $0x08
+ JAE matchlen_loopback_standalone
+
+matchlen_match4_standalone:
+ CMPL DX, $0x04
+ JB matchlen_match2_standalone
+ MOVL (AX)(SI*1), BX
+ CMPL (CX)(SI*1), BX
+ JNE matchlen_match2_standalone
+ LEAL -4(DX), DX
+ LEAL 4(SI), SI
+
+matchlen_match2_standalone:
+ CMPL DX, $0x02
+ JB matchlen_match1_standalone
+ MOVW (AX)(SI*1), BX
+ CMPW (CX)(SI*1), BX
+ JNE matchlen_match1_standalone
+ LEAL -2(DX), DX
+ LEAL 2(SI), SI
+
+matchlen_match1_standalone:
+ CMPL DX, $0x01
+ JB gen_match_len_end
+ MOVB (AX)(SI*1), BL
+ CMPB (CX)(SI*1), BL
+ JNE gen_match_len_end
+ INCL SI
+
+gen_match_len_end:
+ MOVQ SI, ret+48(FP)
+ RET
diff --git a/vendor/github.com/klauspost/compress/flate/matchlen_generic.go b/vendor/github.com/klauspost/compress/flate/matchlen_generic.go
new file mode 100644
index 0000000..ad5cd81
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/flate/matchlen_generic.go
@@ -0,0 +1,33 @@
+//go:build !amd64 || appengine || !gc || noasm
+// +build !amd64 appengine !gc noasm
+
+// Copyright 2019+ Klaus Post. All rights reserved.
+// License information can be found in the LICENSE file.
+
+package flate
+
+import (
+ "encoding/binary"
+ "math/bits"
+)
+
+// matchLen returns the maximum common prefix length of a and b.
+// a must be the shortest of the two.
+func matchLen(a, b []byte) (n int) {
+ for ; len(a) >= 8 && len(b) >= 8; a, b = a[8:], b[8:] {
+ diff := binary.LittleEndian.Uint64(a) ^ binary.LittleEndian.Uint64(b)
+ if diff != 0 {
+ return n + bits.TrailingZeros64(diff)>>3
+ }
+ n += 8
+ }
+
+ for i := range a {
+ if a[i] != b[i] {
+ break
+ }
+ n++
+ }
+ return n
+
+}
diff --git a/vendor/github.com/klauspost/compress/flate/regmask_amd64.go b/vendor/github.com/klauspost/compress/flate/regmask_amd64.go
new file mode 100644
index 0000000..6ed2806
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/flate/regmask_amd64.go
@@ -0,0 +1,37 @@
+package flate
+
+const (
+ // Masks for shifts with register sizes of the shift value.
+ // This can be used to work around the x86 design of shifting by mod register size.
+ // It can be used when a variable shift is always smaller than the register size.
+
+ // reg8SizeMaskX - shift value is 8 bits, shifted is X
+ reg8SizeMask8 = 7
+ reg8SizeMask16 = 15
+ reg8SizeMask32 = 31
+ reg8SizeMask64 = 63
+
+ // reg16SizeMaskX - shift value is 16 bits, shifted is X
+ reg16SizeMask8 = reg8SizeMask8
+ reg16SizeMask16 = reg8SizeMask16
+ reg16SizeMask32 = reg8SizeMask32
+ reg16SizeMask64 = reg8SizeMask64
+
+ // reg32SizeMaskX - shift value is 32 bits, shifted is X
+ reg32SizeMask8 = reg8SizeMask8
+ reg32SizeMask16 = reg8SizeMask16
+ reg32SizeMask32 = reg8SizeMask32
+ reg32SizeMask64 = reg8SizeMask64
+
+ // reg64SizeMaskX - shift value is 64 bits, shifted is X
+ reg64SizeMask8 = reg8SizeMask8
+ reg64SizeMask16 = reg8SizeMask16
+ reg64SizeMask32 = reg8SizeMask32
+ reg64SizeMask64 = reg8SizeMask64
+
+ // regSizeMaskUintX - shift value is uint, shifted is X
+ regSizeMaskUint8 = reg8SizeMask8
+ regSizeMaskUint16 = reg8SizeMask16
+ regSizeMaskUint32 = reg8SizeMask32
+ regSizeMaskUint64 = reg8SizeMask64
+)
diff --git a/vendor/github.com/klauspost/compress/flate/regmask_other.go b/vendor/github.com/klauspost/compress/flate/regmask_other.go
new file mode 100644
index 0000000..1b7a2cb
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/flate/regmask_other.go
@@ -0,0 +1,40 @@
+//go:build !amd64
+// +build !amd64
+
+package flate
+
+const (
+ // Masks for shifts with register sizes of the shift value.
+ // This can be used to work around the x86 design of shifting by mod register size.
+ // It can be used when a variable shift is always smaller than the register size.
+
+ // reg8SizeMaskX - shift value is 8 bits, shifted is X
+ reg8SizeMask8 = 0xff
+ reg8SizeMask16 = 0xff
+ reg8SizeMask32 = 0xff
+ reg8SizeMask64 = 0xff
+
+ // reg16SizeMaskX - shift value is 16 bits, shifted is X
+ reg16SizeMask8 = 0xffff
+ reg16SizeMask16 = 0xffff
+ reg16SizeMask32 = 0xffff
+ reg16SizeMask64 = 0xffff
+
+ // reg32SizeMaskX - shift value is 32 bits, shifted is X
+ reg32SizeMask8 = 0xffffffff
+ reg32SizeMask16 = 0xffffffff
+ reg32SizeMask32 = 0xffffffff
+ reg32SizeMask64 = 0xffffffff
+
+ // reg64SizeMaskX - shift value is 64 bits, shifted is X
+ reg64SizeMask8 = 0xffffffffffffffff
+ reg64SizeMask16 = 0xffffffffffffffff
+ reg64SizeMask32 = 0xffffffffffffffff
+ reg64SizeMask64 = 0xffffffffffffffff
+
+ // regSizeMaskUintX - shift value is uint, shifted is X
+ regSizeMaskUint8 = ^uint(0)
+ regSizeMaskUint16 = ^uint(0)
+ regSizeMaskUint32 = ^uint(0)
+ regSizeMaskUint64 = ^uint(0)
+)
diff --git a/vendor/github.com/klauspost/compress/flate/stateless.go b/vendor/github.com/klauspost/compress/flate/stateless.go
new file mode 100644
index 0000000..f3d4139
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/flate/stateless.go
@@ -0,0 +1,318 @@
+package flate
+
+import (
+ "io"
+ "math"
+ "sync"
+)
+
+const (
+ maxStatelessBlock = math.MaxInt16
+ // dictionary will be taken from maxStatelessBlock, so limit it.
+ maxStatelessDict = 8 << 10
+
+ slTableBits = 13
+ slTableSize = 1 << slTableBits
+ slTableShift = 32 - slTableBits
+)
+
+type statelessWriter struct {
+ dst io.Writer
+ closed bool
+}
+
+func (s *statelessWriter) Close() error {
+ if s.closed {
+ return nil
+ }
+ s.closed = true
+ // Emit EOF block
+ return StatelessDeflate(s.dst, nil, true, nil)
+}
+
+func (s *statelessWriter) Write(p []byte) (n int, err error) {
+ err = StatelessDeflate(s.dst, p, false, nil)
+ if err != nil {
+ return 0, err
+ }
+ return len(p), nil
+}
+
+func (s *statelessWriter) Reset(w io.Writer) {
+ s.dst = w
+ s.closed = false
+}
+
+// NewStatelessWriter will do compression but without maintaining any state
+// between Write calls.
+// There will be no memory kept between Write calls,
+// but compression and speed will be suboptimal.
+// Because of this, the size of actual Write calls will affect output size.
+func NewStatelessWriter(dst io.Writer) io.WriteCloser {
+ return &statelessWriter{dst: dst}
+}
+
+// bitWriterPool contains bit writers that can be reused.
+var bitWriterPool = sync.Pool{
+ New: func() interface{} {
+ return newHuffmanBitWriter(nil)
+ },
+}
+
+// StatelessDeflate allows compressing directly to a Writer without retaining state.
+// When returning everything will be flushed.
+// Up to 8KB of an optional dictionary can be given which is presumed to precede the block.
+// Longer dictionaries will be truncated and will still produce valid output.
+// Sending nil dictionary is perfectly fine.
+func StatelessDeflate(out io.Writer, in []byte, eof bool, dict []byte) error {
+ var dst tokens
+ bw := bitWriterPool.Get().(*huffmanBitWriter)
+ bw.reset(out)
+ defer func() {
+ // don't keep a reference to our output
+ bw.reset(nil)
+ bitWriterPool.Put(bw)
+ }()
+ if eof && len(in) == 0 {
+ // Just write an EOF block.
+ // Could be faster...
+ bw.writeStoredHeader(0, true)
+ bw.flush()
+ return bw.err
+ }
+
+ // Truncate dict
+ if len(dict) > maxStatelessDict {
+ dict = dict[len(dict)-maxStatelessDict:]
+ }
+
+ // For subsequent loops, keep shallow dict reference to avoid alloc+copy.
+ var inDict []byte
+
+ for len(in) > 0 {
+ todo := in
+ if len(inDict) > 0 {
+ if len(todo) > maxStatelessBlock-maxStatelessDict {
+ todo = todo[:maxStatelessBlock-maxStatelessDict]
+ }
+ } else if len(todo) > maxStatelessBlock-len(dict) {
+ todo = todo[:maxStatelessBlock-len(dict)]
+ }
+ inOrg := in
+ in = in[len(todo):]
+ uncompressed := todo
+ if len(dict) > 0 {
+ // combine dict and source
+ bufLen := len(todo) + len(dict)
+ combined := make([]byte, bufLen)
+ copy(combined, dict)
+ copy(combined[len(dict):], todo)
+ todo = combined
+ }
+ // Compress
+ if len(inDict) == 0 {
+ statelessEnc(&dst, todo, int16(len(dict)))
+ } else {
+ statelessEnc(&dst, inDict[:maxStatelessDict+len(todo)], maxStatelessDict)
+ }
+ isEof := eof && len(in) == 0
+
+ if dst.n == 0 {
+ bw.writeStoredHeader(len(uncompressed), isEof)
+ if bw.err != nil {
+ return bw.err
+ }
+ bw.writeBytes(uncompressed)
+ } else if int(dst.n) > len(uncompressed)-len(uncompressed)>>4 {
+ // If we removed less than 1/16th, huffman compress the block.
+ bw.writeBlockHuff(isEof, uncompressed, len(in) == 0)
+ } else {
+ bw.writeBlockDynamic(&dst, isEof, uncompressed, len(in) == 0)
+ }
+ if len(in) > 0 {
+ // Retain a dict if we have more
+ inDict = inOrg[len(uncompressed)-maxStatelessDict:]
+ dict = nil
+ dst.Reset()
+ }
+ if bw.err != nil {
+ return bw.err
+ }
+ }
+ if !eof {
+ // Align, only a stored block can do that.
+ bw.writeStoredHeader(0, false)
+ }
+ bw.flush()
+ return bw.err
+}
+
+func hashSL(u uint32) uint32 {
+ return (u * 0x1e35a7bd) >> slTableShift
+}
+
+func load3216(b []byte, i int16) uint32 {
+ // Help the compiler eliminate bounds checks on the read so it can be done in a single read.
+ b = b[i:]
+ b = b[:4]
+ return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
+}
+
+func load6416(b []byte, i int16) uint64 {
+ // Help the compiler eliminate bounds checks on the read so it can be done in a single read.
+ b = b[i:]
+ b = b[:8]
+ return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 |
+ uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56
+}
+
+func statelessEnc(dst *tokens, src []byte, startAt int16) {
+ const (
+ inputMargin = 12 - 1
+ minNonLiteralBlockSize = 1 + 1 + inputMargin
+ )
+
+ type tableEntry struct {
+ offset int16
+ }
+
+ var table [slTableSize]tableEntry
+
+ // This check isn't in the Snappy implementation, but there, the caller
+ // instead of the callee handles this case.
+ if len(src)-int(startAt) < minNonLiteralBlockSize {
+ // We do not fill the token table.
+ // This will be picked up by caller.
+ dst.n = 0
+ return
+ }
+ // Index until startAt
+ if startAt > 0 {
+ cv := load3232(src, 0)
+ for i := int16(0); i < startAt; i++ {
+ table[hashSL(cv)] = tableEntry{offset: i}
+ cv = (cv >> 8) | (uint32(src[i+4]) << 24)
+ }
+ }
+
+ s := startAt + 1
+ nextEmit := startAt
+ // sLimit is when to stop looking for offset/length copies. The inputMargin
+ // lets us use a fast path for emitLiteral in the main loop, while we are
+ // looking for copies.
+ sLimit := int16(len(src) - inputMargin)
+
+ // nextEmit is where in src the next emitLiteral should start from.
+ cv := load3216(src, s)
+
+ for {
+ const skipLog = 5
+ const doEvery = 2
+
+ nextS := s
+ var candidate tableEntry
+ for {
+ nextHash := hashSL(cv)
+ candidate = table[nextHash]
+ nextS = s + doEvery + (s-nextEmit)>>skipLog
+ if nextS > sLimit || nextS <= 0 {
+ goto emitRemainder
+ }
+
+ now := load6416(src, nextS)
+ table[nextHash] = tableEntry{offset: s}
+ nextHash = hashSL(uint32(now))
+
+ if cv == load3216(src, candidate.offset) {
+ table[nextHash] = tableEntry{offset: nextS}
+ break
+ }
+
+ // Do one right away...
+ cv = uint32(now)
+ s = nextS
+ nextS++
+ candidate = table[nextHash]
+ now >>= 8
+ table[nextHash] = tableEntry{offset: s}
+
+ if cv == load3216(src, candidate.offset) {
+ table[nextHash] = tableEntry{offset: nextS}
+ break
+ }
+ cv = uint32(now)
+ s = nextS
+ }
+
+ // A 4-byte match has been found. We'll later see if more than 4 bytes
+ // match. But, prior to the match, src[nextEmit:s] are unmatched. Emit
+ // them as literal bytes.
+ for {
+ // Invariant: we have a 4-byte match at s, and no need to emit any
+ // literal bytes prior to s.
+
+ // Extend the 4-byte match as long as possible.
+ t := candidate.offset
+ l := int16(matchLen(src[s+4:], src[t+4:]) + 4)
+
+ // Extend backwards
+ for t > 0 && s > nextEmit && src[t-1] == src[s-1] {
+ s--
+ t--
+ l++
+ }
+ if nextEmit < s {
+ if false {
+ emitLiteral(dst, src[nextEmit:s])
+ } else {
+ for _, v := range src[nextEmit:s] {
+ dst.tokens[dst.n] = token(v)
+ dst.litHist[v]++
+ dst.n++
+ }
+ }
+ }
+
+ // Save the match found
+ dst.AddMatchLong(int32(l), uint32(s-t-baseMatchOffset))
+ s += l
+ nextEmit = s
+ if nextS >= s {
+ s = nextS + 1
+ }
+ if s >= sLimit {
+ goto emitRemainder
+ }
+
+ // We could immediately start working at s now, but to improve
+ // compression we first update the hash table at s-2 and at s. If
+ // another emitCopy is not our next move, also calculate nextHash
+ // at s+1. At least on GOARCH=amd64, these three hash calculations
+ // are faster as one load64 call (with some shifts) instead of
+ // three load32 calls.
+ x := load6416(src, s-2)
+ o := s - 2
+ prevHash := hashSL(uint32(x))
+ table[prevHash] = tableEntry{offset: o}
+ x >>= 16
+ currHash := hashSL(uint32(x))
+ candidate = table[currHash]
+ table[currHash] = tableEntry{offset: o + 2}
+
+ if uint32(x) != load3216(src, candidate.offset) {
+ cv = uint32(x >> 8)
+ s++
+ break
+ }
+ }
+ }
+
+emitRemainder:
+ if int(nextEmit) < len(src) {
+ // If nothing was added, don't encode literals.
+ if dst.n == 0 {
+ return
+ }
+ emitLiteral(dst, src[nextEmit:])
+ }
+}
diff --git a/vendor/github.com/klauspost/compress/flate/token.go b/vendor/github.com/klauspost/compress/flate/token.go
new file mode 100644
index 0000000..d818790
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/flate/token.go
@@ -0,0 +1,379 @@
+// Copyright 2009 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 flate
+
+import (
+ "bytes"
+ "encoding/binary"
+ "fmt"
+ "io"
+ "math"
+)
+
+const (
+ // bits 0-16 xoffset = offset - MIN_OFFSET_SIZE, or literal - 16 bits
+ // bits 16-22 offsetcode - 5 bits
+ // bits 22-30 xlength = length - MIN_MATCH_LENGTH - 8 bits
+ // bits 30-32 type 0 = literal 1=EOF 2=Match 3=Unused - 2 bits
+ lengthShift = 22
+ offsetMask = 1<maxnumlit
+ offHist [32]uint16 // offset codes
+ litHist [256]uint16 // codes 0->255
+ nFilled int
+ n uint16 // Must be able to contain maxStoreBlockSize
+ tokens [maxStoreBlockSize + 1]token
+}
+
+func (t *tokens) Reset() {
+ if t.n == 0 {
+ return
+ }
+ t.n = 0
+ t.nFilled = 0
+ for i := range t.litHist[:] {
+ t.litHist[i] = 0
+ }
+ for i := range t.extraHist[:] {
+ t.extraHist[i] = 0
+ }
+ for i := range t.offHist[:] {
+ t.offHist[i] = 0
+ }
+}
+
+func (t *tokens) Fill() {
+ if t.n == 0 {
+ return
+ }
+ for i, v := range t.litHist[:] {
+ if v == 0 {
+ t.litHist[i] = 1
+ t.nFilled++
+ }
+ }
+ for i, v := range t.extraHist[:literalCount-256] {
+ if v == 0 {
+ t.nFilled++
+ t.extraHist[i] = 1
+ }
+ }
+ for i, v := range t.offHist[:offsetCodeCount] {
+ if v == 0 {
+ t.offHist[i] = 1
+ }
+ }
+}
+
+func indexTokens(in []token) tokens {
+ var t tokens
+ t.indexTokens(in)
+ return t
+}
+
+func (t *tokens) indexTokens(in []token) {
+ t.Reset()
+ for _, tok := range in {
+ if tok < matchType {
+ t.AddLiteral(tok.literal())
+ continue
+ }
+ t.AddMatch(uint32(tok.length()), tok.offset()&matchOffsetOnlyMask)
+ }
+}
+
+// emitLiteral writes a literal chunk and returns the number of bytes written.
+func emitLiteral(dst *tokens, lit []byte) {
+ for _, v := range lit {
+ dst.tokens[dst.n] = token(v)
+ dst.litHist[v]++
+ dst.n++
+ }
+}
+
+func (t *tokens) AddLiteral(lit byte) {
+ t.tokens[t.n] = token(lit)
+ t.litHist[lit]++
+ t.n++
+}
+
+// from https://stackoverflow.com/a/28730362
+func mFastLog2(val float32) float32 {
+ ux := int32(math.Float32bits(val))
+ log2 := (float32)(((ux >> 23) & 255) - 128)
+ ux &= -0x7f800001
+ ux += 127 << 23
+ uval := math.Float32frombits(uint32(ux))
+ log2 += ((-0.34484843)*uval+2.02466578)*uval - 0.67487759
+ return log2
+}
+
+// EstimatedBits will return an minimum size estimated by an *optimal*
+// compression of the block.
+// The size of the block
+func (t *tokens) EstimatedBits() int {
+ shannon := float32(0)
+ bits := int(0)
+ nMatches := 0
+ total := int(t.n) + t.nFilled
+ if total > 0 {
+ invTotal := 1.0 / float32(total)
+ for _, v := range t.litHist[:] {
+ if v > 0 {
+ n := float32(v)
+ shannon += atLeastOne(-mFastLog2(n*invTotal)) * n
+ }
+ }
+ // Just add 15 for EOB
+ shannon += 15
+ for i, v := range t.extraHist[1 : literalCount-256] {
+ if v > 0 {
+ n := float32(v)
+ shannon += atLeastOne(-mFastLog2(n*invTotal)) * n
+ bits += int(lengthExtraBits[i&31]) * int(v)
+ nMatches += int(v)
+ }
+ }
+ }
+ if nMatches > 0 {
+ invTotal := 1.0 / float32(nMatches)
+ for i, v := range t.offHist[:offsetCodeCount] {
+ if v > 0 {
+ n := float32(v)
+ shannon += atLeastOne(-mFastLog2(n*invTotal)) * n
+ bits += int(offsetExtraBits[i&31]) * int(v)
+ }
+ }
+ }
+ return int(shannon) + bits
+}
+
+// AddMatch adds a match to the tokens.
+// This function is very sensitive to inlining and right on the border.
+func (t *tokens) AddMatch(xlength uint32, xoffset uint32) {
+ if debugDeflate {
+ if xlength >= maxMatchLength+baseMatchLength {
+ panic(fmt.Errorf("invalid length: %v", xlength))
+ }
+ if xoffset >= maxMatchOffset+baseMatchOffset {
+ panic(fmt.Errorf("invalid offset: %v", xoffset))
+ }
+ }
+ oCode := offsetCode(xoffset)
+ xoffset |= oCode << 16
+
+ t.extraHist[lengthCodes1[uint8(xlength)]]++
+ t.offHist[oCode&31]++
+ t.tokens[t.n] = token(matchType | xlength<= maxMatchOffset+baseMatchOffset {
+ panic(fmt.Errorf("invalid offset: %v", xoffset))
+ }
+ }
+ oc := offsetCode(xoffset)
+ xoffset |= oc << 16
+ for xlength > 0 {
+ xl := xlength
+ if xl > 258 {
+ // We need to have at least baseMatchLength left over for next loop.
+ if xl > 258+baseMatchLength {
+ xl = 258
+ } else {
+ xl = 258 - baseMatchLength
+ }
+ }
+ xlength -= xl
+ xl -= baseMatchLength
+ t.extraHist[lengthCodes1[uint8(xl)]]++
+ t.offHist[oc&31]++
+ t.tokens[t.n] = token(matchType | uint32(xl)<> lengthShift) }
+
+// Convert length to code.
+func lengthCode(len uint8) uint8 { return lengthCodes[len] }
+
+// Returns the offset code corresponding to a specific offset
+func offsetCode(off uint32) uint32 {
+ if false {
+ if off < uint32(len(offsetCodes)) {
+ return offsetCodes[off&255]
+ } else if off>>7 < uint32(len(offsetCodes)) {
+ return offsetCodes[(off>>7)&255] + 14
+ } else {
+ return offsetCodes[(off>>14)&255] + 28
+ }
+ }
+ if off < uint32(len(offsetCodes)) {
+ return offsetCodes[uint8(off)]
+ }
+ return offsetCodes14[uint8(off>>7)]
+}
diff --git a/vendor/github.com/klauspost/compress/gzip/gunzip.go b/vendor/github.com/klauspost/compress/gzip/gunzip.go
new file mode 100644
index 0000000..00a0a2c
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/gzip/gunzip.go
@@ -0,0 +1,380 @@
+// Copyright 2009 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 gzip implements reading and writing of gzip format compressed files,
+// as specified in RFC 1952.
+package gzip
+
+import (
+ "bufio"
+ "compress/gzip"
+ "encoding/binary"
+ "hash/crc32"
+ "io"
+ "time"
+
+ "github.com/klauspost/compress/flate"
+)
+
+const (
+ gzipID1 = 0x1f
+ gzipID2 = 0x8b
+ gzipDeflate = 8
+ flagText = 1 << 0
+ flagHdrCrc = 1 << 1
+ flagExtra = 1 << 2
+ flagName = 1 << 3
+ flagComment = 1 << 4
+)
+
+var (
+ // ErrChecksum is returned when reading GZIP data that has an invalid checksum.
+ ErrChecksum = gzip.ErrChecksum
+ // ErrHeader is returned when reading GZIP data that has an invalid header.
+ ErrHeader = gzip.ErrHeader
+)
+
+var le = binary.LittleEndian
+
+// noEOF converts io.EOF to io.ErrUnexpectedEOF.
+func noEOF(err error) error {
+ if err == io.EOF {
+ return io.ErrUnexpectedEOF
+ }
+ return err
+}
+
+// The gzip file stores a header giving metadata about the compressed file.
+// That header is exposed as the fields of the Writer and Reader structs.
+//
+// Strings must be UTF-8 encoded and may only contain Unicode code points
+// U+0001 through U+00FF, due to limitations of the GZIP file format.
+type Header struct {
+ Comment string // comment
+ Extra []byte // "extra data"
+ ModTime time.Time // modification time
+ Name string // file name
+ OS byte // operating system type
+}
+
+// A Reader is an io.Reader that can be read to retrieve
+// uncompressed data from a gzip-format compressed file.
+//
+// In general, a gzip file can be a concatenation of gzip files,
+// each with its own header. Reads from the Reader
+// return the concatenation of the uncompressed data of each.
+// Only the first header is recorded in the Reader fields.
+//
+// Gzip files store a length and checksum of the uncompressed data.
+// The Reader will return a ErrChecksum when Read
+// reaches the end of the uncompressed data if it does not
+// have the expected length or checksum. Clients should treat data
+// returned by Read as tentative until they receive the io.EOF
+// marking the end of the data.
+type Reader struct {
+ Header // valid after NewReader or Reader.Reset
+ r flate.Reader
+ br *bufio.Reader
+ decompressor io.ReadCloser
+ digest uint32 // CRC-32, IEEE polynomial (section 8)
+ size uint32 // Uncompressed size (section 2.3.1)
+ buf [512]byte
+ err error
+ multistream bool
+}
+
+// NewReader creates a new Reader reading the given reader.
+// If r does not also implement io.ByteReader,
+// the decompressor may read more data than necessary from r.
+//
+// It is the caller's responsibility to call Close on the Reader when done.
+//
+// The Reader.Header fields will be valid in the Reader returned.
+func NewReader(r io.Reader) (*Reader, error) {
+ z := new(Reader)
+ if err := z.Reset(r); err != nil {
+ return nil, err
+ }
+ return z, nil
+}
+
+// Reset discards the Reader z's state and makes it equivalent to the
+// result of its original state from NewReader, but reading from r instead.
+// This permits reusing a Reader rather than allocating a new one.
+func (z *Reader) Reset(r io.Reader) error {
+ *z = Reader{
+ decompressor: z.decompressor,
+ multistream: true,
+ br: z.br,
+ }
+ if rr, ok := r.(flate.Reader); ok {
+ z.r = rr
+ } else {
+ // Reuse if we can.
+ if z.br != nil {
+ z.br.Reset(r)
+ } else {
+ z.br = bufio.NewReader(r)
+ }
+ z.r = z.br
+ }
+ z.Header, z.err = z.readHeader()
+ return z.err
+}
+
+// Multistream controls whether the reader supports multistream files.
+//
+// If enabled (the default), the Reader expects the input to be a sequence
+// of individually gzipped data streams, each with its own header and
+// trailer, ending at EOF. The effect is that the concatenation of a sequence
+// of gzipped files is treated as equivalent to the gzip of the concatenation
+// of the sequence. This is standard behavior for gzip readers.
+//
+// Calling Multistream(false) disables this behavior; disabling the behavior
+// can be useful when reading file formats that distinguish individual gzip
+// data streams or mix gzip data streams with other data streams.
+// In this mode, when the Reader reaches the end of the data stream,
+// Read returns io.EOF. If the underlying reader implements io.ByteReader,
+// it will be left positioned just after the gzip stream.
+// To start the next stream, call z.Reset(r) followed by z.Multistream(false).
+// If there is no next stream, z.Reset(r) will return io.EOF.
+func (z *Reader) Multistream(ok bool) {
+ z.multistream = ok
+}
+
+// readString reads a NUL-terminated string from z.r.
+// It treats the bytes read as being encoded as ISO 8859-1 (Latin-1) and
+// will output a string encoded using UTF-8.
+// This method always updates z.digest with the data read.
+func (z *Reader) readString() (string, error) {
+ var err error
+ needConv := false
+ for i := 0; ; i++ {
+ if i >= len(z.buf) {
+ return "", ErrHeader
+ }
+ z.buf[i], err = z.r.ReadByte()
+ if err != nil {
+ return "", err
+ }
+ if z.buf[i] > 0x7f {
+ needConv = true
+ }
+ if z.buf[i] == 0 {
+ // Digest covers the NUL terminator.
+ z.digest = crc32.Update(z.digest, crc32.IEEETable, z.buf[:i+1])
+
+ // Strings are ISO 8859-1, Latin-1 (RFC 1952, section 2.3.1).
+ if needConv {
+ s := make([]rune, 0, i)
+ for _, v := range z.buf[:i] {
+ s = append(s, rune(v))
+ }
+ return string(s), nil
+ }
+ return string(z.buf[:i]), nil
+ }
+ }
+}
+
+// readHeader reads the GZIP header according to section 2.3.1.
+// This method does not set z.err.
+func (z *Reader) readHeader() (hdr Header, err error) {
+ if _, err = io.ReadFull(z.r, z.buf[:10]); err != nil {
+ // RFC 1952, section 2.2, says the following:
+ // A gzip file consists of a series of "members" (compressed data sets).
+ //
+ // Other than this, the specification does not clarify whether a
+ // "series" is defined as "one or more" or "zero or more". To err on the
+ // side of caution, Go interprets this to mean "zero or more".
+ // Thus, it is okay to return io.EOF here.
+ return hdr, err
+ }
+ if z.buf[0] != gzipID1 || z.buf[1] != gzipID2 || z.buf[2] != gzipDeflate {
+ return hdr, ErrHeader
+ }
+ flg := z.buf[3]
+ hdr.ModTime = time.Unix(int64(le.Uint32(z.buf[4:8])), 0)
+ // z.buf[8] is XFL and is currently ignored.
+ hdr.OS = z.buf[9]
+ z.digest = crc32.ChecksumIEEE(z.buf[:10])
+
+ if flg&flagExtra != 0 {
+ if _, err = io.ReadFull(z.r, z.buf[:2]); err != nil {
+ return hdr, noEOF(err)
+ }
+ z.digest = crc32.Update(z.digest, crc32.IEEETable, z.buf[:2])
+ data := make([]byte, le.Uint16(z.buf[:2]))
+ if _, err = io.ReadFull(z.r, data); err != nil {
+ return hdr, noEOF(err)
+ }
+ z.digest = crc32.Update(z.digest, crc32.IEEETable, data)
+ hdr.Extra = data
+ }
+
+ var s string
+ if flg&flagName != 0 {
+ if s, err = z.readString(); err != nil {
+ return hdr, err
+ }
+ hdr.Name = s
+ }
+
+ if flg&flagComment != 0 {
+ if s, err = z.readString(); err != nil {
+ return hdr, err
+ }
+ hdr.Comment = s
+ }
+
+ if flg&flagHdrCrc != 0 {
+ if _, err = io.ReadFull(z.r, z.buf[:2]); err != nil {
+ return hdr, noEOF(err)
+ }
+ digest := le.Uint16(z.buf[:2])
+ if digest != uint16(z.digest) {
+ return hdr, ErrHeader
+ }
+ }
+
+ // Reserved FLG bits must be zero.
+ if flg>>5 != 0 {
+ return hdr, ErrHeader
+ }
+
+ z.digest = 0
+ if z.decompressor == nil {
+ z.decompressor = flate.NewReader(z.r)
+ } else {
+ z.decompressor.(flate.Resetter).Reset(z.r, nil)
+ }
+ return hdr, nil
+}
+
+// Read implements io.Reader, reading uncompressed bytes from its underlying Reader.
+func (z *Reader) Read(p []byte) (n int, err error) {
+ if z.err != nil {
+ return 0, z.err
+ }
+
+ for n == 0 {
+ n, z.err = z.decompressor.Read(p)
+ z.digest = crc32.Update(z.digest, crc32.IEEETable, p[:n])
+ z.size += uint32(n)
+ if z.err != io.EOF {
+ // In the normal case we return here.
+ return n, z.err
+ }
+
+ // Finished file; check checksum and size.
+ if _, err := io.ReadFull(z.r, z.buf[:8]); err != nil {
+ z.err = noEOF(err)
+ return n, z.err
+ }
+ digest := le.Uint32(z.buf[:4])
+ size := le.Uint32(z.buf[4:8])
+ if digest != z.digest || size != z.size {
+ z.err = ErrChecksum
+ return n, z.err
+ }
+ z.digest, z.size = 0, 0
+
+ // File is ok; check if there is another.
+ if !z.multistream {
+ return n, io.EOF
+ }
+ z.err = nil // Remove io.EOF
+
+ if _, z.err = z.readHeader(); z.err != nil {
+ return n, z.err
+ }
+ }
+
+ return n, nil
+}
+
+type crcer interface {
+ io.Writer
+ Sum32() uint32
+ Reset()
+}
+type crcUpdater struct {
+ z *Reader
+}
+
+func (c *crcUpdater) Write(p []byte) (int, error) {
+ c.z.digest = crc32.Update(c.z.digest, crc32.IEEETable, p)
+ return len(p), nil
+}
+
+func (c *crcUpdater) Sum32() uint32 {
+ return c.z.digest
+}
+
+func (c *crcUpdater) Reset() {
+ c.z.digest = 0
+}
+
+// WriteTo support the io.WriteTo interface for io.Copy and friends.
+func (z *Reader) WriteTo(w io.Writer) (int64, error) {
+ total := int64(0)
+ crcWriter := crcer(crc32.NewIEEE())
+ if z.digest != 0 {
+ crcWriter = &crcUpdater{z: z}
+ }
+ for {
+ if z.err != nil {
+ if z.err == io.EOF {
+ return total, nil
+ }
+ return total, z.err
+ }
+
+ // We write both to output and digest.
+ mw := io.MultiWriter(w, crcWriter)
+ n, err := z.decompressor.(io.WriterTo).WriteTo(mw)
+ total += n
+ z.size += uint32(n)
+ if err != nil {
+ z.err = err
+ return total, z.err
+ }
+
+ // Finished file; check checksum + size.
+ if _, err := io.ReadFull(z.r, z.buf[0:8]); err != nil {
+ if err == io.EOF {
+ err = io.ErrUnexpectedEOF
+ }
+ z.err = err
+ return total, err
+ }
+ z.digest = crcWriter.Sum32()
+ digest := le.Uint32(z.buf[:4])
+ size := le.Uint32(z.buf[4:8])
+ if digest != z.digest || size != z.size {
+ z.err = ErrChecksum
+ return total, z.err
+ }
+ z.digest, z.size = 0, 0
+
+ // File is ok; check if there is another.
+ if !z.multistream {
+ return total, nil
+ }
+ crcWriter.Reset()
+ z.err = nil // Remove io.EOF
+
+ if _, z.err = z.readHeader(); z.err != nil {
+ if z.err == io.EOF {
+ return total, nil
+ }
+ return total, z.err
+ }
+ }
+}
+
+// Close closes the Reader. It does not close the underlying io.Reader.
+// In order for the GZIP checksum to be verified, the reader must be
+// fully consumed until the io.EOF.
+func (z *Reader) Close() error { return z.decompressor.Close() }
diff --git a/vendor/github.com/klauspost/compress/gzip/gzip.go b/vendor/github.com/klauspost/compress/gzip/gzip.go
new file mode 100644
index 0000000..5bc7205
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/gzip/gzip.go
@@ -0,0 +1,290 @@
+// 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 gzip
+
+import (
+ "errors"
+ "fmt"
+ "hash/crc32"
+ "io"
+
+ "github.com/klauspost/compress/flate"
+)
+
+// These constants are copied from the flate package, so that code that imports
+// "compress/gzip" does not also have to import "compress/flate".
+const (
+ NoCompression = flate.NoCompression
+ BestSpeed = flate.BestSpeed
+ BestCompression = flate.BestCompression
+ DefaultCompression = flate.DefaultCompression
+ ConstantCompression = flate.ConstantCompression
+ HuffmanOnly = flate.HuffmanOnly
+
+ // StatelessCompression will do compression but without maintaining any state
+ // between Write calls.
+ // There will be no memory kept between Write calls,
+ // but compression and speed will be suboptimal.
+ // Because of this, the size of actual Write calls will affect output size.
+ StatelessCompression = -3
+)
+
+// A Writer is an io.WriteCloser.
+// Writes to a Writer are compressed and written to w.
+type Writer struct {
+ Header // written at first call to Write, Flush, or Close
+ w io.Writer
+ level int
+ err error
+ compressor *flate.Writer
+ digest uint32 // CRC-32, IEEE polynomial (section 8)
+ size uint32 // Uncompressed size (section 2.3.1)
+ wroteHeader bool
+ closed bool
+ buf [10]byte
+}
+
+// NewWriter returns a new Writer.
+// Writes to the returned writer are compressed and written to w.
+//
+// It is the caller's responsibility to call Close on the WriteCloser when done.
+// Writes may be buffered and not flushed until Close.
+//
+// Callers that wish to set the fields in Writer.Header must do so before
+// the first call to Write, Flush, or Close.
+func NewWriter(w io.Writer) *Writer {
+ z, _ := NewWriterLevel(w, DefaultCompression)
+ return z
+}
+
+// NewWriterLevel is like NewWriter but specifies the compression level instead
+// of assuming DefaultCompression.
+//
+// The compression level can be DefaultCompression, NoCompression, or any
+// integer value between BestSpeed and BestCompression inclusive. The error
+// returned will be nil if the level is valid.
+func NewWriterLevel(w io.Writer, level int) (*Writer, error) {
+ if level < StatelessCompression || level > BestCompression {
+ return nil, fmt.Errorf("gzip: invalid compression level: %d", level)
+ }
+ z := new(Writer)
+ z.init(w, level)
+ return z, nil
+}
+
+// MinCustomWindowSize is the minimum window size that can be sent to NewWriterWindow.
+const MinCustomWindowSize = flate.MinCustomWindowSize
+
+// MaxCustomWindowSize is the maximum custom window that can be sent to NewWriterWindow.
+const MaxCustomWindowSize = flate.MaxCustomWindowSize
+
+// NewWriterWindow returns a new Writer compressing data with a custom window size.
+// windowSize must be from MinCustomWindowSize to MaxCustomWindowSize.
+func NewWriterWindow(w io.Writer, windowSize int) (*Writer, error) {
+ if windowSize < MinCustomWindowSize {
+ return nil, errors.New("gzip: requested window size less than MinWindowSize")
+ }
+ if windowSize > MaxCustomWindowSize {
+ return nil, errors.New("gzip: requested window size bigger than MaxCustomWindowSize")
+ }
+
+ z := new(Writer)
+ z.init(w, -windowSize)
+ return z, nil
+}
+
+func (z *Writer) init(w io.Writer, level int) {
+ compressor := z.compressor
+ if level != StatelessCompression {
+ if compressor != nil {
+ compressor.Reset(w)
+ }
+ }
+
+ *z = Writer{
+ Header: Header{
+ OS: 255, // unknown
+ },
+ w: w,
+ level: level,
+ compressor: compressor,
+ }
+}
+
+// Reset discards the Writer z's state and makes it equivalent to the
+// result of its original state from NewWriter or NewWriterLevel, but
+// writing to w instead. This permits reusing a Writer rather than
+// allocating a new one.
+func (z *Writer) Reset(w io.Writer) {
+ z.init(w, z.level)
+}
+
+// writeBytes writes a length-prefixed byte slice to z.w.
+func (z *Writer) writeBytes(b []byte) error {
+ if len(b) > 0xffff {
+ return errors.New("gzip.Write: Extra data is too large")
+ }
+ le.PutUint16(z.buf[:2], uint16(len(b)))
+ _, err := z.w.Write(z.buf[:2])
+ if err != nil {
+ return err
+ }
+ _, err = z.w.Write(b)
+ return err
+}
+
+// writeString writes a UTF-8 string s in GZIP's format to z.w.
+// GZIP (RFC 1952) specifies that strings are NUL-terminated ISO 8859-1 (Latin-1).
+func (z *Writer) writeString(s string) (err error) {
+ // GZIP stores Latin-1 strings; error if non-Latin-1; convert if non-ASCII.
+ needconv := false
+ for _, v := range s {
+ if v == 0 || v > 0xff {
+ return errors.New("gzip.Write: non-Latin-1 header string")
+ }
+ if v > 0x7f {
+ needconv = true
+ }
+ }
+ if needconv {
+ b := make([]byte, 0, len(s))
+ for _, v := range s {
+ b = append(b, byte(v))
+ }
+ _, err = z.w.Write(b)
+ } else {
+ _, err = io.WriteString(z.w, s)
+ }
+ if err != nil {
+ return err
+ }
+ // GZIP strings are NUL-terminated.
+ z.buf[0] = 0
+ _, err = z.w.Write(z.buf[:1])
+ return err
+}
+
+// Write writes a compressed form of p to the underlying io.Writer. The
+// compressed bytes are not necessarily flushed until the Writer is closed.
+func (z *Writer) Write(p []byte) (int, error) {
+ if z.err != nil {
+ return 0, z.err
+ }
+ var n int
+ // Write the GZIP header lazily.
+ if !z.wroteHeader {
+ z.wroteHeader = true
+ z.buf[0] = gzipID1
+ z.buf[1] = gzipID2
+ z.buf[2] = gzipDeflate
+ z.buf[3] = 0
+ if z.Extra != nil {
+ z.buf[3] |= 0x04
+ }
+ if z.Name != "" {
+ z.buf[3] |= 0x08
+ }
+ if z.Comment != "" {
+ z.buf[3] |= 0x10
+ }
+ le.PutUint32(z.buf[4:8], uint32(z.ModTime.Unix()))
+ if z.level == BestCompression {
+ z.buf[8] = 2
+ } else if z.level == BestSpeed {
+ z.buf[8] = 4
+ } else {
+ z.buf[8] = 0
+ }
+ z.buf[9] = z.OS
+ n, z.err = z.w.Write(z.buf[:10])
+ if z.err != nil {
+ return n, z.err
+ }
+ if z.Extra != nil {
+ z.err = z.writeBytes(z.Extra)
+ if z.err != nil {
+ return n, z.err
+ }
+ }
+ if z.Name != "" {
+ z.err = z.writeString(z.Name)
+ if z.err != nil {
+ return n, z.err
+ }
+ }
+ if z.Comment != "" {
+ z.err = z.writeString(z.Comment)
+ if z.err != nil {
+ return n, z.err
+ }
+ }
+
+ if z.compressor == nil && z.level != StatelessCompression {
+ z.compressor, _ = flate.NewWriter(z.w, z.level)
+ }
+ }
+ z.size += uint32(len(p))
+ z.digest = crc32.Update(z.digest, crc32.IEEETable, p)
+ if z.level == StatelessCompression {
+ return len(p), flate.StatelessDeflate(z.w, p, false, nil)
+ }
+ n, z.err = z.compressor.Write(p)
+ return n, z.err
+}
+
+// Flush flushes any pending compressed data to the underlying writer.
+//
+// It is useful mainly in compressed network protocols, to ensure that
+// a remote reader has enough data to reconstruct a packet. Flush does
+// not return until the data has been written. If the underlying
+// writer returns an error, Flush returns that error.
+//
+// In the terminology of the zlib library, Flush is equivalent to Z_SYNC_FLUSH.
+func (z *Writer) Flush() error {
+ if z.err != nil {
+ return z.err
+ }
+ if z.closed || z.level == StatelessCompression {
+ return nil
+ }
+ if !z.wroteHeader {
+ z.Write(nil)
+ if z.err != nil {
+ return z.err
+ }
+ }
+ z.err = z.compressor.Flush()
+ return z.err
+}
+
+// Close closes the Writer, flushing any unwritten data to the underlying
+// io.Writer, but does not close the underlying io.Writer.
+func (z *Writer) Close() error {
+ if z.err != nil {
+ return z.err
+ }
+ if z.closed {
+ return nil
+ }
+ z.closed = true
+ if !z.wroteHeader {
+ z.Write(nil)
+ if z.err != nil {
+ return z.err
+ }
+ }
+ if z.level == StatelessCompression {
+ z.err = flate.StatelessDeflate(z.w, nil, true, nil)
+ } else {
+ z.err = z.compressor.Close()
+ }
+ if z.err != nil {
+ return z.err
+ }
+ le.PutUint32(z.buf[:4], z.digest)
+ le.PutUint32(z.buf[4:8], z.size)
+ _, z.err = z.w.Write(z.buf[:8])
+ return z.err
+}
diff --git a/vendor/github.com/klauspost/compress/zlib/reader.go b/vendor/github.com/klauspost/compress/zlib/reader.go
new file mode 100644
index 0000000..f127d47
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/zlib/reader.go
@@ -0,0 +1,183 @@
+// Copyright 2009 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 zlib implements reading and writing of zlib format compressed data,
+as specified in RFC 1950.
+
+The implementation provides filters that uncompress during reading
+and compress during writing. For example, to write compressed data
+to a buffer:
+
+ var b bytes.Buffer
+ w := zlib.NewWriter(&b)
+ w.Write([]byte("hello, world\n"))
+ w.Close()
+
+and to read that data back:
+
+ r, err := zlib.NewReader(&b)
+ io.Copy(os.Stdout, r)
+ r.Close()
+*/
+package zlib
+
+import (
+ "bufio"
+ "compress/zlib"
+ "hash"
+ "hash/adler32"
+ "io"
+
+ "github.com/klauspost/compress/flate"
+)
+
+const zlibDeflate = 8
+
+var (
+ // ErrChecksum is returned when reading ZLIB data that has an invalid checksum.
+ ErrChecksum = zlib.ErrChecksum
+ // ErrDictionary is returned when reading ZLIB data that has an invalid dictionary.
+ ErrDictionary = zlib.ErrDictionary
+ // ErrHeader is returned when reading ZLIB data that has an invalid header.
+ ErrHeader = zlib.ErrHeader
+)
+
+type reader struct {
+ r flate.Reader
+ decompressor io.ReadCloser
+ digest hash.Hash32
+ err error
+ scratch [4]byte
+}
+
+// Resetter resets a ReadCloser returned by NewReader or NewReaderDict to
+// to switch to a new underlying Reader. This permits reusing a ReadCloser
+// instead of allocating a new one.
+type Resetter interface {
+ // Reset discards any buffered data and resets the Resetter as if it was
+ // newly initialized with the given reader.
+ Reset(r io.Reader, dict []byte) error
+}
+
+// NewReader creates a new ReadCloser.
+// Reads from the returned ReadCloser read and decompress data from r.
+// If r does not implement io.ByteReader, the decompressor may read more
+// data than necessary from r.
+// It is the caller's responsibility to call Close on the ReadCloser when done.
+//
+// The ReadCloser returned by NewReader also implements Resetter.
+func NewReader(r io.Reader) (io.ReadCloser, error) {
+ return NewReaderDict(r, nil)
+}
+
+// NewReaderDict is like NewReader but uses a preset dictionary.
+// NewReaderDict ignores the dictionary if the compressed data does not refer to it.
+// If the compressed data refers to a different dictionary, NewReaderDict returns ErrDictionary.
+//
+// The ReadCloser returned by NewReaderDict also implements Resetter.
+func NewReaderDict(r io.Reader, dict []byte) (io.ReadCloser, error) {
+ z := new(reader)
+ err := z.Reset(r, dict)
+ if err != nil {
+ return nil, err
+ }
+ return z, nil
+}
+
+func (z *reader) Read(p []byte) (int, error) {
+ if z.err != nil {
+ return 0, z.err
+ }
+
+ var n int
+ n, z.err = z.decompressor.Read(p)
+ z.digest.Write(p[0:n])
+ if z.err != io.EOF {
+ // In the normal case we return here.
+ return n, z.err
+ }
+
+ // Finished file; check checksum.
+ if _, err := io.ReadFull(z.r, z.scratch[0:4]); err != nil {
+ if err == io.EOF {
+ err = io.ErrUnexpectedEOF
+ }
+ z.err = err
+ return n, z.err
+ }
+ // ZLIB (RFC 1950) is big-endian, unlike GZIP (RFC 1952).
+ checksum := uint32(z.scratch[0])<<24 | uint32(z.scratch[1])<<16 | uint32(z.scratch[2])<<8 | uint32(z.scratch[3])
+ if checksum != z.digest.Sum32() {
+ z.err = ErrChecksum
+ return n, z.err
+ }
+ return n, io.EOF
+}
+
+// Calling Close does not close the wrapped io.Reader originally passed to NewReader.
+// In order for the ZLIB checksum to be verified, the reader must be
+// fully consumed until the io.EOF.
+func (z *reader) Close() error {
+ if z.err != nil && z.err != io.EOF {
+ return z.err
+ }
+ z.err = z.decompressor.Close()
+ return z.err
+}
+
+func (z *reader) Reset(r io.Reader, dict []byte) error {
+ *z = reader{decompressor: z.decompressor, digest: z.digest}
+ if fr, ok := r.(flate.Reader); ok {
+ z.r = fr
+ } else {
+ z.r = bufio.NewReader(r)
+ }
+
+ // Read the header (RFC 1950 section 2.2.).
+ _, z.err = io.ReadFull(z.r, z.scratch[0:2])
+ if z.err != nil {
+ if z.err == io.EOF {
+ z.err = io.ErrUnexpectedEOF
+ }
+ return z.err
+ }
+ h := uint(z.scratch[0])<<8 | uint(z.scratch[1])
+ if (z.scratch[0]&0x0f != zlibDeflate) || (h%31 != 0) {
+ z.err = ErrHeader
+ return z.err
+ }
+ haveDict := z.scratch[1]&0x20 != 0
+ if haveDict {
+ _, z.err = io.ReadFull(z.r, z.scratch[0:4])
+ if z.err != nil {
+ if z.err == io.EOF {
+ z.err = io.ErrUnexpectedEOF
+ }
+ return z.err
+ }
+ checksum := uint32(z.scratch[0])<<24 | uint32(z.scratch[1])<<16 | uint32(z.scratch[2])<<8 | uint32(z.scratch[3])
+ if checksum != adler32.Checksum(dict) {
+ z.err = ErrDictionary
+ return z.err
+ }
+ }
+
+ if z.decompressor == nil {
+ if haveDict {
+ z.decompressor = flate.NewReaderDict(z.r, dict)
+ } else {
+ z.decompressor = flate.NewReader(z.r)
+ }
+ } else {
+ z.decompressor.(flate.Resetter).Reset(z.r, dict)
+ }
+
+ if z.digest != nil {
+ z.digest.Reset()
+ } else {
+ z.digest = adler32.New()
+ }
+ return nil
+}
diff --git a/vendor/github.com/klauspost/compress/zlib/writer.go b/vendor/github.com/klauspost/compress/zlib/writer.go
new file mode 100644
index 0000000..605816b
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/zlib/writer.go
@@ -0,0 +1,201 @@
+// Copyright 2009 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 zlib
+
+import (
+ "fmt"
+ "hash"
+ "hash/adler32"
+ "io"
+
+ "github.com/klauspost/compress/flate"
+)
+
+// These constants are copied from the flate package, so that code that imports
+// "compress/zlib" does not also have to import "compress/flate".
+const (
+ NoCompression = flate.NoCompression
+ BestSpeed = flate.BestSpeed
+ BestCompression = flate.BestCompression
+ DefaultCompression = flate.DefaultCompression
+ ConstantCompression = flate.ConstantCompression
+ HuffmanOnly = flate.HuffmanOnly
+)
+
+// A Writer takes data written to it and writes the compressed
+// form of that data to an underlying writer (see NewWriter).
+type Writer struct {
+ w io.Writer
+ level int
+ dict []byte
+ compressor *flate.Writer
+ digest hash.Hash32
+ err error
+ scratch [4]byte
+ wroteHeader bool
+}
+
+// NewWriter creates a new Writer.
+// Writes to the returned Writer are compressed and written to w.
+//
+// It is the caller's responsibility to call Close on the WriteCloser when done.
+// Writes may be buffered and not flushed until Close.
+func NewWriter(w io.Writer) *Writer {
+ z, _ := NewWriterLevelDict(w, DefaultCompression, nil)
+ return z
+}
+
+// NewWriterLevel is like NewWriter but specifies the compression level instead
+// of assuming DefaultCompression.
+//
+// The compression level can be DefaultCompression, NoCompression, HuffmanOnly
+// or any integer value between BestSpeed and BestCompression inclusive.
+// The error returned will be nil if the level is valid.
+func NewWriterLevel(w io.Writer, level int) (*Writer, error) {
+ return NewWriterLevelDict(w, level, nil)
+}
+
+// NewWriterLevelDict is like NewWriterLevel but specifies a dictionary to
+// compress with.
+//
+// The dictionary may be nil. If not, its contents should not be modified until
+// the Writer is closed.
+func NewWriterLevelDict(w io.Writer, level int, dict []byte) (*Writer, error) {
+ if level < HuffmanOnly || level > BestCompression {
+ return nil, fmt.Errorf("zlib: invalid compression level: %d", level)
+ }
+ return &Writer{
+ w: w,
+ level: level,
+ dict: dict,
+ }, nil
+}
+
+// Reset clears the state of the Writer z such that it is equivalent to its
+// initial state from NewWriterLevel or NewWriterLevelDict, but instead writing
+// to w.
+func (z *Writer) Reset(w io.Writer) {
+ z.w = w
+ // z.level and z.dict left unchanged.
+ if z.compressor != nil {
+ z.compressor.Reset(w)
+ }
+ if z.digest != nil {
+ z.digest.Reset()
+ }
+ z.err = nil
+ z.scratch = [4]byte{}
+ z.wroteHeader = false
+}
+
+// writeHeader writes the ZLIB header.
+func (z *Writer) writeHeader() (err error) {
+ z.wroteHeader = true
+ // ZLIB has a two-byte header (as documented in RFC 1950).
+ // The first four bits is the CINFO (compression info), which is 7 for the default deflate window size.
+ // The next four bits is the CM (compression method), which is 8 for deflate.
+ z.scratch[0] = 0x78
+ // The next two bits is the FLEVEL (compression level). The four values are:
+ // 0=fastest, 1=fast, 2=default, 3=best.
+ // The next bit, FDICT, is set if a dictionary is given.
+ // The final five FCHECK bits form a mod-31 checksum.
+ switch z.level {
+ case -2, 0, 1:
+ z.scratch[1] = 0 << 6
+ case 2, 3, 4, 5:
+ z.scratch[1] = 1 << 6
+ case 6, -1:
+ z.scratch[1] = 2 << 6
+ case 7, 8, 9:
+ z.scratch[1] = 3 << 6
+ default:
+ panic("unreachable")
+ }
+ if z.dict != nil {
+ z.scratch[1] |= 1 << 5
+ }
+ z.scratch[1] += uint8(31 - (uint16(z.scratch[0])<<8+uint16(z.scratch[1]))%31)
+ if _, err = z.w.Write(z.scratch[0:2]); err != nil {
+ return err
+ }
+ if z.dict != nil {
+ // The next four bytes are the Adler-32 checksum of the dictionary.
+ checksum := adler32.Checksum(z.dict)
+ z.scratch[0] = uint8(checksum >> 24)
+ z.scratch[1] = uint8(checksum >> 16)
+ z.scratch[2] = uint8(checksum >> 8)
+ z.scratch[3] = uint8(checksum >> 0)
+ if _, err = z.w.Write(z.scratch[0:4]); err != nil {
+ return err
+ }
+ }
+ if z.compressor == nil {
+ // Initialize deflater unless the Writer is being reused
+ // after a Reset call.
+ z.compressor, err = flate.NewWriterDict(z.w, z.level, z.dict)
+ if err != nil {
+ return err
+ }
+ z.digest = adler32.New()
+ }
+ return nil
+}
+
+// Write writes a compressed form of p to the underlying io.Writer. The
+// compressed bytes are not necessarily flushed until the Writer is closed or
+// explicitly flushed.
+func (z *Writer) Write(p []byte) (n int, err error) {
+ if !z.wroteHeader {
+ z.err = z.writeHeader()
+ }
+ if z.err != nil {
+ return 0, z.err
+ }
+ if len(p) == 0 {
+ return 0, nil
+ }
+ n, err = z.compressor.Write(p)
+ if err != nil {
+ z.err = err
+ return
+ }
+ z.digest.Write(p)
+ return
+}
+
+// Flush flushes the Writer to its underlying io.Writer.
+func (z *Writer) Flush() error {
+ if !z.wroteHeader {
+ z.err = z.writeHeader()
+ }
+ if z.err != nil {
+ return z.err
+ }
+ z.err = z.compressor.Flush()
+ return z.err
+}
+
+// Close closes the Writer, flushing any unwritten data to the underlying
+// io.Writer, but does not close the underlying io.Writer.
+func (z *Writer) Close() error {
+ if !z.wroteHeader {
+ z.err = z.writeHeader()
+ }
+ if z.err != nil {
+ return z.err
+ }
+ z.err = z.compressor.Close()
+ if z.err != nil {
+ return z.err
+ }
+ checksum := z.digest.Sum32()
+ // ZLIB (RFC 1950) is big-endian, unlike GZIP (RFC 1952).
+ z.scratch[0] = uint8(checksum >> 24)
+ z.scratch[1] = uint8(checksum >> 16)
+ z.scratch[2] = uint8(checksum >> 8)
+ z.scratch[3] = uint8(checksum >> 0)
+ _, z.err = z.w.Write(z.scratch[0:4])
+ return z.err
+}
diff --git a/vendor/github.com/lib/pq/.gitignore b/vendor/github.com/lib/pq/.gitignore
new file mode 100644
index 0000000..3243952
--- /dev/null
+++ b/vendor/github.com/lib/pq/.gitignore
@@ -0,0 +1,6 @@
+.db
+*.test
+*~
+*.swp
+.idea
+.vscode
\ No newline at end of file
diff --git a/vendor/github.com/lib/pq/LICENSE.md b/vendor/github.com/lib/pq/LICENSE.md
new file mode 100644
index 0000000..5773904
--- /dev/null
+++ b/vendor/github.com/lib/pq/LICENSE.md
@@ -0,0 +1,8 @@
+Copyright (c) 2011-2013, 'pq' Contributors
+Portions Copyright (C) 2011 Blake Mizerany
+
+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/lib/pq/README.md b/vendor/github.com/lib/pq/README.md
new file mode 100644
index 0000000..126ee5d
--- /dev/null
+++ b/vendor/github.com/lib/pq/README.md
@@ -0,0 +1,36 @@
+# pq - A pure Go postgres driver for Go's database/sql package
+
+[![GoDoc](https://godoc.org/github.com/lib/pq?status.svg)](https://pkg.go.dev/github.com/lib/pq?tab=doc)
+
+## Install
+
+ go get github.com/lib/pq
+
+## Features
+
+* SSL
+* Handles bad connections for `database/sql`
+* Scan `time.Time` correctly (i.e. `timestamp[tz]`, `time[tz]`, `date`)
+* Scan binary blobs correctly (i.e. `bytea`)
+* Package for `hstore` support
+* COPY FROM support
+* pq.ParseURL for converting urls to connection strings for sql.Open.
+* Many libpq compatible environment variables
+* Unix socket support
+* Notifications: `LISTEN`/`NOTIFY`
+* pgpass support
+* GSS (Kerberos) auth
+
+## Tests
+
+`go test` is used for testing. See [TESTS.md](TESTS.md) for more details.
+
+## Status
+
+This package is currently in maintenance mode, which means:
+1. It generally does not accept new features.
+2. It does accept bug fixes and version compatability changes provided by the community.
+3. Maintainers usually do not resolve reported issues.
+4. Community members are encouraged to help each other with reported issues.
+
+For users that require new features or reliable resolution of reported bugs, we recommend using [pgx](https://github.com/jackc/pgx) which is under active development.
diff --git a/vendor/github.com/lib/pq/TESTS.md b/vendor/github.com/lib/pq/TESTS.md
new file mode 100644
index 0000000..f050211
--- /dev/null
+++ b/vendor/github.com/lib/pq/TESTS.md
@@ -0,0 +1,33 @@
+# Tests
+
+## Running Tests
+
+`go test` is used for testing. A running PostgreSQL
+server is required, with the ability to log in. The
+database to connect to test with is "pqgotest," on
+"localhost" but these can be overridden using [environment
+variables](https://www.postgresql.org/docs/9.3/static/libpq-envars.html).
+
+Example:
+
+ PGHOST=/run/postgresql go test
+
+## Benchmarks
+
+A benchmark suite can be run as part of the tests:
+
+ go test -bench .
+
+## Example setup (Docker)
+
+Run a postgres container:
+
+```
+docker run --expose 5432:5432 postgres
+```
+
+Run tests:
+
+```
+PGHOST=localhost PGPORT=5432 PGUSER=postgres PGSSLMODE=disable PGDATABASE=postgres go test
+```
diff --git a/vendor/github.com/lib/pq/array.go b/vendor/github.com/lib/pq/array.go
new file mode 100644
index 0000000..39c8f7e
--- /dev/null
+++ b/vendor/github.com/lib/pq/array.go
@@ -0,0 +1,895 @@
+package pq
+
+import (
+ "bytes"
+ "database/sql"
+ "database/sql/driver"
+ "encoding/hex"
+ "fmt"
+ "reflect"
+ "strconv"
+ "strings"
+)
+
+var typeByteSlice = reflect.TypeOf([]byte{})
+var typeDriverValuer = reflect.TypeOf((*driver.Valuer)(nil)).Elem()
+var typeSQLScanner = reflect.TypeOf((*sql.Scanner)(nil)).Elem()
+
+// Array returns the optimal driver.Valuer and sql.Scanner for an array or
+// slice of any dimension.
+//
+// For example:
+// db.Query(`SELECT * FROM t WHERE id = ANY($1)`, pq.Array([]int{235, 401}))
+//
+// var x []sql.NullInt64
+// db.QueryRow(`SELECT ARRAY[235, 401]`).Scan(pq.Array(&x))
+//
+// Scanning multi-dimensional arrays is not supported. Arrays where the lower
+// bound is not one (such as `[0:0]={1}') are not supported.
+func Array(a interface{}) interface {
+ driver.Valuer
+ sql.Scanner
+} {
+ switch a := a.(type) {
+ case []bool:
+ return (*BoolArray)(&a)
+ case []float64:
+ return (*Float64Array)(&a)
+ case []float32:
+ return (*Float32Array)(&a)
+ case []int64:
+ return (*Int64Array)(&a)
+ case []int32:
+ return (*Int32Array)(&a)
+ case []string:
+ return (*StringArray)(&a)
+ case [][]byte:
+ return (*ByteaArray)(&a)
+
+ case *[]bool:
+ return (*BoolArray)(a)
+ case *[]float64:
+ return (*Float64Array)(a)
+ case *[]float32:
+ return (*Float32Array)(a)
+ case *[]int64:
+ return (*Int64Array)(a)
+ case *[]int32:
+ return (*Int32Array)(a)
+ case *[]string:
+ return (*StringArray)(a)
+ case *[][]byte:
+ return (*ByteaArray)(a)
+ }
+
+ return GenericArray{a}
+}
+
+// ArrayDelimiter may be optionally implemented by driver.Valuer or sql.Scanner
+// to override the array delimiter used by GenericArray.
+type ArrayDelimiter interface {
+ // ArrayDelimiter returns the delimiter character(s) for this element's type.
+ ArrayDelimiter() string
+}
+
+// BoolArray represents a one-dimensional array of the PostgreSQL boolean type.
+type BoolArray []bool
+
+// Scan implements the sql.Scanner interface.
+func (a *BoolArray) Scan(src interface{}) error {
+ switch src := src.(type) {
+ case []byte:
+ return a.scanBytes(src)
+ case string:
+ return a.scanBytes([]byte(src))
+ case nil:
+ *a = nil
+ return nil
+ }
+
+ return fmt.Errorf("pq: cannot convert %T to BoolArray", src)
+}
+
+func (a *BoolArray) scanBytes(src []byte) error {
+ elems, err := scanLinearArray(src, []byte{','}, "BoolArray")
+ if err != nil {
+ return err
+ }
+ if *a != nil && len(elems) == 0 {
+ *a = (*a)[:0]
+ } else {
+ b := make(BoolArray, len(elems))
+ for i, v := range elems {
+ if len(v) != 1 {
+ return fmt.Errorf("pq: could not parse boolean array index %d: invalid boolean %q", i, v)
+ }
+ switch v[0] {
+ case 't':
+ b[i] = true
+ case 'f':
+ b[i] = false
+ default:
+ return fmt.Errorf("pq: could not parse boolean array index %d: invalid boolean %q", i, v)
+ }
+ }
+ *a = b
+ }
+ return nil
+}
+
+// Value implements the driver.Valuer interface.
+func (a BoolArray) Value() (driver.Value, error) {
+ if a == nil {
+ return nil, nil
+ }
+
+ if n := len(a); n > 0 {
+ // There will be exactly two curly brackets, N bytes of values,
+ // and N-1 bytes of delimiters.
+ b := make([]byte, 1+2*n)
+
+ for i := 0; i < n; i++ {
+ b[2*i] = ','
+ if a[i] {
+ b[1+2*i] = 't'
+ } else {
+ b[1+2*i] = 'f'
+ }
+ }
+
+ b[0] = '{'
+ b[2*n] = '}'
+
+ return string(b), nil
+ }
+
+ return "{}", nil
+}
+
+// ByteaArray represents a one-dimensional array of the PostgreSQL bytea type.
+type ByteaArray [][]byte
+
+// Scan implements the sql.Scanner interface.
+func (a *ByteaArray) Scan(src interface{}) error {
+ switch src := src.(type) {
+ case []byte:
+ return a.scanBytes(src)
+ case string:
+ return a.scanBytes([]byte(src))
+ case nil:
+ *a = nil
+ return nil
+ }
+
+ return fmt.Errorf("pq: cannot convert %T to ByteaArray", src)
+}
+
+func (a *ByteaArray) scanBytes(src []byte) error {
+ elems, err := scanLinearArray(src, []byte{','}, "ByteaArray")
+ if err != nil {
+ return err
+ }
+ if *a != nil && len(elems) == 0 {
+ *a = (*a)[:0]
+ } else {
+ b := make(ByteaArray, len(elems))
+ for i, v := range elems {
+ b[i], err = parseBytea(v)
+ if err != nil {
+ return fmt.Errorf("could not parse bytea array index %d: %s", i, err.Error())
+ }
+ }
+ *a = b
+ }
+ return nil
+}
+
+// Value implements the driver.Valuer interface. It uses the "hex" format which
+// is only supported on PostgreSQL 9.0 or newer.
+func (a ByteaArray) Value() (driver.Value, error) {
+ if a == nil {
+ return nil, nil
+ }
+
+ if n := len(a); n > 0 {
+ // There will be at least two curly brackets, 2*N bytes of quotes,
+ // 3*N bytes of hex formatting, and N-1 bytes of delimiters.
+ size := 1 + 6*n
+ for _, x := range a {
+ size += hex.EncodedLen(len(x))
+ }
+
+ b := make([]byte, size)
+
+ for i, s := 0, b; i < n; i++ {
+ o := copy(s, `,"\\x`)
+ o += hex.Encode(s[o:], a[i])
+ s[o] = '"'
+ s = s[o+1:]
+ }
+
+ b[0] = '{'
+ b[size-1] = '}'
+
+ return string(b), nil
+ }
+
+ return "{}", nil
+}
+
+// Float64Array represents a one-dimensional array of the PostgreSQL double
+// precision type.
+type Float64Array []float64
+
+// Scan implements the sql.Scanner interface.
+func (a *Float64Array) Scan(src interface{}) error {
+ switch src := src.(type) {
+ case []byte:
+ return a.scanBytes(src)
+ case string:
+ return a.scanBytes([]byte(src))
+ case nil:
+ *a = nil
+ return nil
+ }
+
+ return fmt.Errorf("pq: cannot convert %T to Float64Array", src)
+}
+
+func (a *Float64Array) scanBytes(src []byte) error {
+ elems, err := scanLinearArray(src, []byte{','}, "Float64Array")
+ if err != nil {
+ return err
+ }
+ if *a != nil && len(elems) == 0 {
+ *a = (*a)[:0]
+ } else {
+ b := make(Float64Array, len(elems))
+ for i, v := range elems {
+ if b[i], err = strconv.ParseFloat(string(v), 64); err != nil {
+ return fmt.Errorf("pq: parsing array element index %d: %v", i, err)
+ }
+ }
+ *a = b
+ }
+ return nil
+}
+
+// Value implements the driver.Valuer interface.
+func (a Float64Array) Value() (driver.Value, error) {
+ if a == nil {
+ return nil, nil
+ }
+
+ if n := len(a); n > 0 {
+ // There will be at least two curly brackets, N bytes of values,
+ // and N-1 bytes of delimiters.
+ b := make([]byte, 1, 1+2*n)
+ b[0] = '{'
+
+ b = strconv.AppendFloat(b, a[0], 'f', -1, 64)
+ for i := 1; i < n; i++ {
+ b = append(b, ',')
+ b = strconv.AppendFloat(b, a[i], 'f', -1, 64)
+ }
+
+ return string(append(b, '}')), nil
+ }
+
+ return "{}", nil
+}
+
+// Float32Array represents a one-dimensional array of the PostgreSQL double
+// precision type.
+type Float32Array []float32
+
+// Scan implements the sql.Scanner interface.
+func (a *Float32Array) Scan(src interface{}) error {
+ switch src := src.(type) {
+ case []byte:
+ return a.scanBytes(src)
+ case string:
+ return a.scanBytes([]byte(src))
+ case nil:
+ *a = nil
+ return nil
+ }
+
+ return fmt.Errorf("pq: cannot convert %T to Float32Array", src)
+}
+
+func (a *Float32Array) scanBytes(src []byte) error {
+ elems, err := scanLinearArray(src, []byte{','}, "Float32Array")
+ if err != nil {
+ return err
+ }
+ if *a != nil && len(elems) == 0 {
+ *a = (*a)[:0]
+ } else {
+ b := make(Float32Array, len(elems))
+ for i, v := range elems {
+ var x float64
+ if x, err = strconv.ParseFloat(string(v), 32); err != nil {
+ return fmt.Errorf("pq: parsing array element index %d: %v", i, err)
+ }
+ b[i] = float32(x)
+ }
+ *a = b
+ }
+ return nil
+}
+
+// Value implements the driver.Valuer interface.
+func (a Float32Array) Value() (driver.Value, error) {
+ if a == nil {
+ return nil, nil
+ }
+
+ if n := len(a); n > 0 {
+ // There will be at least two curly brackets, N bytes of values,
+ // and N-1 bytes of delimiters.
+ b := make([]byte, 1, 1+2*n)
+ b[0] = '{'
+
+ b = strconv.AppendFloat(b, float64(a[0]), 'f', -1, 32)
+ for i := 1; i < n; i++ {
+ b = append(b, ',')
+ b = strconv.AppendFloat(b, float64(a[i]), 'f', -1, 32)
+ }
+
+ return string(append(b, '}')), nil
+ }
+
+ return "{}", nil
+}
+
+// GenericArray implements the driver.Valuer and sql.Scanner interfaces for
+// an array or slice of any dimension.
+type GenericArray struct{ A interface{} }
+
+func (GenericArray) evaluateDestination(rt reflect.Type) (reflect.Type, func([]byte, reflect.Value) error, string) {
+ var assign func([]byte, reflect.Value) error
+ var del = ","
+
+ // TODO calculate the assign function for other types
+ // TODO repeat this section on the element type of arrays or slices (multidimensional)
+ {
+ if reflect.PtrTo(rt).Implements(typeSQLScanner) {
+ // dest is always addressable because it is an element of a slice.
+ assign = func(src []byte, dest reflect.Value) (err error) {
+ ss := dest.Addr().Interface().(sql.Scanner)
+ if src == nil {
+ err = ss.Scan(nil)
+ } else {
+ err = ss.Scan(src)
+ }
+ return
+ }
+ goto FoundType
+ }
+
+ assign = func([]byte, reflect.Value) error {
+ return fmt.Errorf("pq: scanning to %s is not implemented; only sql.Scanner", rt)
+ }
+ }
+
+FoundType:
+
+ if ad, ok := reflect.Zero(rt).Interface().(ArrayDelimiter); ok {
+ del = ad.ArrayDelimiter()
+ }
+
+ return rt, assign, del
+}
+
+// Scan implements the sql.Scanner interface.
+func (a GenericArray) Scan(src interface{}) error {
+ dpv := reflect.ValueOf(a.A)
+ switch {
+ case dpv.Kind() != reflect.Ptr:
+ return fmt.Errorf("pq: destination %T is not a pointer to array or slice", a.A)
+ case dpv.IsNil():
+ return fmt.Errorf("pq: destination %T is nil", a.A)
+ }
+
+ dv := dpv.Elem()
+ switch dv.Kind() {
+ case reflect.Slice:
+ case reflect.Array:
+ default:
+ return fmt.Errorf("pq: destination %T is not a pointer to array or slice", a.A)
+ }
+
+ switch src := src.(type) {
+ case []byte:
+ return a.scanBytes(src, dv)
+ case string:
+ return a.scanBytes([]byte(src), dv)
+ case nil:
+ if dv.Kind() == reflect.Slice {
+ dv.Set(reflect.Zero(dv.Type()))
+ return nil
+ }
+ }
+
+ return fmt.Errorf("pq: cannot convert %T to %s", src, dv.Type())
+}
+
+func (a GenericArray) scanBytes(src []byte, dv reflect.Value) error {
+ dtype, assign, del := a.evaluateDestination(dv.Type().Elem())
+ dims, elems, err := parseArray(src, []byte(del))
+ if err != nil {
+ return err
+ }
+
+ // TODO allow multidimensional
+
+ if len(dims) > 1 {
+ return fmt.Errorf("pq: scanning from multidimensional ARRAY%s is not implemented",
+ strings.Replace(fmt.Sprint(dims), " ", "][", -1))
+ }
+
+ // Treat a zero-dimensional array like an array with a single dimension of zero.
+ if len(dims) == 0 {
+ dims = append(dims, 0)
+ }
+
+ for i, rt := 0, dv.Type(); i < len(dims); i, rt = i+1, rt.Elem() {
+ switch rt.Kind() {
+ case reflect.Slice:
+ case reflect.Array:
+ if rt.Len() != dims[i] {
+ return fmt.Errorf("pq: cannot convert ARRAY%s to %s",
+ strings.Replace(fmt.Sprint(dims), " ", "][", -1), dv.Type())
+ }
+ default:
+ // TODO handle multidimensional
+ }
+ }
+
+ values := reflect.MakeSlice(reflect.SliceOf(dtype), len(elems), len(elems))
+ for i, e := range elems {
+ if err := assign(e, values.Index(i)); err != nil {
+ return fmt.Errorf("pq: parsing array element index %d: %v", i, err)
+ }
+ }
+
+ // TODO handle multidimensional
+
+ switch dv.Kind() {
+ case reflect.Slice:
+ dv.Set(values.Slice(0, dims[0]))
+ case reflect.Array:
+ for i := 0; i < dims[0]; i++ {
+ dv.Index(i).Set(values.Index(i))
+ }
+ }
+
+ return nil
+}
+
+// Value implements the driver.Valuer interface.
+func (a GenericArray) Value() (driver.Value, error) {
+ if a.A == nil {
+ return nil, nil
+ }
+
+ rv := reflect.ValueOf(a.A)
+
+ switch rv.Kind() {
+ case reflect.Slice:
+ if rv.IsNil() {
+ return nil, nil
+ }
+ case reflect.Array:
+ default:
+ return nil, fmt.Errorf("pq: Unable to convert %T to array", a.A)
+ }
+
+ if n := rv.Len(); n > 0 {
+ // There will be at least two curly brackets, N bytes of values,
+ // and N-1 bytes of delimiters.
+ b := make([]byte, 0, 1+2*n)
+
+ b, _, err := appendArray(b, rv, n)
+ return string(b), err
+ }
+
+ return "{}", nil
+}
+
+// Int64Array represents a one-dimensional array of the PostgreSQL integer types.
+type Int64Array []int64
+
+// Scan implements the sql.Scanner interface.
+func (a *Int64Array) Scan(src interface{}) error {
+ switch src := src.(type) {
+ case []byte:
+ return a.scanBytes(src)
+ case string:
+ return a.scanBytes([]byte(src))
+ case nil:
+ *a = nil
+ return nil
+ }
+
+ return fmt.Errorf("pq: cannot convert %T to Int64Array", src)
+}
+
+func (a *Int64Array) scanBytes(src []byte) error {
+ elems, err := scanLinearArray(src, []byte{','}, "Int64Array")
+ if err != nil {
+ return err
+ }
+ if *a != nil && len(elems) == 0 {
+ *a = (*a)[:0]
+ } else {
+ b := make(Int64Array, len(elems))
+ for i, v := range elems {
+ if b[i], err = strconv.ParseInt(string(v), 10, 64); err != nil {
+ return fmt.Errorf("pq: parsing array element index %d: %v", i, err)
+ }
+ }
+ *a = b
+ }
+ return nil
+}
+
+// Value implements the driver.Valuer interface.
+func (a Int64Array) Value() (driver.Value, error) {
+ if a == nil {
+ return nil, nil
+ }
+
+ if n := len(a); n > 0 {
+ // There will be at least two curly brackets, N bytes of values,
+ // and N-1 bytes of delimiters.
+ b := make([]byte, 1, 1+2*n)
+ b[0] = '{'
+
+ b = strconv.AppendInt(b, a[0], 10)
+ for i := 1; i < n; i++ {
+ b = append(b, ',')
+ b = strconv.AppendInt(b, a[i], 10)
+ }
+
+ return string(append(b, '}')), nil
+ }
+
+ return "{}", nil
+}
+
+// Int32Array represents a one-dimensional array of the PostgreSQL integer types.
+type Int32Array []int32
+
+// Scan implements the sql.Scanner interface.
+func (a *Int32Array) Scan(src interface{}) error {
+ switch src := src.(type) {
+ case []byte:
+ return a.scanBytes(src)
+ case string:
+ return a.scanBytes([]byte(src))
+ case nil:
+ *a = nil
+ return nil
+ }
+
+ return fmt.Errorf("pq: cannot convert %T to Int32Array", src)
+}
+
+func (a *Int32Array) scanBytes(src []byte) error {
+ elems, err := scanLinearArray(src, []byte{','}, "Int32Array")
+ if err != nil {
+ return err
+ }
+ if *a != nil && len(elems) == 0 {
+ *a = (*a)[:0]
+ } else {
+ b := make(Int32Array, len(elems))
+ for i, v := range elems {
+ x, err := strconv.ParseInt(string(v), 10, 32)
+ if err != nil {
+ return fmt.Errorf("pq: parsing array element index %d: %v", i, err)
+ }
+ b[i] = int32(x)
+ }
+ *a = b
+ }
+ return nil
+}
+
+// Value implements the driver.Valuer interface.
+func (a Int32Array) Value() (driver.Value, error) {
+ if a == nil {
+ return nil, nil
+ }
+
+ if n := len(a); n > 0 {
+ // There will be at least two curly brackets, N bytes of values,
+ // and N-1 bytes of delimiters.
+ b := make([]byte, 1, 1+2*n)
+ b[0] = '{'
+
+ b = strconv.AppendInt(b, int64(a[0]), 10)
+ for i := 1; i < n; i++ {
+ b = append(b, ',')
+ b = strconv.AppendInt(b, int64(a[i]), 10)
+ }
+
+ return string(append(b, '}')), nil
+ }
+
+ return "{}", nil
+}
+
+// StringArray represents a one-dimensional array of the PostgreSQL character types.
+type StringArray []string
+
+// Scan implements the sql.Scanner interface.
+func (a *StringArray) Scan(src interface{}) error {
+ switch src := src.(type) {
+ case []byte:
+ return a.scanBytes(src)
+ case string:
+ return a.scanBytes([]byte(src))
+ case nil:
+ *a = nil
+ return nil
+ }
+
+ return fmt.Errorf("pq: cannot convert %T to StringArray", src)
+}
+
+func (a *StringArray) scanBytes(src []byte) error {
+ elems, err := scanLinearArray(src, []byte{','}, "StringArray")
+ if err != nil {
+ return err
+ }
+ if *a != nil && len(elems) == 0 {
+ *a = (*a)[:0]
+ } else {
+ b := make(StringArray, len(elems))
+ for i, v := range elems {
+ if b[i] = string(v); v == nil {
+ return fmt.Errorf("pq: parsing array element index %d: cannot convert nil to string", i)
+ }
+ }
+ *a = b
+ }
+ return nil
+}
+
+// Value implements the driver.Valuer interface.
+func (a StringArray) Value() (driver.Value, error) {
+ if a == nil {
+ return nil, nil
+ }
+
+ if n := len(a); n > 0 {
+ // There will be at least two curly brackets, 2*N bytes of quotes,
+ // and N-1 bytes of delimiters.
+ b := make([]byte, 1, 1+3*n)
+ b[0] = '{'
+
+ b = appendArrayQuotedBytes(b, []byte(a[0]))
+ for i := 1; i < n; i++ {
+ b = append(b, ',')
+ b = appendArrayQuotedBytes(b, []byte(a[i]))
+ }
+
+ return string(append(b, '}')), nil
+ }
+
+ return "{}", nil
+}
+
+// appendArray appends rv to the buffer, returning the extended buffer and
+// the delimiter used between elements.
+//
+// It panics when n <= 0 or rv's Kind is not reflect.Array nor reflect.Slice.
+func appendArray(b []byte, rv reflect.Value, n int) ([]byte, string, error) {
+ var del string
+ var err error
+
+ b = append(b, '{')
+
+ if b, del, err = appendArrayElement(b, rv.Index(0)); err != nil {
+ return b, del, err
+ }
+
+ for i := 1; i < n; i++ {
+ b = append(b, del...)
+ if b, del, err = appendArrayElement(b, rv.Index(i)); err != nil {
+ return b, del, err
+ }
+ }
+
+ return append(b, '}'), del, nil
+}
+
+// appendArrayElement appends rv to the buffer, returning the extended buffer
+// and the delimiter to use before the next element.
+//
+// When rv's Kind is neither reflect.Array nor reflect.Slice, it is converted
+// using driver.DefaultParameterConverter and the resulting []byte or string
+// is double-quoted.
+//
+// See http://www.postgresql.org/docs/current/static/arrays.html#ARRAYS-IO
+func appendArrayElement(b []byte, rv reflect.Value) ([]byte, string, error) {
+ if k := rv.Kind(); k == reflect.Array || k == reflect.Slice {
+ if t := rv.Type(); t != typeByteSlice && !t.Implements(typeDriverValuer) {
+ if n := rv.Len(); n > 0 {
+ return appendArray(b, rv, n)
+ }
+
+ return b, "", nil
+ }
+ }
+
+ var del = ","
+ var err error
+ var iv interface{} = rv.Interface()
+
+ if ad, ok := iv.(ArrayDelimiter); ok {
+ del = ad.ArrayDelimiter()
+ }
+
+ if iv, err = driver.DefaultParameterConverter.ConvertValue(iv); err != nil {
+ return b, del, err
+ }
+
+ switch v := iv.(type) {
+ case nil:
+ return append(b, "NULL"...), del, nil
+ case []byte:
+ return appendArrayQuotedBytes(b, v), del, nil
+ case string:
+ return appendArrayQuotedBytes(b, []byte(v)), del, nil
+ }
+
+ b, err = appendValue(b, iv)
+ return b, del, err
+}
+
+func appendArrayQuotedBytes(b, v []byte) []byte {
+ b = append(b, '"')
+ for {
+ i := bytes.IndexAny(v, `"\`)
+ if i < 0 {
+ b = append(b, v...)
+ break
+ }
+ if i > 0 {
+ b = append(b, v[:i]...)
+ }
+ b = append(b, '\\', v[i])
+ v = v[i+1:]
+ }
+ return append(b, '"')
+}
+
+func appendValue(b []byte, v driver.Value) ([]byte, error) {
+ return append(b, encode(nil, v, 0)...), nil
+}
+
+// parseArray extracts the dimensions and elements of an array represented in
+// text format. Only representations emitted by the backend are supported.
+// Notably, whitespace around brackets and delimiters is significant, and NULL
+// is case-sensitive.
+//
+// See http://www.postgresql.org/docs/current/static/arrays.html#ARRAYS-IO
+func parseArray(src, del []byte) (dims []int, elems [][]byte, err error) {
+ var depth, i int
+
+ if len(src) < 1 || src[0] != '{' {
+ return nil, nil, fmt.Errorf("pq: unable to parse array; expected %q at offset %d", '{', 0)
+ }
+
+Open:
+ for i < len(src) {
+ switch src[i] {
+ case '{':
+ depth++
+ i++
+ case '}':
+ elems = make([][]byte, 0)
+ goto Close
+ default:
+ break Open
+ }
+ }
+ dims = make([]int, i)
+
+Element:
+ for i < len(src) {
+ switch src[i] {
+ case '{':
+ if depth == len(dims) {
+ break Element
+ }
+ depth++
+ dims[depth-1] = 0
+ i++
+ case '"':
+ var elem = []byte{}
+ var escape bool
+ for i++; i < len(src); i++ {
+ if escape {
+ elem = append(elem, src[i])
+ escape = false
+ } else {
+ switch src[i] {
+ default:
+ elem = append(elem, src[i])
+ case '\\':
+ escape = true
+ case '"':
+ elems = append(elems, elem)
+ i++
+ break Element
+ }
+ }
+ }
+ default:
+ for start := i; i < len(src); i++ {
+ if bytes.HasPrefix(src[i:], del) || src[i] == '}' {
+ elem := src[start:i]
+ if len(elem) == 0 {
+ return nil, nil, fmt.Errorf("pq: unable to parse array; unexpected %q at offset %d", src[i], i)
+ }
+ if bytes.Equal(elem, []byte("NULL")) {
+ elem = nil
+ }
+ elems = append(elems, elem)
+ break Element
+ }
+ }
+ }
+ }
+
+ for i < len(src) {
+ if bytes.HasPrefix(src[i:], del) && depth > 0 {
+ dims[depth-1]++
+ i += len(del)
+ goto Element
+ } else if src[i] == '}' && depth > 0 {
+ dims[depth-1]++
+ depth--
+ i++
+ } else {
+ return nil, nil, fmt.Errorf("pq: unable to parse array; unexpected %q at offset %d", src[i], i)
+ }
+ }
+
+Close:
+ for i < len(src) {
+ if src[i] == '}' && depth > 0 {
+ depth--
+ i++
+ } else {
+ return nil, nil, fmt.Errorf("pq: unable to parse array; unexpected %q at offset %d", src[i], i)
+ }
+ }
+ if depth > 0 {
+ err = fmt.Errorf("pq: unable to parse array; expected %q at offset %d", '}', i)
+ }
+ if err == nil {
+ for _, d := range dims {
+ if (len(elems) % d) != 0 {
+ err = fmt.Errorf("pq: multidimensional arrays must have elements with matching dimensions")
+ }
+ }
+ }
+ return
+}
+
+func scanLinearArray(src, del []byte, typ string) (elems [][]byte, err error) {
+ dims, elems, err := parseArray(src, del)
+ if err != nil {
+ return nil, err
+ }
+ if len(dims) > 1 {
+ return nil, fmt.Errorf("pq: cannot convert ARRAY%s to %s", strings.Replace(fmt.Sprint(dims), " ", "][", -1), typ)
+ }
+ return elems, err
+}
diff --git a/vendor/github.com/lib/pq/buf.go b/vendor/github.com/lib/pq/buf.go
new file mode 100644
index 0000000..4b0a0a8
--- /dev/null
+++ b/vendor/github.com/lib/pq/buf.go
@@ -0,0 +1,91 @@
+package pq
+
+import (
+ "bytes"
+ "encoding/binary"
+
+ "github.com/lib/pq/oid"
+)
+
+type readBuf []byte
+
+func (b *readBuf) int32() (n int) {
+ n = int(int32(binary.BigEndian.Uint32(*b)))
+ *b = (*b)[4:]
+ return
+}
+
+func (b *readBuf) oid() (n oid.Oid) {
+ n = oid.Oid(binary.BigEndian.Uint32(*b))
+ *b = (*b)[4:]
+ return
+}
+
+// N.B: this is actually an unsigned 16-bit integer, unlike int32
+func (b *readBuf) int16() (n int) {
+ n = int(binary.BigEndian.Uint16(*b))
+ *b = (*b)[2:]
+ return
+}
+
+func (b *readBuf) string() string {
+ i := bytes.IndexByte(*b, 0)
+ if i < 0 {
+ errorf("invalid message format; expected string terminator")
+ }
+ s := (*b)[:i]
+ *b = (*b)[i+1:]
+ return string(s)
+}
+
+func (b *readBuf) next(n int) (v []byte) {
+ v = (*b)[:n]
+ *b = (*b)[n:]
+ return
+}
+
+func (b *readBuf) byte() byte {
+ return b.next(1)[0]
+}
+
+type writeBuf struct {
+ buf []byte
+ pos int
+}
+
+func (b *writeBuf) int32(n int) {
+ x := make([]byte, 4)
+ binary.BigEndian.PutUint32(x, uint32(n))
+ b.buf = append(b.buf, x...)
+}
+
+func (b *writeBuf) int16(n int) {
+ x := make([]byte, 2)
+ binary.BigEndian.PutUint16(x, uint16(n))
+ b.buf = append(b.buf, x...)
+}
+
+func (b *writeBuf) string(s string) {
+ b.buf = append(append(b.buf, s...), '\000')
+}
+
+func (b *writeBuf) byte(c byte) {
+ b.buf = append(b.buf, c)
+}
+
+func (b *writeBuf) bytes(v []byte) {
+ b.buf = append(b.buf, v...)
+}
+
+func (b *writeBuf) wrap() []byte {
+ p := b.buf[b.pos:]
+ binary.BigEndian.PutUint32(p, uint32(len(p)))
+ return b.buf
+}
+
+func (b *writeBuf) next(c byte) {
+ p := b.buf[b.pos:]
+ binary.BigEndian.PutUint32(p, uint32(len(p)))
+ b.pos = len(b.buf) + 1
+ b.buf = append(b.buf, c, 0, 0, 0, 0)
+}
diff --git a/vendor/github.com/lib/pq/conn.go b/vendor/github.com/lib/pq/conn.go
new file mode 100644
index 0000000..da4ff9d
--- /dev/null
+++ b/vendor/github.com/lib/pq/conn.go
@@ -0,0 +1,2112 @@
+package pq
+
+import (
+ "bufio"
+ "bytes"
+ "context"
+ "crypto/md5"
+ "crypto/sha256"
+ "database/sql"
+ "database/sql/driver"
+ "encoding/binary"
+ "errors"
+ "fmt"
+ "io"
+ "net"
+ "os"
+ "os/user"
+ "path"
+ "path/filepath"
+ "strconv"
+ "strings"
+ "sync"
+ "time"
+ "unicode"
+
+ "github.com/lib/pq/oid"
+ "github.com/lib/pq/scram"
+)
+
+// Common error types
+var (
+ ErrNotSupported = errors.New("pq: Unsupported command")
+ ErrInFailedTransaction = errors.New("pq: Could not complete operation in a failed transaction")
+ ErrSSLNotSupported = errors.New("pq: SSL is not enabled on the server")
+ ErrSSLKeyUnknownOwnership = errors.New("pq: Could not get owner information for private key, may not be properly protected")
+ ErrSSLKeyHasWorldPermissions = errors.New("pq: Private key has world access. Permissions should be u=rw,g=r (0640) if owned by root, or u=rw (0600), or less")
+
+ ErrCouldNotDetectUsername = errors.New("pq: Could not detect default username. Please provide one explicitly")
+
+ errUnexpectedReady = errors.New("unexpected ReadyForQuery")
+ errNoRowsAffected = errors.New("no RowsAffected available after the empty statement")
+ errNoLastInsertID = errors.New("no LastInsertId available after the empty statement")
+)
+
+// Compile time validation that our types implement the expected interfaces
+var (
+ _ driver.Driver = Driver{}
+)
+
+// Driver is the Postgres database driver.
+type Driver struct{}
+
+// Open opens a new connection to the database. name is a connection string.
+// Most users should only use it through database/sql package from the standard
+// library.
+func (d Driver) Open(name string) (driver.Conn, error) {
+ return Open(name)
+}
+
+func init() {
+ sql.Register("postgres", &Driver{})
+}
+
+type parameterStatus struct {
+ // server version in the same format as server_version_num, or 0 if
+ // unavailable
+ serverVersion int
+
+ // the current location based on the TimeZone value of the session, if
+ // available
+ currentLocation *time.Location
+}
+
+type transactionStatus byte
+
+const (
+ txnStatusIdle transactionStatus = 'I'
+ txnStatusIdleInTransaction transactionStatus = 'T'
+ txnStatusInFailedTransaction transactionStatus = 'E'
+)
+
+func (s transactionStatus) String() string {
+ switch s {
+ case txnStatusIdle:
+ return "idle"
+ case txnStatusIdleInTransaction:
+ return "idle in transaction"
+ case txnStatusInFailedTransaction:
+ return "in a failed transaction"
+ default:
+ errorf("unknown transactionStatus %d", s)
+ }
+
+ panic("not reached")
+}
+
+// Dialer is the dialer interface. It can be used to obtain more control over
+// how pq creates network connections.
+type Dialer interface {
+ Dial(network, address string) (net.Conn, error)
+ DialTimeout(network, address string, timeout time.Duration) (net.Conn, error)
+}
+
+// DialerContext is the context-aware dialer interface.
+type DialerContext interface {
+ DialContext(ctx context.Context, network, address string) (net.Conn, error)
+}
+
+type defaultDialer struct {
+ d net.Dialer
+}
+
+func (d defaultDialer) Dial(network, address string) (net.Conn, error) {
+ return d.d.Dial(network, address)
+}
+func (d defaultDialer) DialTimeout(
+ network, address string, timeout time.Duration,
+) (net.Conn, error) {
+ ctx, cancel := context.WithTimeout(context.Background(), timeout)
+ defer cancel()
+ return d.DialContext(ctx, network, address)
+}
+func (d defaultDialer) DialContext(ctx context.Context, network, address string) (net.Conn, error) {
+ return d.d.DialContext(ctx, network, address)
+}
+
+type conn struct {
+ c net.Conn
+ buf *bufio.Reader
+ namei int
+ scratch [512]byte
+ txnStatus transactionStatus
+ txnFinish func()
+
+ // Save connection arguments to use during CancelRequest.
+ dialer Dialer
+ opts values
+
+ // Cancellation key data for use with CancelRequest messages.
+ processID int
+ secretKey int
+
+ parameterStatus parameterStatus
+
+ saveMessageType byte
+ saveMessageBuffer []byte
+
+ // If an error is set, this connection is bad and all public-facing
+ // functions should return the appropriate error by calling get()
+ // (ErrBadConn) or getForNext().
+ err syncErr
+
+ // If set, this connection should never use the binary format when
+ // receiving query results from prepared statements. Only provided for
+ // debugging.
+ disablePreparedBinaryResult bool
+
+ // Whether to always send []byte parameters over as binary. Enables single
+ // round-trip mode for non-prepared Query calls.
+ binaryParameters bool
+
+ // If true this connection is in the middle of a COPY
+ inCopy bool
+
+ // If not nil, notices will be synchronously sent here
+ noticeHandler func(*Error)
+
+ // If not nil, notifications will be synchronously sent here
+ notificationHandler func(*Notification)
+
+ // GSSAPI context
+ gss GSS
+}
+
+type syncErr struct {
+ err error
+ sync.Mutex
+}
+
+// Return ErrBadConn if connection is bad.
+func (e *syncErr) get() error {
+ e.Lock()
+ defer e.Unlock()
+ if e.err != nil {
+ return driver.ErrBadConn
+ }
+ return nil
+}
+
+// Return the error set on the connection. Currently only used by rows.Next.
+func (e *syncErr) getForNext() error {
+ e.Lock()
+ defer e.Unlock()
+ return e.err
+}
+
+// Set error, only if it isn't set yet.
+func (e *syncErr) set(err error) {
+ if err == nil {
+ panic("attempt to set nil err")
+ }
+ e.Lock()
+ defer e.Unlock()
+ if e.err == nil {
+ e.err = err
+ }
+}
+
+// Handle driver-side settings in parsed connection string.
+func (cn *conn) handleDriverSettings(o values) (err error) {
+ boolSetting := func(key string, val *bool) error {
+ if value, ok := o[key]; ok {
+ if value == "yes" {
+ *val = true
+ } else if value == "no" {
+ *val = false
+ } else {
+ return fmt.Errorf("unrecognized value %q for %s", value, key)
+ }
+ }
+ return nil
+ }
+
+ err = boolSetting("disable_prepared_binary_result", &cn.disablePreparedBinaryResult)
+ if err != nil {
+ return err
+ }
+ return boolSetting("binary_parameters", &cn.binaryParameters)
+}
+
+func (cn *conn) handlePgpass(o values) {
+ // if a password was supplied, do not process .pgpass
+ if _, ok := o["password"]; ok {
+ return
+ }
+ filename := os.Getenv("PGPASSFILE")
+ if filename == "" {
+ // XXX this code doesn't work on Windows where the default filename is
+ // XXX %APPDATA%\postgresql\pgpass.conf
+ // Prefer $HOME over user.Current due to glibc bug: golang.org/issue/13470
+ userHome := os.Getenv("HOME")
+ if userHome == "" {
+ user, err := user.Current()
+ if err != nil {
+ return
+ }
+ userHome = user.HomeDir
+ }
+ filename = filepath.Join(userHome, ".pgpass")
+ }
+ fileinfo, err := os.Stat(filename)
+ if err != nil {
+ return
+ }
+ mode := fileinfo.Mode()
+ if mode&(0x77) != 0 {
+ // XXX should warn about incorrect .pgpass permissions as psql does
+ return
+ }
+ file, err := os.Open(filename)
+ if err != nil {
+ return
+ }
+ defer file.Close()
+ scanner := bufio.NewScanner(io.Reader(file))
+ // From: https://github.com/tg/pgpass/blob/master/reader.go
+ for scanner.Scan() {
+ if scanText(scanner.Text(), o) {
+ break
+ }
+ }
+}
+
+// GetFields is a helper function for scanText.
+func getFields(s string) []string {
+ fs := make([]string, 0, 5)
+ f := make([]rune, 0, len(s))
+
+ var esc bool
+ for _, c := range s {
+ switch {
+ case esc:
+ f = append(f, c)
+ esc = false
+ case c == '\\':
+ esc = true
+ case c == ':':
+ fs = append(fs, string(f))
+ f = f[:0]
+ default:
+ f = append(f, c)
+ }
+ }
+ return append(fs, string(f))
+}
+
+// ScanText assists HandlePgpass in it's objective.
+func scanText(line string, o values) bool {
+ hostname := o["host"]
+ ntw, _ := network(o)
+ port := o["port"]
+ db := o["dbname"]
+ username := o["user"]
+ if len(line) == 0 || line[0] == '#' {
+ return false
+ }
+ split := getFields(line)
+ if len(split) != 5 {
+ return false
+ }
+ if (split[0] == "*" || split[0] == hostname || (split[0] == "localhost" && (hostname == "" || ntw == "unix"))) && (split[1] == "*" || split[1] == port) && (split[2] == "*" || split[2] == db) && (split[3] == "*" || split[3] == username) {
+ o["password"] = split[4]
+ return true
+ }
+ return false
+}
+
+func (cn *conn) writeBuf(b byte) *writeBuf {
+ cn.scratch[0] = b
+ return &writeBuf{
+ buf: cn.scratch[:5],
+ pos: 1,
+ }
+}
+
+// Open opens a new connection to the database. dsn is a connection string.
+// Most users should only use it through database/sql package from the standard
+// library.
+func Open(dsn string) (_ driver.Conn, err error) {
+ return DialOpen(defaultDialer{}, dsn)
+}
+
+// DialOpen opens a new connection to the database using a dialer.
+func DialOpen(d Dialer, dsn string) (_ driver.Conn, err error) {
+ c, err := NewConnector(dsn)
+ if err != nil {
+ return nil, err
+ }
+ c.Dialer(d)
+ return c.open(context.Background())
+}
+
+func (c *Connector) open(ctx context.Context) (cn *conn, err error) {
+ // Handle any panics during connection initialization. Note that we
+ // specifically do *not* want to use errRecover(), as that would turn any
+ // connection errors into ErrBadConns, hiding the real error message from
+ // the user.
+ defer errRecoverNoErrBadConn(&err)
+
+ // Create a new values map (copy). This makes it so maps in different
+ // connections do not reference the same underlying data structure, so it
+ // is safe for multiple connections to concurrently write to their opts.
+ o := make(values)
+ for k, v := range c.opts {
+ o[k] = v
+ }
+
+ cn = &conn{
+ opts: o,
+ dialer: c.dialer,
+ }
+ err = cn.handleDriverSettings(o)
+ if err != nil {
+ return nil, err
+ }
+ cn.handlePgpass(o)
+
+ cn.c, err = dial(ctx, c.dialer, o)
+ if err != nil {
+ return nil, err
+ }
+
+ err = cn.ssl(o)
+ if err != nil {
+ if cn.c != nil {
+ cn.c.Close()
+ }
+ return nil, err
+ }
+
+ // cn.startup panics on error. Make sure we don't leak cn.c.
+ panicking := true
+ defer func() {
+ if panicking {
+ cn.c.Close()
+ }
+ }()
+
+ cn.buf = bufio.NewReader(cn.c)
+ cn.startup(o)
+
+ // reset the deadline, in case one was set (see dial)
+ if timeout, ok := o["connect_timeout"]; ok && timeout != "0" {
+ err = cn.c.SetDeadline(time.Time{})
+ }
+ panicking = false
+ return cn, err
+}
+
+func dial(ctx context.Context, d Dialer, o values) (net.Conn, error) {
+ network, address := network(o)
+
+ // Zero or not specified means wait indefinitely.
+ if timeout, ok := o["connect_timeout"]; ok && timeout != "0" {
+ seconds, err := strconv.ParseInt(timeout, 10, 0)
+ if err != nil {
+ return nil, fmt.Errorf("invalid value for parameter connect_timeout: %s", err)
+ }
+ duration := time.Duration(seconds) * time.Second
+
+ // connect_timeout should apply to the entire connection establishment
+ // procedure, so we both use a timeout for the TCP connection
+ // establishment and set a deadline for doing the initial handshake.
+ // The deadline is then reset after startup() is done.
+ deadline := time.Now().Add(duration)
+ var conn net.Conn
+ if dctx, ok := d.(DialerContext); ok {
+ ctx, cancel := context.WithTimeout(ctx, duration)
+ defer cancel()
+ conn, err = dctx.DialContext(ctx, network, address)
+ } else {
+ conn, err = d.DialTimeout(network, address, duration)
+ }
+ if err != nil {
+ return nil, err
+ }
+ err = conn.SetDeadline(deadline)
+ return conn, err
+ }
+ if dctx, ok := d.(DialerContext); ok {
+ return dctx.DialContext(ctx, network, address)
+ }
+ return d.Dial(network, address)
+}
+
+func network(o values) (string, string) {
+ host := o["host"]
+
+ if strings.HasPrefix(host, "/") {
+ sockPath := path.Join(host, ".s.PGSQL."+o["port"])
+ return "unix", sockPath
+ }
+
+ return "tcp", net.JoinHostPort(host, o["port"])
+}
+
+type values map[string]string
+
+// scanner implements a tokenizer for libpq-style option strings.
+type scanner struct {
+ s []rune
+ i int
+}
+
+// newScanner returns a new scanner initialized with the option string s.
+func newScanner(s string) *scanner {
+ return &scanner{[]rune(s), 0}
+}
+
+// Next returns the next rune.
+// It returns 0, false if the end of the text has been reached.
+func (s *scanner) Next() (rune, bool) {
+ if s.i >= len(s.s) {
+ return 0, false
+ }
+ r := s.s[s.i]
+ s.i++
+ return r, true
+}
+
+// SkipSpaces returns the next non-whitespace rune.
+// It returns 0, false if the end of the text has been reached.
+func (s *scanner) SkipSpaces() (rune, bool) {
+ r, ok := s.Next()
+ for unicode.IsSpace(r) && ok {
+ r, ok = s.Next()
+ }
+ return r, ok
+}
+
+// parseOpts parses the options from name and adds them to the values.
+//
+// The parsing code is based on conninfo_parse from libpq's fe-connect.c
+func parseOpts(name string, o values) error {
+ s := newScanner(name)
+
+ for {
+ var (
+ keyRunes, valRunes []rune
+ r rune
+ ok bool
+ )
+
+ if r, ok = s.SkipSpaces(); !ok {
+ break
+ }
+
+ // Scan the key
+ for !unicode.IsSpace(r) && r != '=' {
+ keyRunes = append(keyRunes, r)
+ if r, ok = s.Next(); !ok {
+ break
+ }
+ }
+
+ // Skip any whitespace if we're not at the = yet
+ if r != '=' {
+ r, ok = s.SkipSpaces()
+ }
+
+ // The current character should be =
+ if r != '=' || !ok {
+ return fmt.Errorf(`missing "=" after %q in connection info string"`, string(keyRunes))
+ }
+
+ // Skip any whitespace after the =
+ if r, ok = s.SkipSpaces(); !ok {
+ // If we reach the end here, the last value is just an empty string as per libpq.
+ o[string(keyRunes)] = ""
+ break
+ }
+
+ if r != '\'' {
+ for !unicode.IsSpace(r) {
+ if r == '\\' {
+ if r, ok = s.Next(); !ok {
+ return fmt.Errorf(`missing character after backslash`)
+ }
+ }
+ valRunes = append(valRunes, r)
+
+ if r, ok = s.Next(); !ok {
+ break
+ }
+ }
+ } else {
+ quote:
+ for {
+ if r, ok = s.Next(); !ok {
+ return fmt.Errorf(`unterminated quoted string literal in connection string`)
+ }
+ switch r {
+ case '\'':
+ break quote
+ case '\\':
+ r, _ = s.Next()
+ fallthrough
+ default:
+ valRunes = append(valRunes, r)
+ }
+ }
+ }
+
+ o[string(keyRunes)] = string(valRunes)
+ }
+
+ return nil
+}
+
+func (cn *conn) isInTransaction() bool {
+ return cn.txnStatus == txnStatusIdleInTransaction ||
+ cn.txnStatus == txnStatusInFailedTransaction
+}
+
+func (cn *conn) checkIsInTransaction(intxn bool) {
+ if cn.isInTransaction() != intxn {
+ cn.err.set(driver.ErrBadConn)
+ errorf("unexpected transaction status %v", cn.txnStatus)
+ }
+}
+
+func (cn *conn) Begin() (_ driver.Tx, err error) {
+ return cn.begin("")
+}
+
+func (cn *conn) begin(mode string) (_ driver.Tx, err error) {
+ if err := cn.err.get(); err != nil {
+ return nil, err
+ }
+ defer cn.errRecover(&err)
+
+ cn.checkIsInTransaction(false)
+ _, commandTag, err := cn.simpleExec("BEGIN" + mode)
+ if err != nil {
+ return nil, err
+ }
+ if commandTag != "BEGIN" {
+ cn.err.set(driver.ErrBadConn)
+ return nil, fmt.Errorf("unexpected command tag %s", commandTag)
+ }
+ if cn.txnStatus != txnStatusIdleInTransaction {
+ cn.err.set(driver.ErrBadConn)
+ return nil, fmt.Errorf("unexpected transaction status %v", cn.txnStatus)
+ }
+ return cn, nil
+}
+
+func (cn *conn) closeTxn() {
+ if finish := cn.txnFinish; finish != nil {
+ finish()
+ }
+}
+
+func (cn *conn) Commit() (err error) {
+ defer cn.closeTxn()
+ if err := cn.err.get(); err != nil {
+ return err
+ }
+ defer cn.errRecover(&err)
+
+ cn.checkIsInTransaction(true)
+ // We don't want the client to think that everything is okay if it tries
+ // to commit a failed transaction. However, no matter what we return,
+ // database/sql will release this connection back into the free connection
+ // pool so we have to abort the current transaction here. Note that you
+ // would get the same behaviour if you issued a COMMIT in a failed
+ // transaction, so it's also the least surprising thing to do here.
+ if cn.txnStatus == txnStatusInFailedTransaction {
+ if err := cn.rollback(); err != nil {
+ return err
+ }
+ return ErrInFailedTransaction
+ }
+
+ _, commandTag, err := cn.simpleExec("COMMIT")
+ if err != nil {
+ if cn.isInTransaction() {
+ cn.err.set(driver.ErrBadConn)
+ }
+ return err
+ }
+ if commandTag != "COMMIT" {
+ cn.err.set(driver.ErrBadConn)
+ return fmt.Errorf("unexpected command tag %s", commandTag)
+ }
+ cn.checkIsInTransaction(false)
+ return nil
+}
+
+func (cn *conn) Rollback() (err error) {
+ defer cn.closeTxn()
+ if err := cn.err.get(); err != nil {
+ return err
+ }
+ defer cn.errRecover(&err)
+ return cn.rollback()
+}
+
+func (cn *conn) rollback() (err error) {
+ cn.checkIsInTransaction(true)
+ _, commandTag, err := cn.simpleExec("ROLLBACK")
+ if err != nil {
+ if cn.isInTransaction() {
+ cn.err.set(driver.ErrBadConn)
+ }
+ return err
+ }
+ if commandTag != "ROLLBACK" {
+ return fmt.Errorf("unexpected command tag %s", commandTag)
+ }
+ cn.checkIsInTransaction(false)
+ return nil
+}
+
+func (cn *conn) gname() string {
+ cn.namei++
+ return strconv.FormatInt(int64(cn.namei), 10)
+}
+
+func (cn *conn) simpleExec(q string) (res driver.Result, commandTag string, err error) {
+ b := cn.writeBuf('Q')
+ b.string(q)
+ cn.send(b)
+
+ for {
+ t, r := cn.recv1()
+ switch t {
+ case 'C':
+ res, commandTag = cn.parseComplete(r.string())
+ case 'Z':
+ cn.processReadyForQuery(r)
+ if res == nil && err == nil {
+ err = errUnexpectedReady
+ }
+ // done
+ return
+ case 'E':
+ err = parseError(r)
+ case 'I':
+ res = emptyRows
+ case 'T', 'D':
+ // ignore any results
+ default:
+ cn.err.set(driver.ErrBadConn)
+ errorf("unknown response for simple query: %q", t)
+ }
+ }
+}
+
+func (cn *conn) simpleQuery(q string) (res *rows, err error) {
+ defer cn.errRecover(&err)
+
+ b := cn.writeBuf('Q')
+ b.string(q)
+ cn.send(b)
+
+ for {
+ t, r := cn.recv1()
+ switch t {
+ case 'C', 'I':
+ // We allow queries which don't return any results through Query as
+ // well as Exec. We still have to give database/sql a rows object
+ // the user can close, though, to avoid connections from being
+ // leaked. A "rows" with done=true works fine for that purpose.
+ if err != nil {
+ cn.err.set(driver.ErrBadConn)
+ errorf("unexpected message %q in simple query execution", t)
+ }
+ if res == nil {
+ res = &rows{
+ cn: cn,
+ }
+ }
+ // Set the result and tag to the last command complete if there wasn't a
+ // query already run. Although queries usually return from here and cede
+ // control to Next, a query with zero results does not.
+ if t == 'C' {
+ res.result, res.tag = cn.parseComplete(r.string())
+ if res.colNames != nil {
+ return
+ }
+ }
+ res.done = true
+ case 'Z':
+ cn.processReadyForQuery(r)
+ // done
+ return
+ case 'E':
+ res = nil
+ err = parseError(r)
+ case 'D':
+ if res == nil {
+ cn.err.set(driver.ErrBadConn)
+ errorf("unexpected DataRow in simple query execution")
+ }
+ // the query didn't fail; kick off to Next
+ cn.saveMessage(t, r)
+ return
+ case 'T':
+ // res might be non-nil here if we received a previous
+ // CommandComplete, but that's fine; just overwrite it
+ res = &rows{cn: cn}
+ res.rowsHeader = parsePortalRowDescribe(r)
+
+ // To work around a bug in QueryRow in Go 1.2 and earlier, wait
+ // until the first DataRow has been received.
+ default:
+ cn.err.set(driver.ErrBadConn)
+ errorf("unknown response for simple query: %q", t)
+ }
+ }
+}
+
+type noRows struct{}
+
+var emptyRows noRows
+
+var _ driver.Result = noRows{}
+
+func (noRows) LastInsertId() (int64, error) {
+ return 0, errNoLastInsertID
+}
+
+func (noRows) RowsAffected() (int64, error) {
+ return 0, errNoRowsAffected
+}
+
+// Decides which column formats to use for a prepared statement. The input is
+// an array of type oids, one element per result column.
+func decideColumnFormats(
+ colTyps []fieldDesc, forceText bool,
+) (colFmts []format, colFmtData []byte) {
+ if len(colTyps) == 0 {
+ return nil, colFmtDataAllText
+ }
+
+ colFmts = make([]format, len(colTyps))
+ if forceText {
+ return colFmts, colFmtDataAllText
+ }
+
+ allBinary := true
+ allText := true
+ for i, t := range colTyps {
+ switch t.OID {
+ // This is the list of types to use binary mode for when receiving them
+ // through a prepared statement. If a type appears in this list, it
+ // must also be implemented in binaryDecode in encode.go.
+ case oid.T_bytea:
+ fallthrough
+ case oid.T_int8:
+ fallthrough
+ case oid.T_int4:
+ fallthrough
+ case oid.T_int2:
+ fallthrough
+ case oid.T_uuid:
+ colFmts[i] = formatBinary
+ allText = false
+
+ default:
+ allBinary = false
+ }
+ }
+
+ if allBinary {
+ return colFmts, colFmtDataAllBinary
+ } else if allText {
+ return colFmts, colFmtDataAllText
+ } else {
+ colFmtData = make([]byte, 2+len(colFmts)*2)
+ binary.BigEndian.PutUint16(colFmtData, uint16(len(colFmts)))
+ for i, v := range colFmts {
+ binary.BigEndian.PutUint16(colFmtData[2+i*2:], uint16(v))
+ }
+ return colFmts, colFmtData
+ }
+}
+
+func (cn *conn) prepareTo(q, stmtName string) *stmt {
+ st := &stmt{cn: cn, name: stmtName}
+
+ b := cn.writeBuf('P')
+ b.string(st.name)
+ b.string(q)
+ b.int16(0)
+
+ b.next('D')
+ b.byte('S')
+ b.string(st.name)
+
+ b.next('S')
+ cn.send(b)
+
+ cn.readParseResponse()
+ st.paramTyps, st.colNames, st.colTyps = cn.readStatementDescribeResponse()
+ st.colFmts, st.colFmtData = decideColumnFormats(st.colTyps, cn.disablePreparedBinaryResult)
+ cn.readReadyForQuery()
+ return st
+}
+
+func (cn *conn) Prepare(q string) (_ driver.Stmt, err error) {
+ if err := cn.err.get(); err != nil {
+ return nil, err
+ }
+ defer cn.errRecover(&err)
+
+ if len(q) >= 4 && strings.EqualFold(q[:4], "COPY") {
+ s, err := cn.prepareCopyIn(q)
+ if err == nil {
+ cn.inCopy = true
+ }
+ return s, err
+ }
+ return cn.prepareTo(q, cn.gname()), nil
+}
+
+func (cn *conn) Close() (err error) {
+ // Skip cn.bad return here because we always want to close a connection.
+ defer cn.errRecover(&err)
+
+ // Ensure that cn.c.Close is always run. Since error handling is done with
+ // panics and cn.errRecover, the Close must be in a defer.
+ defer func() {
+ cerr := cn.c.Close()
+ if err == nil {
+ err = cerr
+ }
+ }()
+
+ // Don't go through send(); ListenerConn relies on us not scribbling on the
+ // scratch buffer of this connection.
+ return cn.sendSimpleMessage('X')
+}
+
+// Implement the "Queryer" interface
+func (cn *conn) Query(query string, args []driver.Value) (driver.Rows, error) {
+ return cn.query(query, args)
+}
+
+func (cn *conn) query(query string, args []driver.Value) (_ *rows, err error) {
+ if err := cn.err.get(); err != nil {
+ return nil, err
+ }
+ if cn.inCopy {
+ return nil, errCopyInProgress
+ }
+ defer cn.errRecover(&err)
+
+ // Check to see if we can use the "simpleQuery" interface, which is
+ // *much* faster than going through prepare/exec
+ if len(args) == 0 {
+ return cn.simpleQuery(query)
+ }
+
+ if cn.binaryParameters {
+ cn.sendBinaryModeQuery(query, args)
+
+ cn.readParseResponse()
+ cn.readBindResponse()
+ rows := &rows{cn: cn}
+ rows.rowsHeader = cn.readPortalDescribeResponse()
+ cn.postExecuteWorkaround()
+ return rows, nil
+ }
+ st := cn.prepareTo(query, "")
+ st.exec(args)
+ return &rows{
+ cn: cn,
+ rowsHeader: st.rowsHeader,
+ }, nil
+}
+
+// Implement the optional "Execer" interface for one-shot queries
+func (cn *conn) Exec(query string, args []driver.Value) (res driver.Result, err error) {
+ if err := cn.err.get(); err != nil {
+ return nil, err
+ }
+ defer cn.errRecover(&err)
+
+ // Check to see if we can use the "simpleExec" interface, which is
+ // *much* faster than going through prepare/exec
+ if len(args) == 0 {
+ // ignore commandTag, our caller doesn't care
+ r, _, err := cn.simpleExec(query)
+ return r, err
+ }
+
+ if cn.binaryParameters {
+ cn.sendBinaryModeQuery(query, args)
+
+ cn.readParseResponse()
+ cn.readBindResponse()
+ cn.readPortalDescribeResponse()
+ cn.postExecuteWorkaround()
+ res, _, err = cn.readExecuteResponse("Execute")
+ return res, err
+ }
+ // Use the unnamed statement to defer planning until bind
+ // time, or else value-based selectivity estimates cannot be
+ // used.
+ st := cn.prepareTo(query, "")
+ r, err := st.Exec(args)
+ if err != nil {
+ panic(err)
+ }
+ return r, err
+}
+
+type safeRetryError struct {
+ Err error
+}
+
+func (se *safeRetryError) Error() string {
+ return se.Err.Error()
+}
+
+func (cn *conn) send(m *writeBuf) {
+ n, err := cn.c.Write(m.wrap())
+ if err != nil {
+ if n == 0 {
+ err = &safeRetryError{Err: err}
+ }
+ panic(err)
+ }
+}
+
+func (cn *conn) sendStartupPacket(m *writeBuf) error {
+ _, err := cn.c.Write((m.wrap())[1:])
+ return err
+}
+
+// Send a message of type typ to the server on the other end of cn. The
+// message should have no payload. This method does not use the scratch
+// buffer.
+func (cn *conn) sendSimpleMessage(typ byte) (err error) {
+ _, err = cn.c.Write([]byte{typ, '\x00', '\x00', '\x00', '\x04'})
+ return err
+}
+
+// saveMessage memorizes a message and its buffer in the conn struct.
+// recvMessage will then return these values on the next call to it. This
+// method is useful in cases where you have to see what the next message is
+// going to be (e.g. to see whether it's an error or not) but you can't handle
+// the message yourself.
+func (cn *conn) saveMessage(typ byte, buf *readBuf) {
+ if cn.saveMessageType != 0 {
+ cn.err.set(driver.ErrBadConn)
+ errorf("unexpected saveMessageType %d", cn.saveMessageType)
+ }
+ cn.saveMessageType = typ
+ cn.saveMessageBuffer = *buf
+}
+
+// recvMessage receives any message from the backend, or returns an error if
+// a problem occurred while reading the message.
+func (cn *conn) recvMessage(r *readBuf) (byte, error) {
+ // workaround for a QueryRow bug, see exec
+ if cn.saveMessageType != 0 {
+ t := cn.saveMessageType
+ *r = cn.saveMessageBuffer
+ cn.saveMessageType = 0
+ cn.saveMessageBuffer = nil
+ return t, nil
+ }
+
+ x := cn.scratch[:5]
+ _, err := io.ReadFull(cn.buf, x)
+ if err != nil {
+ return 0, err
+ }
+
+ // read the type and length of the message that follows
+ t := x[0]
+ n := int(binary.BigEndian.Uint32(x[1:])) - 4
+ var y []byte
+ if n <= len(cn.scratch) {
+ y = cn.scratch[:n]
+ } else {
+ y = make([]byte, n)
+ }
+ _, err = io.ReadFull(cn.buf, y)
+ if err != nil {
+ return 0, err
+ }
+ *r = y
+ return t, nil
+}
+
+// recv receives a message from the backend, but if an error happened while
+// reading the message or the received message was an ErrorResponse, it panics.
+// NoticeResponses are ignored. This function should generally be used only
+// during the startup sequence.
+func (cn *conn) recv() (t byte, r *readBuf) {
+ for {
+ var err error
+ r = &readBuf{}
+ t, err = cn.recvMessage(r)
+ if err != nil {
+ panic(err)
+ }
+ switch t {
+ case 'E':
+ panic(parseError(r))
+ case 'N':
+ if n := cn.noticeHandler; n != nil {
+ n(parseError(r))
+ }
+ case 'A':
+ if n := cn.notificationHandler; n != nil {
+ n(recvNotification(r))
+ }
+ default:
+ return
+ }
+ }
+}
+
+// recv1Buf is exactly equivalent to recv1, except it uses a buffer supplied by
+// the caller to avoid an allocation.
+func (cn *conn) recv1Buf(r *readBuf) byte {
+ for {
+ t, err := cn.recvMessage(r)
+ if err != nil {
+ panic(err)
+ }
+
+ switch t {
+ case 'A':
+ if n := cn.notificationHandler; n != nil {
+ n(recvNotification(r))
+ }
+ case 'N':
+ if n := cn.noticeHandler; n != nil {
+ n(parseError(r))
+ }
+ case 'S':
+ cn.processParameterStatus(r)
+ default:
+ return t
+ }
+ }
+}
+
+// recv1 receives a message from the backend, panicking if an error occurs
+// while attempting to read it. All asynchronous messages are ignored, with
+// the exception of ErrorResponse.
+func (cn *conn) recv1() (t byte, r *readBuf) {
+ r = &readBuf{}
+ t = cn.recv1Buf(r)
+ return t, r
+}
+
+func (cn *conn) ssl(o values) error {
+ upgrade, err := ssl(o)
+ if err != nil {
+ return err
+ }
+
+ if upgrade == nil {
+ // Nothing to do
+ return nil
+ }
+
+ w := cn.writeBuf(0)
+ w.int32(80877103)
+ if err = cn.sendStartupPacket(w); err != nil {
+ return err
+ }
+
+ b := cn.scratch[:1]
+ _, err = io.ReadFull(cn.c, b)
+ if err != nil {
+ return err
+ }
+
+ if b[0] != 'S' {
+ return ErrSSLNotSupported
+ }
+
+ cn.c, err = upgrade(cn.c)
+ return err
+}
+
+// isDriverSetting returns true iff a setting is purely for configuring the
+// driver's options and should not be sent to the server in the connection
+// startup packet.
+func isDriverSetting(key string) bool {
+ switch key {
+ case "host", "port":
+ return true
+ case "password":
+ return true
+ case "sslmode", "sslcert", "sslkey", "sslrootcert", "sslinline", "sslsni":
+ return true
+ case "fallback_application_name":
+ return true
+ case "connect_timeout":
+ return true
+ case "disable_prepared_binary_result":
+ return true
+ case "binary_parameters":
+ return true
+ case "krbsrvname":
+ return true
+ case "krbspn":
+ return true
+ default:
+ return false
+ }
+}
+
+func (cn *conn) startup(o values) {
+ w := cn.writeBuf(0)
+ w.int32(196608)
+ // Send the backend the name of the database we want to connect to, and the
+ // user we want to connect as. Additionally, we send over any run-time
+ // parameters potentially included in the connection string. If the server
+ // doesn't recognize any of them, it will reply with an error.
+ for k, v := range o {
+ if isDriverSetting(k) {
+ // skip options which can't be run-time parameters
+ continue
+ }
+ // The protocol requires us to supply the database name as "database"
+ // instead of "dbname".
+ if k == "dbname" {
+ k = "database"
+ }
+ w.string(k)
+ w.string(v)
+ }
+ w.string("")
+ if err := cn.sendStartupPacket(w); err != nil {
+ panic(err)
+ }
+
+ for {
+ t, r := cn.recv()
+ switch t {
+ case 'K':
+ cn.processBackendKeyData(r)
+ case 'S':
+ cn.processParameterStatus(r)
+ case 'R':
+ cn.auth(r, o)
+ case 'Z':
+ cn.processReadyForQuery(r)
+ return
+ default:
+ errorf("unknown response for startup: %q", t)
+ }
+ }
+}
+
+func (cn *conn) auth(r *readBuf, o values) {
+ switch code := r.int32(); code {
+ case 0:
+ // OK
+ case 3:
+ w := cn.writeBuf('p')
+ w.string(o["password"])
+ cn.send(w)
+
+ t, r := cn.recv()
+ if t != 'R' {
+ errorf("unexpected password response: %q", t)
+ }
+
+ if r.int32() != 0 {
+ errorf("unexpected authentication response: %q", t)
+ }
+ case 5:
+ s := string(r.next(4))
+ w := cn.writeBuf('p')
+ w.string("md5" + md5s(md5s(o["password"]+o["user"])+s))
+ cn.send(w)
+
+ t, r := cn.recv()
+ if t != 'R' {
+ errorf("unexpected password response: %q", t)
+ }
+
+ if r.int32() != 0 {
+ errorf("unexpected authentication response: %q", t)
+ }
+ case 7: // GSSAPI, startup
+ if newGss == nil {
+ errorf("kerberos error: no GSSAPI provider registered (import github.com/lib/pq/auth/kerberos if you need Kerberos support)")
+ }
+ cli, err := newGss()
+ if err != nil {
+ errorf("kerberos error: %s", err.Error())
+ }
+
+ var token []byte
+
+ if spn, ok := o["krbspn"]; ok {
+ // Use the supplied SPN if provided..
+ token, err = cli.GetInitTokenFromSpn(spn)
+ } else {
+ // Allow the kerberos service name to be overridden
+ service := "postgres"
+ if val, ok := o["krbsrvname"]; ok {
+ service = val
+ }
+
+ token, err = cli.GetInitToken(o["host"], service)
+ }
+
+ if err != nil {
+ errorf("failed to get Kerberos ticket: %q", err)
+ }
+
+ w := cn.writeBuf('p')
+ w.bytes(token)
+ cn.send(w)
+
+ // Store for GSSAPI continue message
+ cn.gss = cli
+
+ case 8: // GSSAPI continue
+
+ if cn.gss == nil {
+ errorf("GSSAPI protocol error")
+ }
+
+ b := []byte(*r)
+
+ done, tokOut, err := cn.gss.Continue(b)
+ if err == nil && !done {
+ w := cn.writeBuf('p')
+ w.bytes(tokOut)
+ cn.send(w)
+ }
+
+ // Errors fall through and read the more detailed message
+ // from the server..
+
+ case 10:
+ sc := scram.NewClient(sha256.New, o["user"], o["password"])
+ sc.Step(nil)
+ if sc.Err() != nil {
+ errorf("SCRAM-SHA-256 error: %s", sc.Err().Error())
+ }
+ scOut := sc.Out()
+
+ w := cn.writeBuf('p')
+ w.string("SCRAM-SHA-256")
+ w.int32(len(scOut))
+ w.bytes(scOut)
+ cn.send(w)
+
+ t, r := cn.recv()
+ if t != 'R' {
+ errorf("unexpected password response: %q", t)
+ }
+
+ if r.int32() != 11 {
+ errorf("unexpected authentication response: %q", t)
+ }
+
+ nextStep := r.next(len(*r))
+ sc.Step(nextStep)
+ if sc.Err() != nil {
+ errorf("SCRAM-SHA-256 error: %s", sc.Err().Error())
+ }
+
+ scOut = sc.Out()
+ w = cn.writeBuf('p')
+ w.bytes(scOut)
+ cn.send(w)
+
+ t, r = cn.recv()
+ if t != 'R' {
+ errorf("unexpected password response: %q", t)
+ }
+
+ if r.int32() != 12 {
+ errorf("unexpected authentication response: %q", t)
+ }
+
+ nextStep = r.next(len(*r))
+ sc.Step(nextStep)
+ if sc.Err() != nil {
+ errorf("SCRAM-SHA-256 error: %s", sc.Err().Error())
+ }
+
+ default:
+ errorf("unknown authentication response: %d", code)
+ }
+}
+
+type format int
+
+const formatText format = 0
+const formatBinary format = 1
+
+// One result-column format code with the value 1 (i.e. all binary).
+var colFmtDataAllBinary = []byte{0, 1, 0, 1}
+
+// No result-column format codes (i.e. all text).
+var colFmtDataAllText = []byte{0, 0}
+
+type stmt struct {
+ cn *conn
+ name string
+ rowsHeader
+ colFmtData []byte
+ paramTyps []oid.Oid
+ closed bool
+}
+
+func (st *stmt) Close() (err error) {
+ if st.closed {
+ return nil
+ }
+ if err := st.cn.err.get(); err != nil {
+ return err
+ }
+ defer st.cn.errRecover(&err)
+
+ w := st.cn.writeBuf('C')
+ w.byte('S')
+ w.string(st.name)
+ st.cn.send(w)
+
+ st.cn.send(st.cn.writeBuf('S'))
+
+ t, _ := st.cn.recv1()
+ if t != '3' {
+ st.cn.err.set(driver.ErrBadConn)
+ errorf("unexpected close response: %q", t)
+ }
+ st.closed = true
+
+ t, r := st.cn.recv1()
+ if t != 'Z' {
+ st.cn.err.set(driver.ErrBadConn)
+ errorf("expected ready for query, but got: %q", t)
+ }
+ st.cn.processReadyForQuery(r)
+
+ return nil
+}
+
+func (st *stmt) Query(v []driver.Value) (r driver.Rows, err error) {
+ return st.query(v)
+}
+
+func (st *stmt) query(v []driver.Value) (r *rows, err error) {
+ if err := st.cn.err.get(); err != nil {
+ return nil, err
+ }
+ defer st.cn.errRecover(&err)
+
+ st.exec(v)
+ return &rows{
+ cn: st.cn,
+ rowsHeader: st.rowsHeader,
+ }, nil
+}
+
+func (st *stmt) Exec(v []driver.Value) (res driver.Result, err error) {
+ if err := st.cn.err.get(); err != nil {
+ return nil, err
+ }
+ defer st.cn.errRecover(&err)
+
+ st.exec(v)
+ res, _, err = st.cn.readExecuteResponse("simple query")
+ return res, err
+}
+
+func (st *stmt) exec(v []driver.Value) {
+ if len(v) >= 65536 {
+ errorf("got %d parameters but PostgreSQL only supports 65535 parameters", len(v))
+ }
+ if len(v) != len(st.paramTyps) {
+ errorf("got %d parameters but the statement requires %d", len(v), len(st.paramTyps))
+ }
+
+ cn := st.cn
+ w := cn.writeBuf('B')
+ w.byte(0) // unnamed portal
+ w.string(st.name)
+
+ if cn.binaryParameters {
+ cn.sendBinaryParameters(w, v)
+ } else {
+ w.int16(0)
+ w.int16(len(v))
+ for i, x := range v {
+ if x == nil {
+ w.int32(-1)
+ } else {
+ b := encode(&cn.parameterStatus, x, st.paramTyps[i])
+ w.int32(len(b))
+ w.bytes(b)
+ }
+ }
+ }
+ w.bytes(st.colFmtData)
+
+ w.next('E')
+ w.byte(0)
+ w.int32(0)
+
+ w.next('S')
+ cn.send(w)
+
+ cn.readBindResponse()
+ cn.postExecuteWorkaround()
+
+}
+
+func (st *stmt) NumInput() int {
+ return len(st.paramTyps)
+}
+
+// parseComplete parses the "command tag" from a CommandComplete message, and
+// returns the number of rows affected (if applicable) and a string
+// identifying only the command that was executed, e.g. "ALTER TABLE". If the
+// command tag could not be parsed, parseComplete panics.
+func (cn *conn) parseComplete(commandTag string) (driver.Result, string) {
+ commandsWithAffectedRows := []string{
+ "SELECT ",
+ // INSERT is handled below
+ "UPDATE ",
+ "DELETE ",
+ "FETCH ",
+ "MOVE ",
+ "COPY ",
+ }
+
+ var affectedRows *string
+ for _, tag := range commandsWithAffectedRows {
+ if strings.HasPrefix(commandTag, tag) {
+ t := commandTag[len(tag):]
+ affectedRows = &t
+ commandTag = tag[:len(tag)-1]
+ break
+ }
+ }
+ // INSERT also includes the oid of the inserted row in its command tag.
+ // Oids in user tables are deprecated, and the oid is only returned when
+ // exactly one row is inserted, so it's unlikely to be of value to any
+ // real-world application and we can ignore it.
+ if affectedRows == nil && strings.HasPrefix(commandTag, "INSERT ") {
+ parts := strings.Split(commandTag, " ")
+ if len(parts) != 3 {
+ cn.err.set(driver.ErrBadConn)
+ errorf("unexpected INSERT command tag %s", commandTag)
+ }
+ affectedRows = &parts[len(parts)-1]
+ commandTag = "INSERT"
+ }
+ // There should be no affected rows attached to the tag, just return it
+ if affectedRows == nil {
+ return driver.RowsAffected(0), commandTag
+ }
+ n, err := strconv.ParseInt(*affectedRows, 10, 64)
+ if err != nil {
+ cn.err.set(driver.ErrBadConn)
+ errorf("could not parse commandTag: %s", err)
+ }
+ return driver.RowsAffected(n), commandTag
+}
+
+type rowsHeader struct {
+ colNames []string
+ colTyps []fieldDesc
+ colFmts []format
+}
+
+type rows struct {
+ cn *conn
+ finish func()
+ rowsHeader
+ done bool
+ rb readBuf
+ result driver.Result
+ tag string
+
+ next *rowsHeader
+}
+
+func (rs *rows) Close() error {
+ if finish := rs.finish; finish != nil {
+ defer finish()
+ }
+ // no need to look at cn.bad as Next() will
+ for {
+ err := rs.Next(nil)
+ switch err {
+ case nil:
+ case io.EOF:
+ // rs.Next can return io.EOF on both 'Z' (ready for query) and 'T' (row
+ // description, used with HasNextResultSet). We need to fetch messages until
+ // we hit a 'Z', which is done by waiting for done to be set.
+ if rs.done {
+ return nil
+ }
+ default:
+ return err
+ }
+ }
+}
+
+func (rs *rows) Columns() []string {
+ return rs.colNames
+}
+
+func (rs *rows) Result() driver.Result {
+ if rs.result == nil {
+ return emptyRows
+ }
+ return rs.result
+}
+
+func (rs *rows) Tag() string {
+ return rs.tag
+}
+
+func (rs *rows) Next(dest []driver.Value) (err error) {
+ if rs.done {
+ return io.EOF
+ }
+
+ conn := rs.cn
+ if err := conn.err.getForNext(); err != nil {
+ return err
+ }
+ defer conn.errRecover(&err)
+
+ for {
+ t := conn.recv1Buf(&rs.rb)
+ switch t {
+ case 'E':
+ err = parseError(&rs.rb)
+ case 'C', 'I':
+ if t == 'C' {
+ rs.result, rs.tag = conn.parseComplete(rs.rb.string())
+ }
+ continue
+ case 'Z':
+ conn.processReadyForQuery(&rs.rb)
+ rs.done = true
+ if err != nil {
+ return err
+ }
+ return io.EOF
+ case 'D':
+ n := rs.rb.int16()
+ if err != nil {
+ conn.err.set(driver.ErrBadConn)
+ errorf("unexpected DataRow after error %s", err)
+ }
+ if n < len(dest) {
+ dest = dest[:n]
+ }
+ for i := range dest {
+ l := rs.rb.int32()
+ if l == -1 {
+ dest[i] = nil
+ continue
+ }
+ dest[i] = decode(&conn.parameterStatus, rs.rb.next(l), rs.colTyps[i].OID, rs.colFmts[i])
+ }
+ return
+ case 'T':
+ next := parsePortalRowDescribe(&rs.rb)
+ rs.next = &next
+ return io.EOF
+ default:
+ errorf("unexpected message after execute: %q", t)
+ }
+ }
+}
+
+func (rs *rows) HasNextResultSet() bool {
+ hasNext := rs.next != nil && !rs.done
+ return hasNext
+}
+
+func (rs *rows) NextResultSet() error {
+ if rs.next == nil {
+ return io.EOF
+ }
+ rs.rowsHeader = *rs.next
+ rs.next = nil
+ return nil
+}
+
+// QuoteIdentifier quotes an "identifier" (e.g. a table or a column name) to be
+// used as part of an SQL statement. For example:
+//
+// tblname := "my_table"
+// data := "my_data"
+// quoted := pq.QuoteIdentifier(tblname)
+// err := db.Exec(fmt.Sprintf("INSERT INTO %s VALUES ($1)", quoted), data)
+//
+// Any double quotes in name will be escaped. The quoted identifier will be
+// case sensitive when used in a query. If the input string contains a zero
+// byte, the result will be truncated immediately before it.
+func QuoteIdentifier(name string) string {
+ end := strings.IndexRune(name, 0)
+ if end > -1 {
+ name = name[:end]
+ }
+ return `"` + strings.Replace(name, `"`, `""`, -1) + `"`
+}
+
+// BufferQuoteIdentifier satisfies the same purpose as QuoteIdentifier, but backed by a
+// byte buffer.
+func BufferQuoteIdentifier(name string, buffer *bytes.Buffer) {
+ end := strings.IndexRune(name, 0)
+ if end > -1 {
+ name = name[:end]
+ }
+ buffer.WriteRune('"')
+ buffer.WriteString(strings.Replace(name, `"`, `""`, -1))
+ buffer.WriteRune('"')
+}
+
+// QuoteLiteral quotes a 'literal' (e.g. a parameter, often used to pass literal
+// to DDL and other statements that do not accept parameters) to be used as part
+// of an SQL statement. For example:
+//
+// exp_date := pq.QuoteLiteral("2023-01-05 15:00:00Z")
+// err := db.Exec(fmt.Sprintf("CREATE ROLE my_user VALID UNTIL %s", exp_date))
+//
+// Any single quotes in name will be escaped. Any backslashes (i.e. "\") will be
+// replaced by two backslashes (i.e. "\\") and the C-style escape identifier
+// that PostgreSQL provides ('E') will be prepended to the string.
+func QuoteLiteral(literal string) string {
+ // This follows the PostgreSQL internal algorithm for handling quoted literals
+ // from libpq, which can be found in the "PQEscapeStringInternal" function,
+ // which is found in the libpq/fe-exec.c source file:
+ // https://git.postgresql.org/gitweb/?p=postgresql.git;a=blob;f=src/interfaces/libpq/fe-exec.c
+ //
+ // substitute any single-quotes (') with two single-quotes ('')
+ literal = strings.Replace(literal, `'`, `''`, -1)
+ // determine if the string has any backslashes (\) in it.
+ // if it does, replace any backslashes (\) with two backslashes (\\)
+ // then, we need to wrap the entire string with a PostgreSQL
+ // C-style escape. Per how "PQEscapeStringInternal" handles this case, we
+ // also add a space before the "E"
+ if strings.Contains(literal, `\`) {
+ literal = strings.Replace(literal, `\`, `\\`, -1)
+ literal = ` E'` + literal + `'`
+ } else {
+ // otherwise, we can just wrap the literal with a pair of single quotes
+ literal = `'` + literal + `'`
+ }
+ return literal
+}
+
+func md5s(s string) string {
+ h := md5.New()
+ h.Write([]byte(s))
+ return fmt.Sprintf("%x", h.Sum(nil))
+}
+
+func (cn *conn) sendBinaryParameters(b *writeBuf, args []driver.Value) {
+ // Do one pass over the parameters to see if we're going to send any of
+ // them over in binary. If we are, create a paramFormats array at the
+ // same time.
+ var paramFormats []int
+ for i, x := range args {
+ _, ok := x.([]byte)
+ if ok {
+ if paramFormats == nil {
+ paramFormats = make([]int, len(args))
+ }
+ paramFormats[i] = 1
+ }
+ }
+ if paramFormats == nil {
+ b.int16(0)
+ } else {
+ b.int16(len(paramFormats))
+ for _, x := range paramFormats {
+ b.int16(x)
+ }
+ }
+
+ b.int16(len(args))
+ for _, x := range args {
+ if x == nil {
+ b.int32(-1)
+ } else {
+ datum := binaryEncode(&cn.parameterStatus, x)
+ b.int32(len(datum))
+ b.bytes(datum)
+ }
+ }
+}
+
+func (cn *conn) sendBinaryModeQuery(query string, args []driver.Value) {
+ if len(args) >= 65536 {
+ errorf("got %d parameters but PostgreSQL only supports 65535 parameters", len(args))
+ }
+
+ b := cn.writeBuf('P')
+ b.byte(0) // unnamed statement
+ b.string(query)
+ b.int16(0)
+
+ b.next('B')
+ b.int16(0) // unnamed portal and statement
+ cn.sendBinaryParameters(b, args)
+ b.bytes(colFmtDataAllText)
+
+ b.next('D')
+ b.byte('P')
+ b.byte(0) // unnamed portal
+
+ b.next('E')
+ b.byte(0)
+ b.int32(0)
+
+ b.next('S')
+ cn.send(b)
+}
+
+func (cn *conn) processParameterStatus(r *readBuf) {
+ var err error
+
+ param := r.string()
+ switch param {
+ case "server_version":
+ var major1 int
+ var major2 int
+ _, err = fmt.Sscanf(r.string(), "%d.%d", &major1, &major2)
+ if err == nil {
+ cn.parameterStatus.serverVersion = major1*10000 + major2*100
+ }
+
+ case "TimeZone":
+ cn.parameterStatus.currentLocation, err = time.LoadLocation(r.string())
+ if err != nil {
+ cn.parameterStatus.currentLocation = nil
+ }
+
+ default:
+ // ignore
+ }
+}
+
+func (cn *conn) processReadyForQuery(r *readBuf) {
+ cn.txnStatus = transactionStatus(r.byte())
+}
+
+func (cn *conn) readReadyForQuery() {
+ t, r := cn.recv1()
+ switch t {
+ case 'Z':
+ cn.processReadyForQuery(r)
+ return
+ default:
+ cn.err.set(driver.ErrBadConn)
+ errorf("unexpected message %q; expected ReadyForQuery", t)
+ }
+}
+
+func (cn *conn) processBackendKeyData(r *readBuf) {
+ cn.processID = r.int32()
+ cn.secretKey = r.int32()
+}
+
+func (cn *conn) readParseResponse() {
+ t, r := cn.recv1()
+ switch t {
+ case '1':
+ return
+ case 'E':
+ err := parseError(r)
+ cn.readReadyForQuery()
+ panic(err)
+ default:
+ cn.err.set(driver.ErrBadConn)
+ errorf("unexpected Parse response %q", t)
+ }
+}
+
+func (cn *conn) readStatementDescribeResponse() (
+ paramTyps []oid.Oid,
+ colNames []string,
+ colTyps []fieldDesc,
+) {
+ for {
+ t, r := cn.recv1()
+ switch t {
+ case 't':
+ nparams := r.int16()
+ paramTyps = make([]oid.Oid, nparams)
+ for i := range paramTyps {
+ paramTyps[i] = r.oid()
+ }
+ case 'n':
+ return paramTyps, nil, nil
+ case 'T':
+ colNames, colTyps = parseStatementRowDescribe(r)
+ return paramTyps, colNames, colTyps
+ case 'E':
+ err := parseError(r)
+ cn.readReadyForQuery()
+ panic(err)
+ default:
+ cn.err.set(driver.ErrBadConn)
+ errorf("unexpected Describe statement response %q", t)
+ }
+ }
+}
+
+func (cn *conn) readPortalDescribeResponse() rowsHeader {
+ t, r := cn.recv1()
+ switch t {
+ case 'T':
+ return parsePortalRowDescribe(r)
+ case 'n':
+ return rowsHeader{}
+ case 'E':
+ err := parseError(r)
+ cn.readReadyForQuery()
+ panic(err)
+ default:
+ cn.err.set(driver.ErrBadConn)
+ errorf("unexpected Describe response %q", t)
+ }
+ panic("not reached")
+}
+
+func (cn *conn) readBindResponse() {
+ t, r := cn.recv1()
+ switch t {
+ case '2':
+ return
+ case 'E':
+ err := parseError(r)
+ cn.readReadyForQuery()
+ panic(err)
+ default:
+ cn.err.set(driver.ErrBadConn)
+ errorf("unexpected Bind response %q", t)
+ }
+}
+
+func (cn *conn) postExecuteWorkaround() {
+ // Work around a bug in sql.DB.QueryRow: in Go 1.2 and earlier it ignores
+ // any errors from rows.Next, which masks errors that happened during the
+ // execution of the query. To avoid the problem in common cases, we wait
+ // here for one more message from the database. If it's not an error the
+ // query will likely succeed (or perhaps has already, if it's a
+ // CommandComplete), so we push the message into the conn struct; recv1
+ // will return it as the next message for rows.Next or rows.Close.
+ // However, if it's an error, we wait until ReadyForQuery and then return
+ // the error to our caller.
+ for {
+ t, r := cn.recv1()
+ switch t {
+ case 'E':
+ err := parseError(r)
+ cn.readReadyForQuery()
+ panic(err)
+ case 'C', 'D', 'I':
+ // the query didn't fail, but we can't process this message
+ cn.saveMessage(t, r)
+ return
+ default:
+ cn.err.set(driver.ErrBadConn)
+ errorf("unexpected message during extended query execution: %q", t)
+ }
+ }
+}
+
+// Only for Exec(), since we ignore the returned data
+func (cn *conn) readExecuteResponse(
+ protocolState string,
+) (res driver.Result, commandTag string, err error) {
+ for {
+ t, r := cn.recv1()
+ switch t {
+ case 'C':
+ if err != nil {
+ cn.err.set(driver.ErrBadConn)
+ errorf("unexpected CommandComplete after error %s", err)
+ }
+ res, commandTag = cn.parseComplete(r.string())
+ case 'Z':
+ cn.processReadyForQuery(r)
+ if res == nil && err == nil {
+ err = errUnexpectedReady
+ }
+ return res, commandTag, err
+ case 'E':
+ err = parseError(r)
+ case 'T', 'D', 'I':
+ if err != nil {
+ cn.err.set(driver.ErrBadConn)
+ errorf("unexpected %q after error %s", t, err)
+ }
+ if t == 'I' {
+ res = emptyRows
+ }
+ // ignore any results
+ default:
+ cn.err.set(driver.ErrBadConn)
+ errorf("unknown %s response: %q", protocolState, t)
+ }
+ }
+}
+
+func parseStatementRowDescribe(r *readBuf) (colNames []string, colTyps []fieldDesc) {
+ n := r.int16()
+ colNames = make([]string, n)
+ colTyps = make([]fieldDesc, n)
+ for i := range colNames {
+ colNames[i] = r.string()
+ r.next(6)
+ colTyps[i].OID = r.oid()
+ colTyps[i].Len = r.int16()
+ colTyps[i].Mod = r.int32()
+ // format code not known when describing a statement; always 0
+ r.next(2)
+ }
+ return
+}
+
+func parsePortalRowDescribe(r *readBuf) rowsHeader {
+ n := r.int16()
+ colNames := make([]string, n)
+ colFmts := make([]format, n)
+ colTyps := make([]fieldDesc, n)
+ for i := range colNames {
+ colNames[i] = r.string()
+ r.next(6)
+ colTyps[i].OID = r.oid()
+ colTyps[i].Len = r.int16()
+ colTyps[i].Mod = r.int32()
+ colFmts[i] = format(r.int16())
+ }
+ return rowsHeader{
+ colNames: colNames,
+ colFmts: colFmts,
+ colTyps: colTyps,
+ }
+}
+
+// parseEnviron tries to mimic some of libpq's environment handling
+//
+// To ease testing, it does not directly reference os.Environ, but is
+// designed to accept its output.
+//
+// Environment-set connection information is intended to have a higher
+// precedence than a library default but lower than any explicitly
+// passed information (such as in the URL or connection string).
+func parseEnviron(env []string) (out map[string]string) {
+ out = make(map[string]string)
+
+ for _, v := range env {
+ parts := strings.SplitN(v, "=", 2)
+
+ accrue := func(keyname string) {
+ out[keyname] = parts[1]
+ }
+ unsupported := func() {
+ panic(fmt.Sprintf("setting %v not supported", parts[0]))
+ }
+
+ // The order of these is the same as is seen in the
+ // PostgreSQL 9.1 manual. Unsupported but well-defined
+ // keys cause a panic; these should be unset prior to
+ // execution. Options which pq expects to be set to a
+ // certain value are allowed, but must be set to that
+ // value if present (they can, of course, be absent).
+ switch parts[0] {
+ case "PGHOST":
+ accrue("host")
+ case "PGHOSTADDR":
+ unsupported()
+ case "PGPORT":
+ accrue("port")
+ case "PGDATABASE":
+ accrue("dbname")
+ case "PGUSER":
+ accrue("user")
+ case "PGPASSWORD":
+ accrue("password")
+ case "PGSERVICE", "PGSERVICEFILE", "PGREALM":
+ unsupported()
+ case "PGOPTIONS":
+ accrue("options")
+ case "PGAPPNAME":
+ accrue("application_name")
+ case "PGSSLMODE":
+ accrue("sslmode")
+ case "PGSSLCERT":
+ accrue("sslcert")
+ case "PGSSLKEY":
+ accrue("sslkey")
+ case "PGSSLROOTCERT":
+ accrue("sslrootcert")
+ case "PGSSLSNI":
+ accrue("sslsni")
+ case "PGREQUIRESSL", "PGSSLCRL":
+ unsupported()
+ case "PGREQUIREPEER":
+ unsupported()
+ case "PGKRBSRVNAME", "PGGSSLIB":
+ unsupported()
+ case "PGCONNECT_TIMEOUT":
+ accrue("connect_timeout")
+ case "PGCLIENTENCODING":
+ accrue("client_encoding")
+ case "PGDATESTYLE":
+ accrue("datestyle")
+ case "PGTZ":
+ accrue("timezone")
+ case "PGGEQO":
+ accrue("geqo")
+ case "PGSYSCONFDIR", "PGLOCALEDIR":
+ unsupported()
+ }
+ }
+
+ return out
+}
+
+// isUTF8 returns whether name is a fuzzy variation of the string "UTF-8".
+func isUTF8(name string) bool {
+ // Recognize all sorts of silly things as "UTF-8", like Postgres does
+ s := strings.Map(alnumLowerASCII, name)
+ return s == "utf8" || s == "unicode"
+}
+
+func alnumLowerASCII(ch rune) rune {
+ if 'A' <= ch && ch <= 'Z' {
+ return ch + ('a' - 'A')
+ }
+ if 'a' <= ch && ch <= 'z' || '0' <= ch && ch <= '9' {
+ return ch
+ }
+ return -1 // discard
+}
+
+// The database/sql/driver package says:
+// All Conn implementations should implement the following interfaces: Pinger, SessionResetter, and Validator.
+var _ driver.Pinger = &conn{}
+var _ driver.SessionResetter = &conn{}
+
+func (cn *conn) ResetSession(ctx context.Context) error {
+ // Ensure bad connections are reported: From database/sql/driver:
+ // If a connection is never returned to the connection pool but immediately reused, then
+ // ResetSession is called prior to reuse but IsValid is not called.
+ return cn.err.get()
+}
+
+func (cn *conn) IsValid() bool {
+ return cn.err.get() == nil
+}
diff --git a/vendor/github.com/lib/pq/conn_go115.go b/vendor/github.com/lib/pq/conn_go115.go
new file mode 100644
index 0000000..f4ef030
--- /dev/null
+++ b/vendor/github.com/lib/pq/conn_go115.go
@@ -0,0 +1,8 @@
+//go:build go1.15
+// +build go1.15
+
+package pq
+
+import "database/sql/driver"
+
+var _ driver.Validator = &conn{}
diff --git a/vendor/github.com/lib/pq/conn_go18.go b/vendor/github.com/lib/pq/conn_go18.go
new file mode 100644
index 0000000..63d4ca6
--- /dev/null
+++ b/vendor/github.com/lib/pq/conn_go18.go
@@ -0,0 +1,247 @@
+package pq
+
+import (
+ "context"
+ "database/sql"
+ "database/sql/driver"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "time"
+)
+
+const (
+ watchCancelDialContextTimeout = time.Second * 10
+)
+
+// Implement the "QueryerContext" interface
+func (cn *conn) QueryContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Rows, error) {
+ list := make([]driver.Value, len(args))
+ for i, nv := range args {
+ list[i] = nv.Value
+ }
+ finish := cn.watchCancel(ctx)
+ r, err := cn.query(query, list)
+ if err != nil {
+ if finish != nil {
+ finish()
+ }
+ return nil, err
+ }
+ r.finish = finish
+ return r, nil
+}
+
+// Implement the "ExecerContext" interface
+func (cn *conn) ExecContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Result, error) {
+ list := make([]driver.Value, len(args))
+ for i, nv := range args {
+ list[i] = nv.Value
+ }
+
+ if finish := cn.watchCancel(ctx); finish != nil {
+ defer finish()
+ }
+
+ return cn.Exec(query, list)
+}
+
+// Implement the "ConnPrepareContext" interface
+func (cn *conn) PrepareContext(ctx context.Context, query string) (driver.Stmt, error) {
+ if finish := cn.watchCancel(ctx); finish != nil {
+ defer finish()
+ }
+ return cn.Prepare(query)
+}
+
+// Implement the "ConnBeginTx" interface
+func (cn *conn) BeginTx(ctx context.Context, opts driver.TxOptions) (driver.Tx, error) {
+ var mode string
+
+ switch sql.IsolationLevel(opts.Isolation) {
+ case sql.LevelDefault:
+ // Don't touch mode: use the server's default
+ case sql.LevelReadUncommitted:
+ mode = " ISOLATION LEVEL READ UNCOMMITTED"
+ case sql.LevelReadCommitted:
+ mode = " ISOLATION LEVEL READ COMMITTED"
+ case sql.LevelRepeatableRead:
+ mode = " ISOLATION LEVEL REPEATABLE READ"
+ case sql.LevelSerializable:
+ mode = " ISOLATION LEVEL SERIALIZABLE"
+ default:
+ return nil, fmt.Errorf("pq: isolation level not supported: %d", opts.Isolation)
+ }
+
+ if opts.ReadOnly {
+ mode += " READ ONLY"
+ } else {
+ mode += " READ WRITE"
+ }
+
+ tx, err := cn.begin(mode)
+ if err != nil {
+ return nil, err
+ }
+ cn.txnFinish = cn.watchCancel(ctx)
+ return tx, nil
+}
+
+func (cn *conn) Ping(ctx context.Context) error {
+ if finish := cn.watchCancel(ctx); finish != nil {
+ defer finish()
+ }
+ rows, err := cn.simpleQuery(";")
+ if err != nil {
+ return driver.ErrBadConn // https://golang.org/pkg/database/sql/driver/#Pinger
+ }
+ rows.Close()
+ return nil
+}
+
+func (cn *conn) watchCancel(ctx context.Context) func() {
+ if done := ctx.Done(); done != nil {
+ finished := make(chan struct{}, 1)
+ go func() {
+ select {
+ case <-done:
+ select {
+ case finished <- struct{}{}:
+ default:
+ // We raced with the finish func, let the next query handle this with the
+ // context.
+ return
+ }
+
+ // Set the connection state to bad so it does not get reused.
+ cn.err.set(ctx.Err())
+
+ // At this point the function level context is canceled,
+ // so it must not be used for the additional network
+ // request to cancel the query.
+ // Create a new context to pass into the dial.
+ ctxCancel, cancel := context.WithTimeout(context.Background(), watchCancelDialContextTimeout)
+ defer cancel()
+
+ _ = cn.cancel(ctxCancel)
+ case <-finished:
+ }
+ }()
+ return func() {
+ select {
+ case <-finished:
+ cn.err.set(ctx.Err())
+ cn.Close()
+ case finished <- struct{}{}:
+ }
+ }
+ }
+ return nil
+}
+
+func (cn *conn) cancel(ctx context.Context) error {
+ // Create a new values map (copy). This makes sure the connection created
+ // in this method cannot write to the same underlying data, which could
+ // cause a concurrent map write panic. This is necessary because cancel
+ // is called from a goroutine in watchCancel.
+ o := make(values)
+ for k, v := range cn.opts {
+ o[k] = v
+ }
+
+ c, err := dial(ctx, cn.dialer, o)
+ if err != nil {
+ return err
+ }
+ defer c.Close()
+
+ {
+ can := conn{
+ c: c,
+ }
+ err = can.ssl(o)
+ if err != nil {
+ return err
+ }
+
+ w := can.writeBuf(0)
+ w.int32(80877102) // cancel request code
+ w.int32(cn.processID)
+ w.int32(cn.secretKey)
+
+ if err := can.sendStartupPacket(w); err != nil {
+ return err
+ }
+ }
+
+ // Read until EOF to ensure that the server received the cancel.
+ {
+ _, err := io.Copy(ioutil.Discard, c)
+ return err
+ }
+}
+
+// Implement the "StmtQueryContext" interface
+func (st *stmt) QueryContext(ctx context.Context, args []driver.NamedValue) (driver.Rows, error) {
+ list := make([]driver.Value, len(args))
+ for i, nv := range args {
+ list[i] = nv.Value
+ }
+ finish := st.watchCancel(ctx)
+ r, err := st.query(list)
+ if err != nil {
+ if finish != nil {
+ finish()
+ }
+ return nil, err
+ }
+ r.finish = finish
+ return r, nil
+}
+
+// Implement the "StmtExecContext" interface
+func (st *stmt) ExecContext(ctx context.Context, args []driver.NamedValue) (driver.Result, error) {
+ list := make([]driver.Value, len(args))
+ for i, nv := range args {
+ list[i] = nv.Value
+ }
+
+ if finish := st.watchCancel(ctx); finish != nil {
+ defer finish()
+ }
+
+ return st.Exec(list)
+}
+
+// watchCancel is implemented on stmt in order to not mark the parent conn as bad
+func (st *stmt) watchCancel(ctx context.Context) func() {
+ if done := ctx.Done(); done != nil {
+ finished := make(chan struct{})
+ go func() {
+ select {
+ case <-done:
+ // At this point the function level context is canceled,
+ // so it must not be used for the additional network
+ // request to cancel the query.
+ // Create a new context to pass into the dial.
+ ctxCancel, cancel := context.WithTimeout(context.Background(), watchCancelDialContextTimeout)
+ defer cancel()
+
+ _ = st.cancel(ctxCancel)
+ finished <- struct{}{}
+ case <-finished:
+ }
+ }()
+ return func() {
+ select {
+ case <-finished:
+ case finished <- struct{}{}:
+ }
+ }
+ }
+ return nil
+}
+
+func (st *stmt) cancel(ctx context.Context) error {
+ return st.cn.cancel(ctx)
+}
diff --git a/vendor/github.com/lib/pq/connector.go b/vendor/github.com/lib/pq/connector.go
new file mode 100644
index 0000000..1145e12
--- /dev/null
+++ b/vendor/github.com/lib/pq/connector.go
@@ -0,0 +1,120 @@
+package pq
+
+import (
+ "context"
+ "database/sql/driver"
+ "errors"
+ "fmt"
+ "os"
+ "strings"
+)
+
+// Connector represents a fixed configuration for the pq driver with a given
+// name. Connector satisfies the database/sql/driver Connector interface and
+// can be used to create any number of DB Conn's via the database/sql OpenDB
+// function.
+//
+// See https://golang.org/pkg/database/sql/driver/#Connector.
+// See https://golang.org/pkg/database/sql/#OpenDB.
+type Connector struct {
+ opts values
+ dialer Dialer
+}
+
+// Connect returns a connection to the database using the fixed configuration
+// of this Connector. Context is not used.
+func (c *Connector) Connect(ctx context.Context) (driver.Conn, error) {
+ return c.open(ctx)
+}
+
+// Dialer allows change the dialer used to open connections.
+func (c *Connector) Dialer(dialer Dialer) {
+ c.dialer = dialer
+}
+
+// Driver returns the underlying driver of this Connector.
+func (c *Connector) Driver() driver.Driver {
+ return &Driver{}
+}
+
+// NewConnector returns a connector for the pq driver in a fixed configuration
+// with the given dsn. The returned connector can be used to create any number
+// of equivalent Conn's. The returned connector is intended to be used with
+// database/sql.OpenDB.
+//
+// See https://golang.org/pkg/database/sql/driver/#Connector.
+// See https://golang.org/pkg/database/sql/#OpenDB.
+func NewConnector(dsn string) (*Connector, error) {
+ var err error
+ o := make(values)
+
+ // A number of defaults are applied here, in this order:
+ //
+ // * Very low precedence defaults applied in every situation
+ // * Environment variables
+ // * Explicitly passed connection information
+ o["host"] = "localhost"
+ o["port"] = "5432"
+ // N.B.: Extra float digits should be set to 3, but that breaks
+ // Postgres 8.4 and older, where the max is 2.
+ o["extra_float_digits"] = "2"
+ for k, v := range parseEnviron(os.Environ()) {
+ o[k] = v
+ }
+
+ if strings.HasPrefix(dsn, "postgres://") || strings.HasPrefix(dsn, "postgresql://") {
+ dsn, err = ParseURL(dsn)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ if err := parseOpts(dsn, o); err != nil {
+ return nil, err
+ }
+
+ // Use the "fallback" application name if necessary
+ if fallback, ok := o["fallback_application_name"]; ok {
+ if _, ok := o["application_name"]; !ok {
+ o["application_name"] = fallback
+ }
+ }
+
+ // We can't work with any client_encoding other than UTF-8 currently.
+ // However, we have historically allowed the user to set it to UTF-8
+ // explicitly, and there's no reason to break such programs, so allow that.
+ // Note that the "options" setting could also set client_encoding, but
+ // parsing its value is not worth it. Instead, we always explicitly send
+ // client_encoding as a separate run-time parameter, which should override
+ // anything set in options.
+ if enc, ok := o["client_encoding"]; ok && !isUTF8(enc) {
+ return nil, errors.New("client_encoding must be absent or 'UTF8'")
+ }
+ o["client_encoding"] = "UTF8"
+ // DateStyle needs a similar treatment.
+ if datestyle, ok := o["datestyle"]; ok {
+ if datestyle != "ISO, MDY" {
+ return nil, fmt.Errorf("setting datestyle must be absent or %v; got %v", "ISO, MDY", datestyle)
+ }
+ } else {
+ o["datestyle"] = "ISO, MDY"
+ }
+
+ // If a user is not provided by any other means, the last
+ // resort is to use the current operating system provided user
+ // name.
+ if _, ok := o["user"]; !ok {
+ u, err := userCurrent()
+ if err != nil {
+ return nil, err
+ }
+ o["user"] = u
+ }
+
+ // SSL is not necessary or supported over UNIX domain sockets
+ if network, _ := network(o); network == "unix" {
+ o["sslmode"] = "disable"
+ }
+
+ return &Connector{opts: o, dialer: defaultDialer{}}, nil
+}
diff --git a/vendor/github.com/lib/pq/copy.go b/vendor/github.com/lib/pq/copy.go
new file mode 100644
index 0000000..a8f16b2
--- /dev/null
+++ b/vendor/github.com/lib/pq/copy.go
@@ -0,0 +1,348 @@
+package pq
+
+import (
+ "bytes"
+ "context"
+ "database/sql/driver"
+ "encoding/binary"
+ "errors"
+ "fmt"
+ "sync"
+)
+
+var (
+ errCopyInClosed = errors.New("pq: copyin statement has already been closed")
+ errBinaryCopyNotSupported = errors.New("pq: only text format supported for COPY")
+ errCopyToNotSupported = errors.New("pq: COPY TO is not supported")
+ errCopyNotSupportedOutsideTxn = errors.New("pq: COPY is only allowed inside a transaction")
+ errCopyInProgress = errors.New("pq: COPY in progress")
+)
+
+// CopyIn creates a COPY FROM statement which can be prepared with
+// Tx.Prepare(). The target table should be visible in search_path.
+func CopyIn(table string, columns ...string) string {
+ buffer := bytes.NewBufferString("COPY ")
+ BufferQuoteIdentifier(table, buffer)
+ buffer.WriteString(" (")
+ makeStmt(buffer, columns...)
+ return buffer.String()
+}
+
+// MakeStmt makes the stmt string for CopyIn and CopyInSchema.
+func makeStmt(buffer *bytes.Buffer, columns ...string) {
+ //s := bytes.NewBufferString()
+ for i, col := range columns {
+ if i != 0 {
+ buffer.WriteString(", ")
+ }
+ BufferQuoteIdentifier(col, buffer)
+ }
+ buffer.WriteString(") FROM STDIN")
+}
+
+// CopyInSchema creates a COPY FROM statement which can be prepared with
+// Tx.Prepare().
+func CopyInSchema(schema, table string, columns ...string) string {
+ buffer := bytes.NewBufferString("COPY ")
+ BufferQuoteIdentifier(schema, buffer)
+ buffer.WriteRune('.')
+ BufferQuoteIdentifier(table, buffer)
+ buffer.WriteString(" (")
+ makeStmt(buffer, columns...)
+ return buffer.String()
+}
+
+type copyin struct {
+ cn *conn
+ buffer []byte
+ rowData chan []byte
+ done chan bool
+
+ closed bool
+
+ mu struct {
+ sync.Mutex
+ err error
+ driver.Result
+ }
+}
+
+const ciBufferSize = 64 * 1024
+
+// flush buffer before the buffer is filled up and needs reallocation
+const ciBufferFlushSize = 63 * 1024
+
+func (cn *conn) prepareCopyIn(q string) (_ driver.Stmt, err error) {
+ if !cn.isInTransaction() {
+ return nil, errCopyNotSupportedOutsideTxn
+ }
+
+ ci := ©in{
+ cn: cn,
+ buffer: make([]byte, 0, ciBufferSize),
+ rowData: make(chan []byte),
+ done: make(chan bool, 1),
+ }
+ // add CopyData identifier + 4 bytes for message length
+ ci.buffer = append(ci.buffer, 'd', 0, 0, 0, 0)
+
+ b := cn.writeBuf('Q')
+ b.string(q)
+ cn.send(b)
+
+awaitCopyInResponse:
+ for {
+ t, r := cn.recv1()
+ switch t {
+ case 'G':
+ if r.byte() != 0 {
+ err = errBinaryCopyNotSupported
+ break awaitCopyInResponse
+ }
+ go ci.resploop()
+ return ci, nil
+ case 'H':
+ err = errCopyToNotSupported
+ break awaitCopyInResponse
+ case 'E':
+ err = parseError(r)
+ case 'Z':
+ if err == nil {
+ ci.setBad(driver.ErrBadConn)
+ errorf("unexpected ReadyForQuery in response to COPY")
+ }
+ cn.processReadyForQuery(r)
+ return nil, err
+ default:
+ ci.setBad(driver.ErrBadConn)
+ errorf("unknown response for copy query: %q", t)
+ }
+ }
+
+ // something went wrong, abort COPY before we return
+ b = cn.writeBuf('f')
+ b.string(err.Error())
+ cn.send(b)
+
+ for {
+ t, r := cn.recv1()
+ switch t {
+ case 'c', 'C', 'E':
+ case 'Z':
+ // correctly aborted, we're done
+ cn.processReadyForQuery(r)
+ return nil, err
+ default:
+ ci.setBad(driver.ErrBadConn)
+ errorf("unknown response for CopyFail: %q", t)
+ }
+ }
+}
+
+func (ci *copyin) flush(buf []byte) {
+ // set message length (without message identifier)
+ binary.BigEndian.PutUint32(buf[1:], uint32(len(buf)-1))
+
+ _, err := ci.cn.c.Write(buf)
+ if err != nil {
+ panic(err)
+ }
+}
+
+func (ci *copyin) resploop() {
+ for {
+ var r readBuf
+ t, err := ci.cn.recvMessage(&r)
+ if err != nil {
+ ci.setBad(driver.ErrBadConn)
+ ci.setError(err)
+ ci.done <- true
+ return
+ }
+ switch t {
+ case 'C':
+ // complete
+ res, _ := ci.cn.parseComplete(r.string())
+ ci.setResult(res)
+ case 'N':
+ if n := ci.cn.noticeHandler; n != nil {
+ n(parseError(&r))
+ }
+ case 'Z':
+ ci.cn.processReadyForQuery(&r)
+ ci.done <- true
+ return
+ case 'E':
+ err := parseError(&r)
+ ci.setError(err)
+ default:
+ ci.setBad(driver.ErrBadConn)
+ ci.setError(fmt.Errorf("unknown response during CopyIn: %q", t))
+ ci.done <- true
+ return
+ }
+ }
+}
+
+func (ci *copyin) setBad(err error) {
+ ci.cn.err.set(err)
+}
+
+func (ci *copyin) getBad() error {
+ return ci.cn.err.get()
+}
+
+func (ci *copyin) err() error {
+ ci.mu.Lock()
+ err := ci.mu.err
+ ci.mu.Unlock()
+ return err
+}
+
+// setError() sets ci.err if one has not been set already. Caller must not be
+// holding ci.Mutex.
+func (ci *copyin) setError(err error) {
+ ci.mu.Lock()
+ if ci.mu.err == nil {
+ ci.mu.err = err
+ }
+ ci.mu.Unlock()
+}
+
+func (ci *copyin) setResult(result driver.Result) {
+ ci.mu.Lock()
+ ci.mu.Result = result
+ ci.mu.Unlock()
+}
+
+func (ci *copyin) getResult() driver.Result {
+ ci.mu.Lock()
+ result := ci.mu.Result
+ ci.mu.Unlock()
+ if result == nil {
+ return driver.RowsAffected(0)
+ }
+ return result
+}
+
+func (ci *copyin) NumInput() int {
+ return -1
+}
+
+func (ci *copyin) Query(v []driver.Value) (r driver.Rows, err error) {
+ return nil, ErrNotSupported
+}
+
+// Exec inserts values into the COPY stream. The insert is asynchronous
+// and Exec can return errors from previous Exec calls to the same
+// COPY stmt.
+//
+// You need to call Exec(nil) to sync the COPY stream and to get any
+// errors from pending data, since Stmt.Close() doesn't return errors
+// to the user.
+func (ci *copyin) Exec(v []driver.Value) (r driver.Result, err error) {
+ if ci.closed {
+ return nil, errCopyInClosed
+ }
+
+ if err := ci.getBad(); err != nil {
+ return nil, err
+ }
+ defer ci.cn.errRecover(&err)
+
+ if err := ci.err(); err != nil {
+ return nil, err
+ }
+
+ if len(v) == 0 {
+ if err := ci.Close(); err != nil {
+ return driver.RowsAffected(0), err
+ }
+
+ return ci.getResult(), nil
+ }
+
+ numValues := len(v)
+ for i, value := range v {
+ ci.buffer = appendEncodedText(&ci.cn.parameterStatus, ci.buffer, value)
+ if i < numValues-1 {
+ ci.buffer = append(ci.buffer, '\t')
+ }
+ }
+
+ ci.buffer = append(ci.buffer, '\n')
+
+ if len(ci.buffer) > ciBufferFlushSize {
+ ci.flush(ci.buffer)
+ // reset buffer, keep bytes for message identifier and length
+ ci.buffer = ci.buffer[:5]
+ }
+
+ return driver.RowsAffected(0), nil
+}
+
+// CopyData inserts a raw string into the COPY stream. The insert is
+// asynchronous and CopyData can return errors from previous CopyData calls to
+// the same COPY stmt.
+//
+// You need to call Exec(nil) to sync the COPY stream and to get any
+// errors from pending data, since Stmt.Close() doesn't return errors
+// to the user.
+func (ci *copyin) CopyData(ctx context.Context, line string) (r driver.Result, err error) {
+ if ci.closed {
+ return nil, errCopyInClosed
+ }
+
+ if finish := ci.cn.watchCancel(ctx); finish != nil {
+ defer finish()
+ }
+
+ if err := ci.getBad(); err != nil {
+ return nil, err
+ }
+ defer ci.cn.errRecover(&err)
+
+ if err := ci.err(); err != nil {
+ return nil, err
+ }
+
+ ci.buffer = append(ci.buffer, []byte(line)...)
+ ci.buffer = append(ci.buffer, '\n')
+
+ if len(ci.buffer) > ciBufferFlushSize {
+ ci.flush(ci.buffer)
+ // reset buffer, keep bytes for message identifier and length
+ ci.buffer = ci.buffer[:5]
+ }
+
+ return driver.RowsAffected(0), nil
+}
+
+func (ci *copyin) Close() (err error) {
+ if ci.closed { // Don't do anything, we're already closed
+ return nil
+ }
+ ci.closed = true
+
+ if err := ci.getBad(); err != nil {
+ return err
+ }
+ defer ci.cn.errRecover(&err)
+
+ if len(ci.buffer) > 0 {
+ ci.flush(ci.buffer)
+ }
+ // Avoid touching the scratch buffer as resploop could be using it.
+ err = ci.cn.sendSimpleMessage('c')
+ if err != nil {
+ return err
+ }
+
+ <-ci.done
+ ci.cn.inCopy = false
+
+ if err := ci.err(); err != nil {
+ return err
+ }
+ return nil
+}
diff --git a/vendor/github.com/lib/pq/doc.go b/vendor/github.com/lib/pq/doc.go
new file mode 100644
index 0000000..b571848
--- /dev/null
+++ b/vendor/github.com/lib/pq/doc.go
@@ -0,0 +1,268 @@
+/*
+Package pq is a pure Go Postgres driver for the database/sql package.
+
+In most cases clients will use the database/sql package instead of
+using this package directly. For example:
+
+ import (
+ "database/sql"
+
+ _ "github.com/lib/pq"
+ )
+
+ func main() {
+ connStr := "user=pqgotest dbname=pqgotest sslmode=verify-full"
+ db, err := sql.Open("postgres", connStr)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ age := 21
+ rows, err := db.Query("SELECT name FROM users WHERE age = $1", age)
+ …
+ }
+
+You can also connect to a database using a URL. For example:
+
+ connStr := "postgres://pqgotest:password@localhost/pqgotest?sslmode=verify-full"
+ db, err := sql.Open("postgres", connStr)
+
+
+Connection String Parameters
+
+
+Similarly to libpq, when establishing a connection using pq you are expected to
+supply a connection string containing zero or more parameters.
+A subset of the connection parameters supported by libpq are also supported by pq.
+Additionally, pq also lets you specify run-time parameters (such as search_path or work_mem)
+directly in the connection string. This is different from libpq, which does not allow
+run-time parameters in the connection string, instead requiring you to supply
+them in the options parameter.
+
+For compatibility with libpq, the following special connection parameters are
+supported:
+
+ * dbname - The name of the database to connect to
+ * user - The user to sign in as
+ * password - The user's password
+ * host - The host to connect to. Values that start with / are for unix
+ domain sockets. (default is localhost)
+ * port - The port to bind to. (default is 5432)
+ * sslmode - Whether or not to use SSL (default is require, this is not
+ the default for libpq)
+ * fallback_application_name - An application_name to fall back to if one isn't provided.
+ * connect_timeout - Maximum wait for connection, in seconds. Zero or
+ not specified means wait indefinitely.
+ * sslcert - Cert file location. The file must contain PEM encoded data.
+ * sslkey - Key file location. The file must contain PEM encoded data.
+ * sslrootcert - The location of the root certificate file. The file
+ must contain PEM encoded data.
+
+Valid values for sslmode are:
+
+ * disable - No SSL
+ * require - Always SSL (skip verification)
+ * verify-ca - Always SSL (verify that the certificate presented by the
+ server was signed by a trusted CA)
+ * verify-full - Always SSL (verify that the certification presented by
+ the server was signed by a trusted CA and the server host name
+ matches the one in the certificate)
+
+See http://www.postgresql.org/docs/current/static/libpq-connect.html#LIBPQ-CONNSTRING
+for more information about connection string parameters.
+
+Use single quotes for values that contain whitespace:
+
+ "user=pqgotest password='with spaces'"
+
+A backslash will escape the next character in values:
+
+ "user=space\ man password='it\'s valid'"
+
+Note that the connection parameter client_encoding (which sets the
+text encoding for the connection) may be set but must be "UTF8",
+matching with the same rules as Postgres. It is an error to provide
+any other value.
+
+In addition to the parameters listed above, any run-time parameter that can be
+set at backend start time can be set in the connection string. For more
+information, see
+http://www.postgresql.org/docs/current/static/runtime-config.html.
+
+Most environment variables as specified at http://www.postgresql.org/docs/current/static/libpq-envars.html
+supported by libpq are also supported by pq. If any of the environment
+variables not supported by pq are set, pq will panic during connection
+establishment. Environment variables have a lower precedence than explicitly
+provided connection parameters.
+
+The pgpass mechanism as described in http://www.postgresql.org/docs/current/static/libpq-pgpass.html
+is supported, but on Windows PGPASSFILE must be specified explicitly.
+
+
+Queries
+
+
+database/sql does not dictate any specific format for parameter
+markers in query strings, and pq uses the Postgres-native ordinal markers,
+as shown above. The same marker can be reused for the same parameter:
+
+ rows, err := db.Query(`SELECT name FROM users WHERE favorite_fruit = $1
+ OR age BETWEEN $2 AND $2 + 3`, "orange", 64)
+
+pq does not support the LastInsertId() method of the Result type in database/sql.
+To return the identifier of an INSERT (or UPDATE or DELETE), use the Postgres
+RETURNING clause with a standard Query or QueryRow call:
+
+ var userid int
+ err := db.QueryRow(`INSERT INTO users(name, favorite_fruit, age)
+ VALUES('beatrice', 'starfruit', 93) RETURNING id`).Scan(&userid)
+
+For more details on RETURNING, see the Postgres documentation:
+
+ http://www.postgresql.org/docs/current/static/sql-insert.html
+ http://www.postgresql.org/docs/current/static/sql-update.html
+ http://www.postgresql.org/docs/current/static/sql-delete.html
+
+For additional instructions on querying see the documentation for the database/sql package.
+
+
+Data Types
+
+
+Parameters pass through driver.DefaultParameterConverter before they are handled
+by this package. When the binary_parameters connection option is enabled,
+[]byte values are sent directly to the backend as data in binary format.
+
+This package returns the following types for values from the PostgreSQL backend:
+
+ - integer types smallint, integer, and bigint are returned as int64
+ - floating-point types real and double precision are returned as float64
+ - character types char, varchar, and text are returned as string
+ - temporal types date, time, timetz, timestamp, and timestamptz are
+ returned as time.Time
+ - the boolean type is returned as bool
+ - the bytea type is returned as []byte
+
+All other types are returned directly from the backend as []byte values in text format.
+
+
+Errors
+
+
+pq may return errors of type *pq.Error which can be interrogated for error details:
+
+ if err, ok := err.(*pq.Error); ok {
+ fmt.Println("pq error:", err.Code.Name())
+ }
+
+See the pq.Error type for details.
+
+
+Bulk imports
+
+You can perform bulk imports by preparing a statement returned by pq.CopyIn (or
+pq.CopyInSchema) in an explicit transaction (sql.Tx). The returned statement
+handle can then be repeatedly "executed" to copy data into the target table.
+After all data has been processed you should call Exec() once with no arguments
+to flush all buffered data. Any call to Exec() might return an error which
+should be handled appropriately, but because of the internal buffering an error
+returned by Exec() might not be related to the data passed in the call that
+failed.
+
+CopyIn uses COPY FROM internally. It is not possible to COPY outside of an
+explicit transaction in pq.
+
+Usage example:
+
+ txn, err := db.Begin()
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ stmt, err := txn.Prepare(pq.CopyIn("users", "name", "age"))
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ for _, user := range users {
+ _, err = stmt.Exec(user.Name, int64(user.Age))
+ if err != nil {
+ log.Fatal(err)
+ }
+ }
+
+ _, err = stmt.Exec()
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ err = stmt.Close()
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ err = txn.Commit()
+ if err != nil {
+ log.Fatal(err)
+ }
+
+
+Notifications
+
+
+PostgreSQL supports a simple publish/subscribe model over database
+connections. See http://www.postgresql.org/docs/current/static/sql-notify.html
+for more information about the general mechanism.
+
+To start listening for notifications, you first have to open a new connection
+to the database by calling NewListener. This connection can not be used for
+anything other than LISTEN / NOTIFY. Calling Listen will open a "notification
+channel"; once a notification channel is open, a notification generated on that
+channel will effect a send on the Listener.Notify channel. A notification
+channel will remain open until Unlisten is called, though connection loss might
+result in some notifications being lost. To solve this problem, Listener sends
+a nil pointer over the Notify channel any time the connection is re-established
+following a connection loss. The application can get information about the
+state of the underlying connection by setting an event callback in the call to
+NewListener.
+
+A single Listener can safely be used from concurrent goroutines, which means
+that there is often no need to create more than one Listener in your
+application. However, a Listener is always connected to a single database, so
+you will need to create a new Listener instance for every database you want to
+receive notifications in.
+
+The channel name in both Listen and Unlisten is case sensitive, and can contain
+any characters legal in an identifier (see
+http://www.postgresql.org/docs/current/static/sql-syntax-lexical.html#SQL-SYNTAX-IDENTIFIERS
+for more information). Note that the channel name will be truncated to 63
+bytes by the PostgreSQL server.
+
+You can find a complete, working example of Listener usage at
+https://godoc.org/github.com/lib/pq/example/listen.
+
+
+Kerberos Support
+
+
+If you need support for Kerberos authentication, add the following to your main
+package:
+
+ import "github.com/lib/pq/auth/kerberos"
+
+ func init() {
+ pq.RegisterGSSProvider(func() (pq.Gss, error) { return kerberos.NewGSS() })
+ }
+
+This package is in a separate module so that users who don't need Kerberos
+don't have to download unnecessary dependencies.
+
+When imported, additional connection string parameters are supported:
+
+ * krbsrvname - GSS (Kerberos) service name when constructing the
+ SPN (default is `postgres`). This will be combined with the host
+ to form the full SPN: `krbsrvname/host`.
+ * krbspn - GSS (Kerberos) SPN. This takes priority over
+ `krbsrvname` if present.
+*/
+package pq
diff --git a/vendor/github.com/lib/pq/encode.go b/vendor/github.com/lib/pq/encode.go
new file mode 100644
index 0000000..bffe609
--- /dev/null
+++ b/vendor/github.com/lib/pq/encode.go
@@ -0,0 +1,632 @@
+package pq
+
+import (
+ "bytes"
+ "database/sql/driver"
+ "encoding/binary"
+ "encoding/hex"
+ "errors"
+ "fmt"
+ "math"
+ "regexp"
+ "strconv"
+ "strings"
+ "sync"
+ "time"
+
+ "github.com/lib/pq/oid"
+)
+
+var time2400Regex = regexp.MustCompile(`^(24:00(?::00(?:\.0+)?)?)(?:[Z+-].*)?$`)
+
+func binaryEncode(parameterStatus *parameterStatus, x interface{}) []byte {
+ switch v := x.(type) {
+ case []byte:
+ return v
+ default:
+ return encode(parameterStatus, x, oid.T_unknown)
+ }
+}
+
+func encode(parameterStatus *parameterStatus, x interface{}, pgtypOid oid.Oid) []byte {
+ switch v := x.(type) {
+ case int64:
+ return strconv.AppendInt(nil, v, 10)
+ case float64:
+ return strconv.AppendFloat(nil, v, 'f', -1, 64)
+ case []byte:
+ if pgtypOid == oid.T_bytea {
+ return encodeBytea(parameterStatus.serverVersion, v)
+ }
+
+ return v
+ case string:
+ if pgtypOid == oid.T_bytea {
+ return encodeBytea(parameterStatus.serverVersion, []byte(v))
+ }
+
+ return []byte(v)
+ case bool:
+ return strconv.AppendBool(nil, v)
+ case time.Time:
+ return formatTs(v)
+
+ default:
+ errorf("encode: unknown type for %T", v)
+ }
+
+ panic("not reached")
+}
+
+func decode(parameterStatus *parameterStatus, s []byte, typ oid.Oid, f format) interface{} {
+ switch f {
+ case formatBinary:
+ return binaryDecode(parameterStatus, s, typ)
+ case formatText:
+ return textDecode(parameterStatus, s, typ)
+ default:
+ panic("not reached")
+ }
+}
+
+func binaryDecode(parameterStatus *parameterStatus, s []byte, typ oid.Oid) interface{} {
+ switch typ {
+ case oid.T_bytea:
+ return s
+ case oid.T_int8:
+ return int64(binary.BigEndian.Uint64(s))
+ case oid.T_int4:
+ return int64(int32(binary.BigEndian.Uint32(s)))
+ case oid.T_int2:
+ return int64(int16(binary.BigEndian.Uint16(s)))
+ case oid.T_uuid:
+ b, err := decodeUUIDBinary(s)
+ if err != nil {
+ panic(err)
+ }
+ return b
+
+ default:
+ errorf("don't know how to decode binary parameter of type %d", uint32(typ))
+ }
+
+ panic("not reached")
+}
+
+func textDecode(parameterStatus *parameterStatus, s []byte, typ oid.Oid) interface{} {
+ switch typ {
+ case oid.T_char, oid.T_varchar, oid.T_text:
+ return string(s)
+ case oid.T_bytea:
+ b, err := parseBytea(s)
+ if err != nil {
+ errorf("%s", err)
+ }
+ return b
+ case oid.T_timestamptz:
+ return parseTs(parameterStatus.currentLocation, string(s))
+ case oid.T_timestamp, oid.T_date:
+ return parseTs(nil, string(s))
+ case oid.T_time:
+ return mustParse("15:04:05", typ, s)
+ case oid.T_timetz:
+ return mustParse("15:04:05-07", typ, s)
+ case oid.T_bool:
+ return s[0] == 't'
+ case oid.T_int8, oid.T_int4, oid.T_int2:
+ i, err := strconv.ParseInt(string(s), 10, 64)
+ if err != nil {
+ errorf("%s", err)
+ }
+ return i
+ case oid.T_float4, oid.T_float8:
+ // We always use 64 bit parsing, regardless of whether the input text is for
+ // a float4 or float8, because clients expect float64s for all float datatypes
+ // and returning a 32-bit parsed float64 produces lossy results.
+ f, err := strconv.ParseFloat(string(s), 64)
+ if err != nil {
+ errorf("%s", err)
+ }
+ return f
+ }
+
+ return s
+}
+
+// appendEncodedText encodes item in text format as required by COPY
+// and appends to buf
+func appendEncodedText(parameterStatus *parameterStatus, buf []byte, x interface{}) []byte {
+ switch v := x.(type) {
+ case int64:
+ return strconv.AppendInt(buf, v, 10)
+ case float64:
+ return strconv.AppendFloat(buf, v, 'f', -1, 64)
+ case []byte:
+ encodedBytea := encodeBytea(parameterStatus.serverVersion, v)
+ return appendEscapedText(buf, string(encodedBytea))
+ case string:
+ return appendEscapedText(buf, v)
+ case bool:
+ return strconv.AppendBool(buf, v)
+ case time.Time:
+ return append(buf, formatTs(v)...)
+ case nil:
+ return append(buf, "\\N"...)
+ default:
+ errorf("encode: unknown type for %T", v)
+ }
+
+ panic("not reached")
+}
+
+func appendEscapedText(buf []byte, text string) []byte {
+ escapeNeeded := false
+ startPos := 0
+ var c byte
+
+ // check if we need to escape
+ for i := 0; i < len(text); i++ {
+ c = text[i]
+ if c == '\\' || c == '\n' || c == '\r' || c == '\t' {
+ escapeNeeded = true
+ startPos = i
+ break
+ }
+ }
+ if !escapeNeeded {
+ return append(buf, text...)
+ }
+
+ // copy till first char to escape, iterate the rest
+ result := append(buf, text[:startPos]...)
+ for i := startPos; i < len(text); i++ {
+ c = text[i]
+ switch c {
+ case '\\':
+ result = append(result, '\\', '\\')
+ case '\n':
+ result = append(result, '\\', 'n')
+ case '\r':
+ result = append(result, '\\', 'r')
+ case '\t':
+ result = append(result, '\\', 't')
+ default:
+ result = append(result, c)
+ }
+ }
+ return result
+}
+
+func mustParse(f string, typ oid.Oid, s []byte) time.Time {
+ str := string(s)
+
+ // Check for a minute and second offset in the timezone.
+ if typ == oid.T_timestamptz || typ == oid.T_timetz {
+ for i := 3; i <= 6; i += 3 {
+ if str[len(str)-i] == ':' {
+ f += ":00"
+ continue
+ }
+ break
+ }
+ }
+
+ // Special case for 24:00 time.
+ // Unfortunately, golang does not parse 24:00 as a proper time.
+ // In this case, we want to try "round to the next day", to differentiate.
+ // As such, we find if the 24:00 time matches at the beginning; if so,
+ // we default it back to 00:00 but add a day later.
+ var is2400Time bool
+ switch typ {
+ case oid.T_timetz, oid.T_time:
+ if matches := time2400Regex.FindStringSubmatch(str); matches != nil {
+ // Concatenate timezone information at the back.
+ str = "00:00:00" + str[len(matches[1]):]
+ is2400Time = true
+ }
+ }
+ t, err := time.Parse(f, str)
+ if err != nil {
+ errorf("decode: %s", err)
+ }
+ if is2400Time {
+ t = t.Add(24 * time.Hour)
+ }
+ return t
+}
+
+var errInvalidTimestamp = errors.New("invalid timestamp")
+
+type timestampParser struct {
+ err error
+}
+
+func (p *timestampParser) expect(str string, char byte, pos int) {
+ if p.err != nil {
+ return
+ }
+ if pos+1 > len(str) {
+ p.err = errInvalidTimestamp
+ return
+ }
+ if c := str[pos]; c != char && p.err == nil {
+ p.err = fmt.Errorf("expected '%v' at position %v; got '%v'", char, pos, c)
+ }
+}
+
+func (p *timestampParser) mustAtoi(str string, begin int, end int) int {
+ if p.err != nil {
+ return 0
+ }
+ if begin < 0 || end < 0 || begin > end || end > len(str) {
+ p.err = errInvalidTimestamp
+ return 0
+ }
+ result, err := strconv.Atoi(str[begin:end])
+ if err != nil {
+ if p.err == nil {
+ p.err = fmt.Errorf("expected number; got '%v'", str)
+ }
+ return 0
+ }
+ return result
+}
+
+// The location cache caches the time zones typically used by the client.
+type locationCache struct {
+ cache map[int]*time.Location
+ lock sync.Mutex
+}
+
+// All connections share the same list of timezones. Benchmarking shows that
+// about 5% speed could be gained by putting the cache in the connection and
+// losing the mutex, at the cost of a small amount of memory and a somewhat
+// significant increase in code complexity.
+var globalLocationCache = newLocationCache()
+
+func newLocationCache() *locationCache {
+ return &locationCache{cache: make(map[int]*time.Location)}
+}
+
+// Returns the cached timezone for the specified offset, creating and caching
+// it if necessary.
+func (c *locationCache) getLocation(offset int) *time.Location {
+ c.lock.Lock()
+ defer c.lock.Unlock()
+
+ location, ok := c.cache[offset]
+ if !ok {
+ location = time.FixedZone("", offset)
+ c.cache[offset] = location
+ }
+
+ return location
+}
+
+var infinityTsEnabled = false
+var infinityTsNegative time.Time
+var infinityTsPositive time.Time
+
+const (
+ infinityTsEnabledAlready = "pq: infinity timestamp enabled already"
+ infinityTsNegativeMustBeSmaller = "pq: infinity timestamp: negative value must be smaller (before) than positive"
+)
+
+// EnableInfinityTs controls the handling of Postgres' "-infinity" and
+// "infinity" "timestamp"s.
+//
+// If EnableInfinityTs is not called, "-infinity" and "infinity" will return
+// []byte("-infinity") and []byte("infinity") respectively, and potentially
+// cause error "sql: Scan error on column index 0: unsupported driver -> Scan
+// pair: []uint8 -> *time.Time", when scanning into a time.Time value.
+//
+// Once EnableInfinityTs has been called, all connections created using this
+// driver will decode Postgres' "-infinity" and "infinity" for "timestamp",
+// "timestamp with time zone" and "date" types to the predefined minimum and
+// maximum times, respectively. When encoding time.Time values, any time which
+// equals or precedes the predefined minimum time will be encoded to
+// "-infinity". Any values at or past the maximum time will similarly be
+// encoded to "infinity".
+//
+// If EnableInfinityTs is called with negative >= positive, it will panic.
+// Calling EnableInfinityTs after a connection has been established results in
+// undefined behavior. If EnableInfinityTs is called more than once, it will
+// panic.
+func EnableInfinityTs(negative time.Time, positive time.Time) {
+ if infinityTsEnabled {
+ panic(infinityTsEnabledAlready)
+ }
+ if !negative.Before(positive) {
+ panic(infinityTsNegativeMustBeSmaller)
+ }
+ infinityTsEnabled = true
+ infinityTsNegative = negative
+ infinityTsPositive = positive
+}
+
+/*
+ * Testing might want to toggle infinityTsEnabled
+ */
+func disableInfinityTs() {
+ infinityTsEnabled = false
+}
+
+// This is a time function specific to the Postgres default DateStyle
+// setting ("ISO, MDY"), the only one we currently support. This
+// accounts for the discrepancies between the parsing available with
+// time.Parse and the Postgres date formatting quirks.
+func parseTs(currentLocation *time.Location, str string) interface{} {
+ switch str {
+ case "-infinity":
+ if infinityTsEnabled {
+ return infinityTsNegative
+ }
+ return []byte(str)
+ case "infinity":
+ if infinityTsEnabled {
+ return infinityTsPositive
+ }
+ return []byte(str)
+ }
+ t, err := ParseTimestamp(currentLocation, str)
+ if err != nil {
+ panic(err)
+ }
+ return t
+}
+
+// ParseTimestamp parses Postgres' text format. It returns a time.Time in
+// currentLocation iff that time's offset agrees with the offset sent from the
+// Postgres server. Otherwise, ParseTimestamp returns a time.Time with the
+// fixed offset offset provided by the Postgres server.
+func ParseTimestamp(currentLocation *time.Location, str string) (time.Time, error) {
+ p := timestampParser{}
+
+ monSep := strings.IndexRune(str, '-')
+ // this is Gregorian year, not ISO Year
+ // In Gregorian system, the year 1 BC is followed by AD 1
+ year := p.mustAtoi(str, 0, monSep)
+ daySep := monSep + 3
+ month := p.mustAtoi(str, monSep+1, daySep)
+ p.expect(str, '-', daySep)
+ timeSep := daySep + 3
+ day := p.mustAtoi(str, daySep+1, timeSep)
+
+ minLen := monSep + len("01-01") + 1
+
+ isBC := strings.HasSuffix(str, " BC")
+ if isBC {
+ minLen += 3
+ }
+
+ var hour, minute, second int
+ if len(str) > minLen {
+ p.expect(str, ' ', timeSep)
+ minSep := timeSep + 3
+ p.expect(str, ':', minSep)
+ hour = p.mustAtoi(str, timeSep+1, minSep)
+ secSep := minSep + 3
+ p.expect(str, ':', secSep)
+ minute = p.mustAtoi(str, minSep+1, secSep)
+ secEnd := secSep + 3
+ second = p.mustAtoi(str, secSep+1, secEnd)
+ }
+ remainderIdx := monSep + len("01-01 00:00:00") + 1
+ // Three optional (but ordered) sections follow: the
+ // fractional seconds, the time zone offset, and the BC
+ // designation. We set them up here and adjust the other
+ // offsets if the preceding sections exist.
+
+ nanoSec := 0
+ tzOff := 0
+
+ if remainderIdx < len(str) && str[remainderIdx] == '.' {
+ fracStart := remainderIdx + 1
+ fracOff := strings.IndexAny(str[fracStart:], "-+Z ")
+ if fracOff < 0 {
+ fracOff = len(str) - fracStart
+ }
+ fracSec := p.mustAtoi(str, fracStart, fracStart+fracOff)
+ nanoSec = fracSec * (1000000000 / int(math.Pow(10, float64(fracOff))))
+
+ remainderIdx += fracOff + 1
+ }
+ if tzStart := remainderIdx; tzStart < len(str) && (str[tzStart] == '-' || str[tzStart] == '+') {
+ // time zone separator is always '-' or '+' or 'Z' (UTC is +00)
+ var tzSign int
+ switch c := str[tzStart]; c {
+ case '-':
+ tzSign = -1
+ case '+':
+ tzSign = +1
+ default:
+ return time.Time{}, fmt.Errorf("expected '-' or '+' at position %v; got %v", tzStart, c)
+ }
+ tzHours := p.mustAtoi(str, tzStart+1, tzStart+3)
+ remainderIdx += 3
+ var tzMin, tzSec int
+ if remainderIdx < len(str) && str[remainderIdx] == ':' {
+ tzMin = p.mustAtoi(str, remainderIdx+1, remainderIdx+3)
+ remainderIdx += 3
+ }
+ if remainderIdx < len(str) && str[remainderIdx] == ':' {
+ tzSec = p.mustAtoi(str, remainderIdx+1, remainderIdx+3)
+ remainderIdx += 3
+ }
+ tzOff = tzSign * ((tzHours * 60 * 60) + (tzMin * 60) + tzSec)
+ } else if tzStart < len(str) && str[tzStart] == 'Z' {
+ // time zone Z separator indicates UTC is +00
+ remainderIdx += 1
+ }
+
+ var isoYear int
+
+ if isBC {
+ isoYear = 1 - year
+ remainderIdx += 3
+ } else {
+ isoYear = year
+ }
+ if remainderIdx < len(str) {
+ return time.Time{}, fmt.Errorf("expected end of input, got %v", str[remainderIdx:])
+ }
+ t := time.Date(isoYear, time.Month(month), day,
+ hour, minute, second, nanoSec,
+ globalLocationCache.getLocation(tzOff))
+
+ if currentLocation != nil {
+ // Set the location of the returned Time based on the session's
+ // TimeZone value, but only if the local time zone database agrees with
+ // the remote database on the offset.
+ lt := t.In(currentLocation)
+ _, newOff := lt.Zone()
+ if newOff == tzOff {
+ t = lt
+ }
+ }
+
+ return t, p.err
+}
+
+// formatTs formats t into a format postgres understands.
+func formatTs(t time.Time) []byte {
+ if infinityTsEnabled {
+ // t <= -infinity : ! (t > -infinity)
+ if !t.After(infinityTsNegative) {
+ return []byte("-infinity")
+ }
+ // t >= infinity : ! (!t < infinity)
+ if !t.Before(infinityTsPositive) {
+ return []byte("infinity")
+ }
+ }
+ return FormatTimestamp(t)
+}
+
+// FormatTimestamp formats t into Postgres' text format for timestamps.
+func FormatTimestamp(t time.Time) []byte {
+ // Need to send dates before 0001 A.D. with " BC" suffix, instead of the
+ // minus sign preferred by Go.
+ // Beware, "0000" in ISO is "1 BC", "-0001" is "2 BC" and so on
+ bc := false
+ if t.Year() <= 0 {
+ // flip year sign, and add 1, e.g: "0" will be "1", and "-10" will be "11"
+ t = t.AddDate((-t.Year())*2+1, 0, 0)
+ bc = true
+ }
+ b := []byte(t.Format("2006-01-02 15:04:05.999999999Z07:00"))
+
+ _, offset := t.Zone()
+ offset %= 60
+ if offset != 0 {
+ // RFC3339Nano already printed the minus sign
+ if offset < 0 {
+ offset = -offset
+ }
+
+ b = append(b, ':')
+ if offset < 10 {
+ b = append(b, '0')
+ }
+ b = strconv.AppendInt(b, int64(offset), 10)
+ }
+
+ if bc {
+ b = append(b, " BC"...)
+ }
+ return b
+}
+
+// Parse a bytea value received from the server. Both "hex" and the legacy
+// "escape" format are supported.
+func parseBytea(s []byte) (result []byte, err error) {
+ if len(s) >= 2 && bytes.Equal(s[:2], []byte("\\x")) {
+ // bytea_output = hex
+ s = s[2:] // trim off leading "\\x"
+ result = make([]byte, hex.DecodedLen(len(s)))
+ _, err := hex.Decode(result, s)
+ if err != nil {
+ return nil, err
+ }
+ } else {
+ // bytea_output = escape
+ for len(s) > 0 {
+ if s[0] == '\\' {
+ // escaped '\\'
+ if len(s) >= 2 && s[1] == '\\' {
+ result = append(result, '\\')
+ s = s[2:]
+ continue
+ }
+
+ // '\\' followed by an octal number
+ if len(s) < 4 {
+ return nil, fmt.Errorf("invalid bytea sequence %v", s)
+ }
+ r, err := strconv.ParseUint(string(s[1:4]), 8, 8)
+ if err != nil {
+ return nil, fmt.Errorf("could not parse bytea value: %s", err.Error())
+ }
+ result = append(result, byte(r))
+ s = s[4:]
+ } else {
+ // We hit an unescaped, raw byte. Try to read in as many as
+ // possible in one go.
+ i := bytes.IndexByte(s, '\\')
+ if i == -1 {
+ result = append(result, s...)
+ break
+ }
+ result = append(result, s[:i]...)
+ s = s[i:]
+ }
+ }
+ }
+
+ return result, nil
+}
+
+func encodeBytea(serverVersion int, v []byte) (result []byte) {
+ if serverVersion >= 90000 {
+ // Use the hex format if we know that the server supports it
+ result = make([]byte, 2+hex.EncodedLen(len(v)))
+ result[0] = '\\'
+ result[1] = 'x'
+ hex.Encode(result[2:], v)
+ } else {
+ // .. or resort to "escape"
+ for _, b := range v {
+ if b == '\\' {
+ result = append(result, '\\', '\\')
+ } else if b < 0x20 || b > 0x7e {
+ result = append(result, []byte(fmt.Sprintf("\\%03o", b))...)
+ } else {
+ result = append(result, b)
+ }
+ }
+ }
+
+ return result
+}
+
+// NullTime represents a time.Time that may be null. NullTime implements the
+// sql.Scanner interface so it can be used as a scan destination, similar to
+// sql.NullString.
+type NullTime struct {
+ Time time.Time
+ Valid bool // Valid is true if Time is not NULL
+}
+
+// Scan implements the Scanner interface.
+func (nt *NullTime) Scan(value interface{}) error {
+ nt.Time, nt.Valid = value.(time.Time)
+ return nil
+}
+
+// Value implements the driver Valuer interface.
+func (nt NullTime) Value() (driver.Value, error) {
+ if !nt.Valid {
+ return nil, nil
+ }
+ return nt.Time, nil
+}
diff --git a/vendor/github.com/lib/pq/error.go b/vendor/github.com/lib/pq/error.go
new file mode 100644
index 0000000..f67c5a5
--- /dev/null
+++ b/vendor/github.com/lib/pq/error.go
@@ -0,0 +1,523 @@
+package pq
+
+import (
+ "database/sql/driver"
+ "fmt"
+ "io"
+ "net"
+ "runtime"
+)
+
+// Error severities
+const (
+ Efatal = "FATAL"
+ Epanic = "PANIC"
+ Ewarning = "WARNING"
+ Enotice = "NOTICE"
+ Edebug = "DEBUG"
+ Einfo = "INFO"
+ Elog = "LOG"
+)
+
+// Error represents an error communicating with the server.
+//
+// See http://www.postgresql.org/docs/current/static/protocol-error-fields.html for details of the fields
+type Error struct {
+ Severity string
+ Code ErrorCode
+ Message string
+ Detail string
+ Hint string
+ Position string
+ InternalPosition string
+ InternalQuery string
+ Where string
+ Schema string
+ Table string
+ Column string
+ DataTypeName string
+ Constraint string
+ File string
+ Line string
+ Routine string
+}
+
+// ErrorCode is a five-character error code.
+type ErrorCode string
+
+// Name returns a more human friendly rendering of the error code, namely the
+// "condition name".
+//
+// See http://www.postgresql.org/docs/9.3/static/errcodes-appendix.html for
+// details.
+func (ec ErrorCode) Name() string {
+ return errorCodeNames[ec]
+}
+
+// ErrorClass is only the class part of an error code.
+type ErrorClass string
+
+// Name returns the condition name of an error class. It is equivalent to the
+// condition name of the "standard" error code (i.e. the one having the last
+// three characters "000").
+func (ec ErrorClass) Name() string {
+ return errorCodeNames[ErrorCode(ec+"000")]
+}
+
+// Class returns the error class, e.g. "28".
+//
+// See http://www.postgresql.org/docs/9.3/static/errcodes-appendix.html for
+// details.
+func (ec ErrorCode) Class() ErrorClass {
+ return ErrorClass(ec[0:2])
+}
+
+// errorCodeNames is a mapping between the five-character error codes and the
+// human readable "condition names". It is derived from the list at
+// http://www.postgresql.org/docs/9.3/static/errcodes-appendix.html
+var errorCodeNames = map[ErrorCode]string{
+ // Class 00 - Successful Completion
+ "00000": "successful_completion",
+ // Class 01 - Warning
+ "01000": "warning",
+ "0100C": "dynamic_result_sets_returned",
+ "01008": "implicit_zero_bit_padding",
+ "01003": "null_value_eliminated_in_set_function",
+ "01007": "privilege_not_granted",
+ "01006": "privilege_not_revoked",
+ "01004": "string_data_right_truncation",
+ "01P01": "deprecated_feature",
+ // Class 02 - No Data (this is also a warning class per the SQL standard)
+ "02000": "no_data",
+ "02001": "no_additional_dynamic_result_sets_returned",
+ // Class 03 - SQL Statement Not Yet Complete
+ "03000": "sql_statement_not_yet_complete",
+ // Class 08 - Connection Exception
+ "08000": "connection_exception",
+ "08003": "connection_does_not_exist",
+ "08006": "connection_failure",
+ "08001": "sqlclient_unable_to_establish_sqlconnection",
+ "08004": "sqlserver_rejected_establishment_of_sqlconnection",
+ "08007": "transaction_resolution_unknown",
+ "08P01": "protocol_violation",
+ // Class 09 - Triggered Action Exception
+ "09000": "triggered_action_exception",
+ // Class 0A - Feature Not Supported
+ "0A000": "feature_not_supported",
+ // Class 0B - Invalid Transaction Initiation
+ "0B000": "invalid_transaction_initiation",
+ // Class 0F - Locator Exception
+ "0F000": "locator_exception",
+ "0F001": "invalid_locator_specification",
+ // Class 0L - Invalid Grantor
+ "0L000": "invalid_grantor",
+ "0LP01": "invalid_grant_operation",
+ // Class 0P - Invalid Role Specification
+ "0P000": "invalid_role_specification",
+ // Class 0Z - Diagnostics Exception
+ "0Z000": "diagnostics_exception",
+ "0Z002": "stacked_diagnostics_accessed_without_active_handler",
+ // Class 20 - Case Not Found
+ "20000": "case_not_found",
+ // Class 21 - Cardinality Violation
+ "21000": "cardinality_violation",
+ // Class 22 - Data Exception
+ "22000": "data_exception",
+ "2202E": "array_subscript_error",
+ "22021": "character_not_in_repertoire",
+ "22008": "datetime_field_overflow",
+ "22012": "division_by_zero",
+ "22005": "error_in_assignment",
+ "2200B": "escape_character_conflict",
+ "22022": "indicator_overflow",
+ "22015": "interval_field_overflow",
+ "2201E": "invalid_argument_for_logarithm",
+ "22014": "invalid_argument_for_ntile_function",
+ "22016": "invalid_argument_for_nth_value_function",
+ "2201F": "invalid_argument_for_power_function",
+ "2201G": "invalid_argument_for_width_bucket_function",
+ "22018": "invalid_character_value_for_cast",
+ "22007": "invalid_datetime_format",
+ "22019": "invalid_escape_character",
+ "2200D": "invalid_escape_octet",
+ "22025": "invalid_escape_sequence",
+ "22P06": "nonstandard_use_of_escape_character",
+ "22010": "invalid_indicator_parameter_value",
+ "22023": "invalid_parameter_value",
+ "2201B": "invalid_regular_expression",
+ "2201W": "invalid_row_count_in_limit_clause",
+ "2201X": "invalid_row_count_in_result_offset_clause",
+ "22009": "invalid_time_zone_displacement_value",
+ "2200C": "invalid_use_of_escape_character",
+ "2200G": "most_specific_type_mismatch",
+ "22004": "null_value_not_allowed",
+ "22002": "null_value_no_indicator_parameter",
+ "22003": "numeric_value_out_of_range",
+ "2200H": "sequence_generator_limit_exceeded",
+ "22026": "string_data_length_mismatch",
+ "22001": "string_data_right_truncation",
+ "22011": "substring_error",
+ "22027": "trim_error",
+ "22024": "unterminated_c_string",
+ "2200F": "zero_length_character_string",
+ "22P01": "floating_point_exception",
+ "22P02": "invalid_text_representation",
+ "22P03": "invalid_binary_representation",
+ "22P04": "bad_copy_file_format",
+ "22P05": "untranslatable_character",
+ "2200L": "not_an_xml_document",
+ "2200M": "invalid_xml_document",
+ "2200N": "invalid_xml_content",
+ "2200S": "invalid_xml_comment",
+ "2200T": "invalid_xml_processing_instruction",
+ // Class 23 - Integrity Constraint Violation
+ "23000": "integrity_constraint_violation",
+ "23001": "restrict_violation",
+ "23502": "not_null_violation",
+ "23503": "foreign_key_violation",
+ "23505": "unique_violation",
+ "23514": "check_violation",
+ "23P01": "exclusion_violation",
+ // Class 24 - Invalid Cursor State
+ "24000": "invalid_cursor_state",
+ // Class 25 - Invalid Transaction State
+ "25000": "invalid_transaction_state",
+ "25001": "active_sql_transaction",
+ "25002": "branch_transaction_already_active",
+ "25008": "held_cursor_requires_same_isolation_level",
+ "25003": "inappropriate_access_mode_for_branch_transaction",
+ "25004": "inappropriate_isolation_level_for_branch_transaction",
+ "25005": "no_active_sql_transaction_for_branch_transaction",
+ "25006": "read_only_sql_transaction",
+ "25007": "schema_and_data_statement_mixing_not_supported",
+ "25P01": "no_active_sql_transaction",
+ "25P02": "in_failed_sql_transaction",
+ // Class 26 - Invalid SQL Statement Name
+ "26000": "invalid_sql_statement_name",
+ // Class 27 - Triggered Data Change Violation
+ "27000": "triggered_data_change_violation",
+ // Class 28 - Invalid Authorization Specification
+ "28000": "invalid_authorization_specification",
+ "28P01": "invalid_password",
+ // Class 2B - Dependent Privilege Descriptors Still Exist
+ "2B000": "dependent_privilege_descriptors_still_exist",
+ "2BP01": "dependent_objects_still_exist",
+ // Class 2D - Invalid Transaction Termination
+ "2D000": "invalid_transaction_termination",
+ // Class 2F - SQL Routine Exception
+ "2F000": "sql_routine_exception",
+ "2F005": "function_executed_no_return_statement",
+ "2F002": "modifying_sql_data_not_permitted",
+ "2F003": "prohibited_sql_statement_attempted",
+ "2F004": "reading_sql_data_not_permitted",
+ // Class 34 - Invalid Cursor Name
+ "34000": "invalid_cursor_name",
+ // Class 38 - External Routine Exception
+ "38000": "external_routine_exception",
+ "38001": "containing_sql_not_permitted",
+ "38002": "modifying_sql_data_not_permitted",
+ "38003": "prohibited_sql_statement_attempted",
+ "38004": "reading_sql_data_not_permitted",
+ // Class 39 - External Routine Invocation Exception
+ "39000": "external_routine_invocation_exception",
+ "39001": "invalid_sqlstate_returned",
+ "39004": "null_value_not_allowed",
+ "39P01": "trigger_protocol_violated",
+ "39P02": "srf_protocol_violated",
+ // Class 3B - Savepoint Exception
+ "3B000": "savepoint_exception",
+ "3B001": "invalid_savepoint_specification",
+ // Class 3D - Invalid Catalog Name
+ "3D000": "invalid_catalog_name",
+ // Class 3F - Invalid Schema Name
+ "3F000": "invalid_schema_name",
+ // Class 40 - Transaction Rollback
+ "40000": "transaction_rollback",
+ "40002": "transaction_integrity_constraint_violation",
+ "40001": "serialization_failure",
+ "40003": "statement_completion_unknown",
+ "40P01": "deadlock_detected",
+ // Class 42 - Syntax Error or Access Rule Violation
+ "42000": "syntax_error_or_access_rule_violation",
+ "42601": "syntax_error",
+ "42501": "insufficient_privilege",
+ "42846": "cannot_coerce",
+ "42803": "grouping_error",
+ "42P20": "windowing_error",
+ "42P19": "invalid_recursion",
+ "42830": "invalid_foreign_key",
+ "42602": "invalid_name",
+ "42622": "name_too_long",
+ "42939": "reserved_name",
+ "42804": "datatype_mismatch",
+ "42P18": "indeterminate_datatype",
+ "42P21": "collation_mismatch",
+ "42P22": "indeterminate_collation",
+ "42809": "wrong_object_type",
+ "42703": "undefined_column",
+ "42883": "undefined_function",
+ "42P01": "undefined_table",
+ "42P02": "undefined_parameter",
+ "42704": "undefined_object",
+ "42701": "duplicate_column",
+ "42P03": "duplicate_cursor",
+ "42P04": "duplicate_database",
+ "42723": "duplicate_function",
+ "42P05": "duplicate_prepared_statement",
+ "42P06": "duplicate_schema",
+ "42P07": "duplicate_table",
+ "42712": "duplicate_alias",
+ "42710": "duplicate_object",
+ "42702": "ambiguous_column",
+ "42725": "ambiguous_function",
+ "42P08": "ambiguous_parameter",
+ "42P09": "ambiguous_alias",
+ "42P10": "invalid_column_reference",
+ "42611": "invalid_column_definition",
+ "42P11": "invalid_cursor_definition",
+ "42P12": "invalid_database_definition",
+ "42P13": "invalid_function_definition",
+ "42P14": "invalid_prepared_statement_definition",
+ "42P15": "invalid_schema_definition",
+ "42P16": "invalid_table_definition",
+ "42P17": "invalid_object_definition",
+ // Class 44 - WITH CHECK OPTION Violation
+ "44000": "with_check_option_violation",
+ // Class 53 - Insufficient Resources
+ "53000": "insufficient_resources",
+ "53100": "disk_full",
+ "53200": "out_of_memory",
+ "53300": "too_many_connections",
+ "53400": "configuration_limit_exceeded",
+ // Class 54 - Program Limit Exceeded
+ "54000": "program_limit_exceeded",
+ "54001": "statement_too_complex",
+ "54011": "too_many_columns",
+ "54023": "too_many_arguments",
+ // Class 55 - Object Not In Prerequisite State
+ "55000": "object_not_in_prerequisite_state",
+ "55006": "object_in_use",
+ "55P02": "cant_change_runtime_param",
+ "55P03": "lock_not_available",
+ // Class 57 - Operator Intervention
+ "57000": "operator_intervention",
+ "57014": "query_canceled",
+ "57P01": "admin_shutdown",
+ "57P02": "crash_shutdown",
+ "57P03": "cannot_connect_now",
+ "57P04": "database_dropped",
+ // Class 58 - System Error (errors external to PostgreSQL itself)
+ "58000": "system_error",
+ "58030": "io_error",
+ "58P01": "undefined_file",
+ "58P02": "duplicate_file",
+ // Class F0 - Configuration File Error
+ "F0000": "config_file_error",
+ "F0001": "lock_file_exists",
+ // Class HV - Foreign Data Wrapper Error (SQL/MED)
+ "HV000": "fdw_error",
+ "HV005": "fdw_column_name_not_found",
+ "HV002": "fdw_dynamic_parameter_value_needed",
+ "HV010": "fdw_function_sequence_error",
+ "HV021": "fdw_inconsistent_descriptor_information",
+ "HV024": "fdw_invalid_attribute_value",
+ "HV007": "fdw_invalid_column_name",
+ "HV008": "fdw_invalid_column_number",
+ "HV004": "fdw_invalid_data_type",
+ "HV006": "fdw_invalid_data_type_descriptors",
+ "HV091": "fdw_invalid_descriptor_field_identifier",
+ "HV00B": "fdw_invalid_handle",
+ "HV00C": "fdw_invalid_option_index",
+ "HV00D": "fdw_invalid_option_name",
+ "HV090": "fdw_invalid_string_length_or_buffer_length",
+ "HV00A": "fdw_invalid_string_format",
+ "HV009": "fdw_invalid_use_of_null_pointer",
+ "HV014": "fdw_too_many_handles",
+ "HV001": "fdw_out_of_memory",
+ "HV00P": "fdw_no_schemas",
+ "HV00J": "fdw_option_name_not_found",
+ "HV00K": "fdw_reply_handle",
+ "HV00Q": "fdw_schema_not_found",
+ "HV00R": "fdw_table_not_found",
+ "HV00L": "fdw_unable_to_create_execution",
+ "HV00M": "fdw_unable_to_create_reply",
+ "HV00N": "fdw_unable_to_establish_connection",
+ // Class P0 - PL/pgSQL Error
+ "P0000": "plpgsql_error",
+ "P0001": "raise_exception",
+ "P0002": "no_data_found",
+ "P0003": "too_many_rows",
+ // Class XX - Internal Error
+ "XX000": "internal_error",
+ "XX001": "data_corrupted",
+ "XX002": "index_corrupted",
+}
+
+func parseError(r *readBuf) *Error {
+ err := new(Error)
+ for t := r.byte(); t != 0; t = r.byte() {
+ msg := r.string()
+ switch t {
+ case 'S':
+ err.Severity = msg
+ case 'C':
+ err.Code = ErrorCode(msg)
+ case 'M':
+ err.Message = msg
+ case 'D':
+ err.Detail = msg
+ case 'H':
+ err.Hint = msg
+ case 'P':
+ err.Position = msg
+ case 'p':
+ err.InternalPosition = msg
+ case 'q':
+ err.InternalQuery = msg
+ case 'W':
+ err.Where = msg
+ case 's':
+ err.Schema = msg
+ case 't':
+ err.Table = msg
+ case 'c':
+ err.Column = msg
+ case 'd':
+ err.DataTypeName = msg
+ case 'n':
+ err.Constraint = msg
+ case 'F':
+ err.File = msg
+ case 'L':
+ err.Line = msg
+ case 'R':
+ err.Routine = msg
+ }
+ }
+ return err
+}
+
+// Fatal returns true if the Error Severity is fatal.
+func (err *Error) Fatal() bool {
+ return err.Severity == Efatal
+}
+
+// SQLState returns the SQLState of the error.
+func (err *Error) SQLState() string {
+ return string(err.Code)
+}
+
+// Get implements the legacy PGError interface. New code should use the fields
+// of the Error struct directly.
+func (err *Error) Get(k byte) (v string) {
+ switch k {
+ case 'S':
+ return err.Severity
+ case 'C':
+ return string(err.Code)
+ case 'M':
+ return err.Message
+ case 'D':
+ return err.Detail
+ case 'H':
+ return err.Hint
+ case 'P':
+ return err.Position
+ case 'p':
+ return err.InternalPosition
+ case 'q':
+ return err.InternalQuery
+ case 'W':
+ return err.Where
+ case 's':
+ return err.Schema
+ case 't':
+ return err.Table
+ case 'c':
+ return err.Column
+ case 'd':
+ return err.DataTypeName
+ case 'n':
+ return err.Constraint
+ case 'F':
+ return err.File
+ case 'L':
+ return err.Line
+ case 'R':
+ return err.Routine
+ }
+ return ""
+}
+
+func (err *Error) Error() string {
+ return "pq: " + err.Message
+}
+
+// PGError is an interface used by previous versions of pq. It is provided
+// only to support legacy code. New code should use the Error type.
+type PGError interface {
+ Error() string
+ Fatal() bool
+ Get(k byte) (v string)
+}
+
+func errorf(s string, args ...interface{}) {
+ panic(fmt.Errorf("pq: %s", fmt.Sprintf(s, args...)))
+}
+
+// TODO(ainar-g) Rename to errorf after removing panics.
+func fmterrorf(s string, args ...interface{}) error {
+ return fmt.Errorf("pq: %s", fmt.Sprintf(s, args...))
+}
+
+func errRecoverNoErrBadConn(err *error) {
+ e := recover()
+ if e == nil {
+ // Do nothing
+ return
+ }
+ var ok bool
+ *err, ok = e.(error)
+ if !ok {
+ *err = fmt.Errorf("pq: unexpected error: %#v", e)
+ }
+}
+
+func (cn *conn) errRecover(err *error) {
+ e := recover()
+ switch v := e.(type) {
+ case nil:
+ // Do nothing
+ case runtime.Error:
+ cn.err.set(driver.ErrBadConn)
+ panic(v)
+ case *Error:
+ if v.Fatal() {
+ *err = driver.ErrBadConn
+ } else {
+ *err = v
+ }
+ case *net.OpError:
+ cn.err.set(driver.ErrBadConn)
+ *err = v
+ case *safeRetryError:
+ cn.err.set(driver.ErrBadConn)
+ *err = driver.ErrBadConn
+ case error:
+ if v == io.EOF || v.Error() == "remote error: handshake failure" {
+ *err = driver.ErrBadConn
+ } else {
+ *err = v
+ }
+
+ default:
+ cn.err.set(driver.ErrBadConn)
+ panic(fmt.Sprintf("unknown error: %#v", e))
+ }
+
+ // Any time we return ErrBadConn, we need to remember it since *Tx doesn't
+ // mark the connection bad in database/sql.
+ if *err == driver.ErrBadConn {
+ cn.err.set(driver.ErrBadConn)
+ }
+}
diff --git a/vendor/github.com/lib/pq/krb.go b/vendor/github.com/lib/pq/krb.go
new file mode 100644
index 0000000..408ec01
--- /dev/null
+++ b/vendor/github.com/lib/pq/krb.go
@@ -0,0 +1,27 @@
+package pq
+
+// NewGSSFunc creates a GSS authentication provider, for use with
+// RegisterGSSProvider.
+type NewGSSFunc func() (GSS, error)
+
+var newGss NewGSSFunc
+
+// RegisterGSSProvider registers a GSS authentication provider. For example, if
+// you need to use Kerberos to authenticate with your server, add this to your
+// main package:
+//
+// import "github.com/lib/pq/auth/kerberos"
+//
+// func init() {
+// pq.RegisterGSSProvider(func() (pq.GSS, error) { return kerberos.NewGSS() })
+// }
+func RegisterGSSProvider(newGssArg NewGSSFunc) {
+ newGss = newGssArg
+}
+
+// GSS provides GSSAPI authentication (e.g., Kerberos).
+type GSS interface {
+ GetInitToken(host string, service string) ([]byte, error)
+ GetInitTokenFromSpn(spn string) ([]byte, error)
+ Continue(inToken []byte) (done bool, outToken []byte, err error)
+}
diff --git a/vendor/github.com/lib/pq/notice.go b/vendor/github.com/lib/pq/notice.go
new file mode 100644
index 0000000..70ad122
--- /dev/null
+++ b/vendor/github.com/lib/pq/notice.go
@@ -0,0 +1,72 @@
+//go:build go1.10
+// +build go1.10
+
+package pq
+
+import (
+ "context"
+ "database/sql/driver"
+)
+
+// NoticeHandler returns the notice handler on the given connection, if any. A
+// runtime panic occurs if c is not a pq connection. This is rarely used
+// directly, use ConnectorNoticeHandler and ConnectorWithNoticeHandler instead.
+func NoticeHandler(c driver.Conn) func(*Error) {
+ return c.(*conn).noticeHandler
+}
+
+// SetNoticeHandler sets the given notice handler on the given connection. A
+// runtime panic occurs if c is not a pq connection. A nil handler may be used
+// to unset it. This is rarely used directly, use ConnectorNoticeHandler and
+// ConnectorWithNoticeHandler instead.
+//
+// Note: Notice handlers are executed synchronously by pq meaning commands
+// won't continue to be processed until the handler returns.
+func SetNoticeHandler(c driver.Conn, handler func(*Error)) {
+ c.(*conn).noticeHandler = handler
+}
+
+// NoticeHandlerConnector wraps a regular connector and sets a notice handler
+// on it.
+type NoticeHandlerConnector struct {
+ driver.Connector
+ noticeHandler func(*Error)
+}
+
+// Connect calls the underlying connector's connect method and then sets the
+// notice handler.
+func (n *NoticeHandlerConnector) Connect(ctx context.Context) (driver.Conn, error) {
+ c, err := n.Connector.Connect(ctx)
+ if err == nil {
+ SetNoticeHandler(c, n.noticeHandler)
+ }
+ return c, err
+}
+
+// ConnectorNoticeHandler returns the currently set notice handler, if any. If
+// the given connector is not a result of ConnectorWithNoticeHandler, nil is
+// returned.
+func ConnectorNoticeHandler(c driver.Connector) func(*Error) {
+ if c, ok := c.(*NoticeHandlerConnector); ok {
+ return c.noticeHandler
+ }
+ return nil
+}
+
+// ConnectorWithNoticeHandler creates or sets the given handler for the given
+// connector. If the given connector is a result of calling this function
+// previously, it is simply set on the given connector and returned. Otherwise,
+// this returns a new connector wrapping the given one and setting the notice
+// handler. A nil notice handler may be used to unset it.
+//
+// The returned connector is intended to be used with database/sql.OpenDB.
+//
+// Note: Notice handlers are executed synchronously by pq meaning commands
+// won't continue to be processed until the handler returns.
+func ConnectorWithNoticeHandler(c driver.Connector, handler func(*Error)) *NoticeHandlerConnector {
+ if c, ok := c.(*NoticeHandlerConnector); ok {
+ c.noticeHandler = handler
+ return c
+ }
+ return &NoticeHandlerConnector{Connector: c, noticeHandler: handler}
+}
diff --git a/vendor/github.com/lib/pq/notify.go b/vendor/github.com/lib/pq/notify.go
new file mode 100644
index 0000000..5c421fd
--- /dev/null
+++ b/vendor/github.com/lib/pq/notify.go
@@ -0,0 +1,858 @@
+package pq
+
+// Package pq is a pure Go Postgres driver for the database/sql package.
+// This module contains support for Postgres LISTEN/NOTIFY.
+
+import (
+ "context"
+ "database/sql/driver"
+ "errors"
+ "fmt"
+ "sync"
+ "sync/atomic"
+ "time"
+)
+
+// Notification represents a single notification from the database.
+type Notification struct {
+ // Process ID (PID) of the notifying postgres backend.
+ BePid int
+ // Name of the channel the notification was sent on.
+ Channel string
+ // Payload, or the empty string if unspecified.
+ Extra string
+}
+
+func recvNotification(r *readBuf) *Notification {
+ bePid := r.int32()
+ channel := r.string()
+ extra := r.string()
+
+ return &Notification{bePid, channel, extra}
+}
+
+// SetNotificationHandler sets the given notification handler on the given
+// connection. A runtime panic occurs if c is not a pq connection. A nil handler
+// may be used to unset it.
+//
+// Note: Notification handlers are executed synchronously by pq meaning commands
+// won't continue to be processed until the handler returns.
+func SetNotificationHandler(c driver.Conn, handler func(*Notification)) {
+ c.(*conn).notificationHandler = handler
+}
+
+// NotificationHandlerConnector wraps a regular connector and sets a notification handler
+// on it.
+type NotificationHandlerConnector struct {
+ driver.Connector
+ notificationHandler func(*Notification)
+}
+
+// Connect calls the underlying connector's connect method and then sets the
+// notification handler.
+func (n *NotificationHandlerConnector) Connect(ctx context.Context) (driver.Conn, error) {
+ c, err := n.Connector.Connect(ctx)
+ if err == nil {
+ SetNotificationHandler(c, n.notificationHandler)
+ }
+ return c, err
+}
+
+// ConnectorNotificationHandler returns the currently set notification handler, if any. If
+// the given connector is not a result of ConnectorWithNotificationHandler, nil is
+// returned.
+func ConnectorNotificationHandler(c driver.Connector) func(*Notification) {
+ if c, ok := c.(*NotificationHandlerConnector); ok {
+ return c.notificationHandler
+ }
+ return nil
+}
+
+// ConnectorWithNotificationHandler creates or sets the given handler for the given
+// connector. If the given connector is a result of calling this function
+// previously, it is simply set on the given connector and returned. Otherwise,
+// this returns a new connector wrapping the given one and setting the notification
+// handler. A nil notification handler may be used to unset it.
+//
+// The returned connector is intended to be used with database/sql.OpenDB.
+//
+// Note: Notification handlers are executed synchronously by pq meaning commands
+// won't continue to be processed until the handler returns.
+func ConnectorWithNotificationHandler(c driver.Connector, handler func(*Notification)) *NotificationHandlerConnector {
+ if c, ok := c.(*NotificationHandlerConnector); ok {
+ c.notificationHandler = handler
+ return c
+ }
+ return &NotificationHandlerConnector{Connector: c, notificationHandler: handler}
+}
+
+const (
+ connStateIdle int32 = iota
+ connStateExpectResponse
+ connStateExpectReadyForQuery
+)
+
+type message struct {
+ typ byte
+ err error
+}
+
+var errListenerConnClosed = errors.New("pq: ListenerConn has been closed")
+
+// ListenerConn is a low-level interface for waiting for notifications. You
+// should use Listener instead.
+type ListenerConn struct {
+ // guards cn and err
+ connectionLock sync.Mutex
+ cn *conn
+ err error
+
+ connState int32
+
+ // the sending goroutine will be holding this lock
+ senderLock sync.Mutex
+
+ notificationChan chan<- *Notification
+
+ replyChan chan message
+}
+
+// NewListenerConn creates a new ListenerConn. Use NewListener instead.
+func NewListenerConn(name string, notificationChan chan<- *Notification) (*ListenerConn, error) {
+ return newDialListenerConn(defaultDialer{}, name, notificationChan)
+}
+
+func newDialListenerConn(d Dialer, name string, c chan<- *Notification) (*ListenerConn, error) {
+ cn, err := DialOpen(d, name)
+ if err != nil {
+ return nil, err
+ }
+
+ l := &ListenerConn{
+ cn: cn.(*conn),
+ notificationChan: c,
+ connState: connStateIdle,
+ replyChan: make(chan message, 2),
+ }
+
+ go l.listenerConnMain()
+
+ return l, nil
+}
+
+// We can only allow one goroutine at a time to be running a query on the
+// connection for various reasons, so the goroutine sending on the connection
+// must be holding senderLock.
+//
+// Returns an error if an unrecoverable error has occurred and the ListenerConn
+// should be abandoned.
+func (l *ListenerConn) acquireSenderLock() error {
+ // we must acquire senderLock first to avoid deadlocks; see ExecSimpleQuery
+ l.senderLock.Lock()
+
+ l.connectionLock.Lock()
+ err := l.err
+ l.connectionLock.Unlock()
+ if err != nil {
+ l.senderLock.Unlock()
+ return err
+ }
+ return nil
+}
+
+func (l *ListenerConn) releaseSenderLock() {
+ l.senderLock.Unlock()
+}
+
+// setState advances the protocol state to newState. Returns false if moving
+// to that state from the current state is not allowed.
+func (l *ListenerConn) setState(newState int32) bool {
+ var expectedState int32
+
+ switch newState {
+ case connStateIdle:
+ expectedState = connStateExpectReadyForQuery
+ case connStateExpectResponse:
+ expectedState = connStateIdle
+ case connStateExpectReadyForQuery:
+ expectedState = connStateExpectResponse
+ default:
+ panic(fmt.Sprintf("unexpected listenerConnState %d", newState))
+ }
+
+ return atomic.CompareAndSwapInt32(&l.connState, expectedState, newState)
+}
+
+// Main logic is here: receive messages from the postgres backend, forward
+// notifications and query replies and keep the internal state in sync with the
+// protocol state. Returns when the connection has been lost, is about to go
+// away or should be discarded because we couldn't agree on the state with the
+// server backend.
+func (l *ListenerConn) listenerConnLoop() (err error) {
+ defer errRecoverNoErrBadConn(&err)
+
+ r := &readBuf{}
+ for {
+ t, err := l.cn.recvMessage(r)
+ if err != nil {
+ return err
+ }
+
+ switch t {
+ case 'A':
+ // recvNotification copies all the data so we don't need to worry
+ // about the scratch buffer being overwritten.
+ l.notificationChan <- recvNotification(r)
+
+ case 'T', 'D':
+ // only used by tests; ignore
+
+ case 'E':
+ // We might receive an ErrorResponse even when not in a query; it
+ // is expected that the server will close the connection after
+ // that, but we should make sure that the error we display is the
+ // one from the stray ErrorResponse, not io.ErrUnexpectedEOF.
+ if !l.setState(connStateExpectReadyForQuery) {
+ return parseError(r)
+ }
+ l.replyChan <- message{t, parseError(r)}
+
+ case 'C', 'I':
+ if !l.setState(connStateExpectReadyForQuery) {
+ // protocol out of sync
+ return fmt.Errorf("unexpected CommandComplete")
+ }
+ // ExecSimpleQuery doesn't need to know about this message
+
+ case 'Z':
+ if !l.setState(connStateIdle) {
+ // protocol out of sync
+ return fmt.Errorf("unexpected ReadyForQuery")
+ }
+ l.replyChan <- message{t, nil}
+
+ case 'S':
+ // ignore
+ case 'N':
+ if n := l.cn.noticeHandler; n != nil {
+ n(parseError(r))
+ }
+ default:
+ return fmt.Errorf("unexpected message %q from server in listenerConnLoop", t)
+ }
+ }
+}
+
+// This is the main routine for the goroutine receiving on the database
+// connection. Most of the main logic is in listenerConnLoop.
+func (l *ListenerConn) listenerConnMain() {
+ err := l.listenerConnLoop()
+
+ // listenerConnLoop terminated; we're done, but we still have to clean up.
+ // Make sure nobody tries to start any new queries by making sure the err
+ // pointer is set. It is important that we do not overwrite its value; a
+ // connection could be closed by either this goroutine or one sending on
+ // the connection -- whoever closes the connection is assumed to have the
+ // more meaningful error message (as the other one will probably get
+ // net.errClosed), so that goroutine sets the error we expose while the
+ // other error is discarded. If the connection is lost while two
+ // goroutines are operating on the socket, it probably doesn't matter which
+ // error we expose so we don't try to do anything more complex.
+ l.connectionLock.Lock()
+ if l.err == nil {
+ l.err = err
+ }
+ l.cn.Close()
+ l.connectionLock.Unlock()
+
+ // There might be a query in-flight; make sure nobody's waiting for a
+ // response to it, since there's not going to be one.
+ close(l.replyChan)
+
+ // let the listener know we're done
+ close(l.notificationChan)
+
+ // this ListenerConn is done
+}
+
+// Listen sends a LISTEN query to the server. See ExecSimpleQuery.
+func (l *ListenerConn) Listen(channel string) (bool, error) {
+ return l.ExecSimpleQuery("LISTEN " + QuoteIdentifier(channel))
+}
+
+// Unlisten sends an UNLISTEN query to the server. See ExecSimpleQuery.
+func (l *ListenerConn) Unlisten(channel string) (bool, error) {
+ return l.ExecSimpleQuery("UNLISTEN " + QuoteIdentifier(channel))
+}
+
+// UnlistenAll sends an `UNLISTEN *` query to the server. See ExecSimpleQuery.
+func (l *ListenerConn) UnlistenAll() (bool, error) {
+ return l.ExecSimpleQuery("UNLISTEN *")
+}
+
+// Ping the remote server to make sure it's alive. Non-nil error means the
+// connection has failed and should be abandoned.
+func (l *ListenerConn) Ping() error {
+ sent, err := l.ExecSimpleQuery("")
+ if !sent {
+ return err
+ }
+ if err != nil {
+ // shouldn't happen
+ panic(err)
+ }
+ return nil
+}
+
+// Attempt to send a query on the connection. Returns an error if sending the
+// query failed, and the caller should initiate closure of this connection.
+// The caller must be holding senderLock (see acquireSenderLock and
+// releaseSenderLock).
+func (l *ListenerConn) sendSimpleQuery(q string) (err error) {
+ defer errRecoverNoErrBadConn(&err)
+
+ // must set connection state before sending the query
+ if !l.setState(connStateExpectResponse) {
+ panic("two queries running at the same time")
+ }
+
+ // Can't use l.cn.writeBuf here because it uses the scratch buffer which
+ // might get overwritten by listenerConnLoop.
+ b := &writeBuf{
+ buf: []byte("Q\x00\x00\x00\x00"),
+ pos: 1,
+ }
+ b.string(q)
+ l.cn.send(b)
+
+ return nil
+}
+
+// ExecSimpleQuery executes a "simple query" (i.e. one with no bindable
+// parameters) on the connection. The possible return values are:
+// 1) "executed" is true; the query was executed to completion on the
+// database server. If the query failed, err will be set to the error
+// returned by the database, otherwise err will be nil.
+// 2) If "executed" is false, the query could not be executed on the remote
+// server. err will be non-nil.
+//
+// After a call to ExecSimpleQuery has returned an executed=false value, the
+// connection has either been closed or will be closed shortly thereafter, and
+// all subsequently executed queries will return an error.
+func (l *ListenerConn) ExecSimpleQuery(q string) (executed bool, err error) {
+ if err = l.acquireSenderLock(); err != nil {
+ return false, err
+ }
+ defer l.releaseSenderLock()
+
+ err = l.sendSimpleQuery(q)
+ if err != nil {
+ // We can't know what state the protocol is in, so we need to abandon
+ // this connection.
+ l.connectionLock.Lock()
+ // Set the error pointer if it hasn't been set already; see
+ // listenerConnMain.
+ if l.err == nil {
+ l.err = err
+ }
+ l.connectionLock.Unlock()
+ l.cn.c.Close()
+ return false, err
+ }
+
+ // now we just wait for a reply..
+ for {
+ m, ok := <-l.replyChan
+ if !ok {
+ // We lost the connection to server, don't bother waiting for a
+ // a response. err should have been set already.
+ l.connectionLock.Lock()
+ err := l.err
+ l.connectionLock.Unlock()
+ return false, err
+ }
+ switch m.typ {
+ case 'Z':
+ // sanity check
+ if m.err != nil {
+ panic("m.err != nil")
+ }
+ // done; err might or might not be set
+ return true, err
+
+ case 'E':
+ // sanity check
+ if m.err == nil {
+ panic("m.err == nil")
+ }
+ // server responded with an error; ReadyForQuery to follow
+ err = m.err
+
+ default:
+ return false, fmt.Errorf("unknown response for simple query: %q", m.typ)
+ }
+ }
+}
+
+// Close closes the connection.
+func (l *ListenerConn) Close() error {
+ l.connectionLock.Lock()
+ if l.err != nil {
+ l.connectionLock.Unlock()
+ return errListenerConnClosed
+ }
+ l.err = errListenerConnClosed
+ l.connectionLock.Unlock()
+ // We can't send anything on the connection without holding senderLock.
+ // Simply close the net.Conn to wake up everyone operating on it.
+ return l.cn.c.Close()
+}
+
+// Err returns the reason the connection was closed. It is not safe to call
+// this function until l.Notify has been closed.
+func (l *ListenerConn) Err() error {
+ return l.err
+}
+
+var errListenerClosed = errors.New("pq: Listener has been closed")
+
+// ErrChannelAlreadyOpen is returned from Listen when a channel is already
+// open.
+var ErrChannelAlreadyOpen = errors.New("pq: channel is already open")
+
+// ErrChannelNotOpen is returned from Unlisten when a channel is not open.
+var ErrChannelNotOpen = errors.New("pq: channel is not open")
+
+// ListenerEventType is an enumeration of listener event types.
+type ListenerEventType int
+
+const (
+ // ListenerEventConnected is emitted only when the database connection
+ // has been initially initialized. The err argument of the callback
+ // will always be nil.
+ ListenerEventConnected ListenerEventType = iota
+
+ // ListenerEventDisconnected is emitted after a database connection has
+ // been lost, either because of an error or because Close has been
+ // called. The err argument will be set to the reason the database
+ // connection was lost.
+ ListenerEventDisconnected
+
+ // ListenerEventReconnected is emitted after a database connection has
+ // been re-established after connection loss. The err argument of the
+ // callback will always be nil. After this event has been emitted, a
+ // nil pq.Notification is sent on the Listener.Notify channel.
+ ListenerEventReconnected
+
+ // ListenerEventConnectionAttemptFailed is emitted after a connection
+ // to the database was attempted, but failed. The err argument will be
+ // set to an error describing why the connection attempt did not
+ // succeed.
+ ListenerEventConnectionAttemptFailed
+)
+
+// EventCallbackType is the event callback type. See also ListenerEventType
+// constants' documentation.
+type EventCallbackType func(event ListenerEventType, err error)
+
+// Listener provides an interface for listening to notifications from a
+// PostgreSQL database. For general usage information, see section
+// "Notifications".
+//
+// Listener can safely be used from concurrently running goroutines.
+type Listener struct {
+ // Channel for receiving notifications from the database. In some cases a
+ // nil value will be sent. See section "Notifications" above.
+ Notify chan *Notification
+
+ name string
+ minReconnectInterval time.Duration
+ maxReconnectInterval time.Duration
+ dialer Dialer
+ eventCallback EventCallbackType
+
+ lock sync.Mutex
+ isClosed bool
+ reconnectCond *sync.Cond
+ cn *ListenerConn
+ connNotificationChan <-chan *Notification
+ channels map[string]struct{}
+}
+
+// NewListener creates a new database connection dedicated to LISTEN / NOTIFY.
+//
+// name should be set to a connection string to be used to establish the
+// database connection (see section "Connection String Parameters" above).
+//
+// minReconnectInterval controls the duration to wait before trying to
+// re-establish the database connection after connection loss. After each
+// consecutive failure this interval is doubled, until maxReconnectInterval is
+// reached. Successfully completing the connection establishment procedure
+// resets the interval back to minReconnectInterval.
+//
+// The last parameter eventCallback can be set to a function which will be
+// called by the Listener when the state of the underlying database connection
+// changes. This callback will be called by the goroutine which dispatches the
+// notifications over the Notify channel, so you should try to avoid doing
+// potentially time-consuming operations from the callback.
+func NewListener(name string,
+ minReconnectInterval time.Duration,
+ maxReconnectInterval time.Duration,
+ eventCallback EventCallbackType) *Listener {
+ return NewDialListener(defaultDialer{}, name, minReconnectInterval, maxReconnectInterval, eventCallback)
+}
+
+// NewDialListener is like NewListener but it takes a Dialer.
+func NewDialListener(d Dialer,
+ name string,
+ minReconnectInterval time.Duration,
+ maxReconnectInterval time.Duration,
+ eventCallback EventCallbackType) *Listener {
+
+ l := &Listener{
+ name: name,
+ minReconnectInterval: minReconnectInterval,
+ maxReconnectInterval: maxReconnectInterval,
+ dialer: d,
+ eventCallback: eventCallback,
+
+ channels: make(map[string]struct{}),
+
+ Notify: make(chan *Notification, 32),
+ }
+ l.reconnectCond = sync.NewCond(&l.lock)
+
+ go l.listenerMain()
+
+ return l
+}
+
+// NotificationChannel returns the notification channel for this listener.
+// This is the same channel as Notify, and will not be recreated during the
+// life time of the Listener.
+func (l *Listener) NotificationChannel() <-chan *Notification {
+ return l.Notify
+}
+
+// Listen starts listening for notifications on a channel. Calls to this
+// function will block until an acknowledgement has been received from the
+// server. Note that Listener automatically re-establishes the connection
+// after connection loss, so this function may block indefinitely if the
+// connection can not be re-established.
+//
+// Listen will only fail in three conditions:
+// 1) The channel is already open. The returned error will be
+// ErrChannelAlreadyOpen.
+// 2) The query was executed on the remote server, but PostgreSQL returned an
+// error message in response to the query. The returned error will be a
+// pq.Error containing the information the server supplied.
+// 3) Close is called on the Listener before the request could be completed.
+//
+// The channel name is case-sensitive.
+func (l *Listener) Listen(channel string) error {
+ l.lock.Lock()
+ defer l.lock.Unlock()
+
+ if l.isClosed {
+ return errListenerClosed
+ }
+
+ // The server allows you to issue a LISTEN on a channel which is already
+ // open, but it seems useful to be able to detect this case to spot for
+ // mistakes in application logic. If the application genuinely does't
+ // care, it can check the exported error and ignore it.
+ _, exists := l.channels[channel]
+ if exists {
+ return ErrChannelAlreadyOpen
+ }
+
+ if l.cn != nil {
+ // If gotResponse is true but error is set, the query was executed on
+ // the remote server, but resulted in an error. This should be
+ // relatively rare, so it's fine if we just pass the error to our
+ // caller. However, if gotResponse is false, we could not complete the
+ // query on the remote server and our underlying connection is about
+ // to go away, so we only add relname to l.channels, and wait for
+ // resync() to take care of the rest.
+ gotResponse, err := l.cn.Listen(channel)
+ if gotResponse && err != nil {
+ return err
+ }
+ }
+
+ l.channels[channel] = struct{}{}
+ for l.cn == nil {
+ l.reconnectCond.Wait()
+ // we let go of the mutex for a while
+ if l.isClosed {
+ return errListenerClosed
+ }
+ }
+
+ return nil
+}
+
+// Unlisten removes a channel from the Listener's channel list. Returns
+// ErrChannelNotOpen if the Listener is not listening on the specified channel.
+// Returns immediately with no error if there is no connection. Note that you
+// might still get notifications for this channel even after Unlisten has
+// returned.
+//
+// The channel name is case-sensitive.
+func (l *Listener) Unlisten(channel string) error {
+ l.lock.Lock()
+ defer l.lock.Unlock()
+
+ if l.isClosed {
+ return errListenerClosed
+ }
+
+ // Similarly to LISTEN, this is not an error in Postgres, but it seems
+ // useful to distinguish from the normal conditions.
+ _, exists := l.channels[channel]
+ if !exists {
+ return ErrChannelNotOpen
+ }
+
+ if l.cn != nil {
+ // Similarly to Listen (see comment in that function), the caller
+ // should only be bothered with an error if it came from the backend as
+ // a response to our query.
+ gotResponse, err := l.cn.Unlisten(channel)
+ if gotResponse && err != nil {
+ return err
+ }
+ }
+
+ // Don't bother waiting for resync if there's no connection.
+ delete(l.channels, channel)
+ return nil
+}
+
+// UnlistenAll removes all channels from the Listener's channel list. Returns
+// immediately with no error if there is no connection. Note that you might
+// still get notifications for any of the deleted channels even after
+// UnlistenAll has returned.
+func (l *Listener) UnlistenAll() error {
+ l.lock.Lock()
+ defer l.lock.Unlock()
+
+ if l.isClosed {
+ return errListenerClosed
+ }
+
+ if l.cn != nil {
+ // Similarly to Listen (see comment in that function), the caller
+ // should only be bothered with an error if it came from the backend as
+ // a response to our query.
+ gotResponse, err := l.cn.UnlistenAll()
+ if gotResponse && err != nil {
+ return err
+ }
+ }
+
+ // Don't bother waiting for resync if there's no connection.
+ l.channels = make(map[string]struct{})
+ return nil
+}
+
+// Ping the remote server to make sure it's alive. Non-nil return value means
+// that there is no active connection.
+func (l *Listener) Ping() error {
+ l.lock.Lock()
+ defer l.lock.Unlock()
+
+ if l.isClosed {
+ return errListenerClosed
+ }
+ if l.cn == nil {
+ return errors.New("no connection")
+ }
+
+ return l.cn.Ping()
+}
+
+// Clean up after losing the server connection. Returns l.cn.Err(), which
+// should have the reason the connection was lost.
+func (l *Listener) disconnectCleanup() error {
+ l.lock.Lock()
+ defer l.lock.Unlock()
+
+ // sanity check; can't look at Err() until the channel has been closed
+ select {
+ case _, ok := <-l.connNotificationChan:
+ if ok {
+ panic("connNotificationChan not closed")
+ }
+ default:
+ panic("connNotificationChan not closed")
+ }
+
+ err := l.cn.Err()
+ l.cn.Close()
+ l.cn = nil
+ return err
+}
+
+// Synchronize the list of channels we want to be listening on with the server
+// after the connection has been established.
+func (l *Listener) resync(cn *ListenerConn, notificationChan <-chan *Notification) error {
+ doneChan := make(chan error)
+ go func(notificationChan <-chan *Notification) {
+ for channel := range l.channels {
+ // If we got a response, return that error to our caller as it's
+ // going to be more descriptive than cn.Err().
+ gotResponse, err := cn.Listen(channel)
+ if gotResponse && err != nil {
+ doneChan <- err
+ return
+ }
+
+ // If we couldn't reach the server, wait for notificationChan to
+ // close and then return the error message from the connection, as
+ // per ListenerConn's interface.
+ if err != nil {
+ for range notificationChan {
+ }
+ doneChan <- cn.Err()
+ return
+ }
+ }
+ doneChan <- nil
+ }(notificationChan)
+
+ // Ignore notifications while synchronization is going on to avoid
+ // deadlocks. We have to send a nil notification over Notify anyway as
+ // we can't possibly know which notifications (if any) were lost while
+ // the connection was down, so there's no reason to try and process
+ // these messages at all.
+ for {
+ select {
+ case _, ok := <-notificationChan:
+ if !ok {
+ notificationChan = nil
+ }
+
+ case err := <-doneChan:
+ return err
+ }
+ }
+}
+
+// caller should NOT be holding l.lock
+func (l *Listener) closed() bool {
+ l.lock.Lock()
+ defer l.lock.Unlock()
+
+ return l.isClosed
+}
+
+func (l *Listener) connect() error {
+ notificationChan := make(chan *Notification, 32)
+ cn, err := newDialListenerConn(l.dialer, l.name, notificationChan)
+ if err != nil {
+ return err
+ }
+
+ l.lock.Lock()
+ defer l.lock.Unlock()
+
+ err = l.resync(cn, notificationChan)
+ if err != nil {
+ cn.Close()
+ return err
+ }
+
+ l.cn = cn
+ l.connNotificationChan = notificationChan
+ l.reconnectCond.Broadcast()
+
+ return nil
+}
+
+// Close disconnects the Listener from the database and shuts it down.
+// Subsequent calls to its methods will return an error. Close returns an
+// error if the connection has already been closed.
+func (l *Listener) Close() error {
+ l.lock.Lock()
+ defer l.lock.Unlock()
+
+ if l.isClosed {
+ return errListenerClosed
+ }
+
+ if l.cn != nil {
+ l.cn.Close()
+ }
+ l.isClosed = true
+
+ // Unblock calls to Listen()
+ l.reconnectCond.Broadcast()
+
+ return nil
+}
+
+func (l *Listener) emitEvent(event ListenerEventType, err error) {
+ if l.eventCallback != nil {
+ l.eventCallback(event, err)
+ }
+}
+
+// Main logic here: maintain a connection to the server when possible, wait
+// for notifications and emit events.
+func (l *Listener) listenerConnLoop() {
+ var nextReconnect time.Time
+
+ reconnectInterval := l.minReconnectInterval
+ for {
+ for {
+ err := l.connect()
+ if err == nil {
+ break
+ }
+
+ if l.closed() {
+ return
+ }
+ l.emitEvent(ListenerEventConnectionAttemptFailed, err)
+
+ time.Sleep(reconnectInterval)
+ reconnectInterval *= 2
+ if reconnectInterval > l.maxReconnectInterval {
+ reconnectInterval = l.maxReconnectInterval
+ }
+ }
+
+ if nextReconnect.IsZero() {
+ l.emitEvent(ListenerEventConnected, nil)
+ } else {
+ l.emitEvent(ListenerEventReconnected, nil)
+ l.Notify <- nil
+ }
+
+ reconnectInterval = l.minReconnectInterval
+ nextReconnect = time.Now().Add(reconnectInterval)
+
+ for {
+ notification, ok := <-l.connNotificationChan
+ if !ok {
+ // lost connection, loop again
+ break
+ }
+ l.Notify <- notification
+ }
+
+ err := l.disconnectCleanup()
+ if l.closed() {
+ return
+ }
+ l.emitEvent(ListenerEventDisconnected, err)
+
+ time.Sleep(time.Until(nextReconnect))
+ }
+}
+
+func (l *Listener) listenerMain() {
+ l.listenerConnLoop()
+ close(l.Notify)
+}
diff --git a/vendor/github.com/lib/pq/oid/doc.go b/vendor/github.com/lib/pq/oid/doc.go
new file mode 100644
index 0000000..caaede2
--- /dev/null
+++ b/vendor/github.com/lib/pq/oid/doc.go
@@ -0,0 +1,6 @@
+// Package oid contains OID constants
+// as defined by the Postgres server.
+package oid
+
+// Oid is a Postgres Object ID.
+type Oid uint32
diff --git a/vendor/github.com/lib/pq/oid/types.go b/vendor/github.com/lib/pq/oid/types.go
new file mode 100644
index 0000000..ecc84c2
--- /dev/null
+++ b/vendor/github.com/lib/pq/oid/types.go
@@ -0,0 +1,343 @@
+// Code generated by gen.go. DO NOT EDIT.
+
+package oid
+
+const (
+ T_bool Oid = 16
+ T_bytea Oid = 17
+ T_char Oid = 18
+ T_name Oid = 19
+ T_int8 Oid = 20
+ T_int2 Oid = 21
+ T_int2vector Oid = 22
+ T_int4 Oid = 23
+ T_regproc Oid = 24
+ T_text Oid = 25
+ T_oid Oid = 26
+ T_tid Oid = 27
+ T_xid Oid = 28
+ T_cid Oid = 29
+ T_oidvector Oid = 30
+ T_pg_ddl_command Oid = 32
+ T_pg_type Oid = 71
+ T_pg_attribute Oid = 75
+ T_pg_proc Oid = 81
+ T_pg_class Oid = 83
+ T_json Oid = 114
+ T_xml Oid = 142
+ T__xml Oid = 143
+ T_pg_node_tree Oid = 194
+ T__json Oid = 199
+ T_smgr Oid = 210
+ T_index_am_handler Oid = 325
+ T_point Oid = 600
+ T_lseg Oid = 601
+ T_path Oid = 602
+ T_box Oid = 603
+ T_polygon Oid = 604
+ T_line Oid = 628
+ T__line Oid = 629
+ T_cidr Oid = 650
+ T__cidr Oid = 651
+ T_float4 Oid = 700
+ T_float8 Oid = 701
+ T_abstime Oid = 702
+ T_reltime Oid = 703
+ T_tinterval Oid = 704
+ T_unknown Oid = 705
+ T_circle Oid = 718
+ T__circle Oid = 719
+ T_money Oid = 790
+ T__money Oid = 791
+ T_macaddr Oid = 829
+ T_inet Oid = 869
+ T__bool Oid = 1000
+ T__bytea Oid = 1001
+ T__char Oid = 1002
+ T__name Oid = 1003
+ T__int2 Oid = 1005
+ T__int2vector Oid = 1006
+ T__int4 Oid = 1007
+ T__regproc Oid = 1008
+ T__text Oid = 1009
+ T__tid Oid = 1010
+ T__xid Oid = 1011
+ T__cid Oid = 1012
+ T__oidvector Oid = 1013
+ T__bpchar Oid = 1014
+ T__varchar Oid = 1015
+ T__int8 Oid = 1016
+ T__point Oid = 1017
+ T__lseg Oid = 1018
+ T__path Oid = 1019
+ T__box Oid = 1020
+ T__float4 Oid = 1021
+ T__float8 Oid = 1022
+ T__abstime Oid = 1023
+ T__reltime Oid = 1024
+ T__tinterval Oid = 1025
+ T__polygon Oid = 1027
+ T__oid Oid = 1028
+ T_aclitem Oid = 1033
+ T__aclitem Oid = 1034
+ T__macaddr Oid = 1040
+ T__inet Oid = 1041
+ T_bpchar Oid = 1042
+ T_varchar Oid = 1043
+ T_date Oid = 1082
+ T_time Oid = 1083
+ T_timestamp Oid = 1114
+ T__timestamp Oid = 1115
+ T__date Oid = 1182
+ T__time Oid = 1183
+ T_timestamptz Oid = 1184
+ T__timestamptz Oid = 1185
+ T_interval Oid = 1186
+ T__interval Oid = 1187
+ T__numeric Oid = 1231
+ T_pg_database Oid = 1248
+ T__cstring Oid = 1263
+ T_timetz Oid = 1266
+ T__timetz Oid = 1270
+ T_bit Oid = 1560
+ T__bit Oid = 1561
+ T_varbit Oid = 1562
+ T__varbit Oid = 1563
+ T_numeric Oid = 1700
+ T_refcursor Oid = 1790
+ T__refcursor Oid = 2201
+ T_regprocedure Oid = 2202
+ T_regoper Oid = 2203
+ T_regoperator Oid = 2204
+ T_regclass Oid = 2205
+ T_regtype Oid = 2206
+ T__regprocedure Oid = 2207
+ T__regoper Oid = 2208
+ T__regoperator Oid = 2209
+ T__regclass Oid = 2210
+ T__regtype Oid = 2211
+ T_record Oid = 2249
+ T_cstring Oid = 2275
+ T_any Oid = 2276
+ T_anyarray Oid = 2277
+ T_void Oid = 2278
+ T_trigger Oid = 2279
+ T_language_handler Oid = 2280
+ T_internal Oid = 2281
+ T_opaque Oid = 2282
+ T_anyelement Oid = 2283
+ T__record Oid = 2287
+ T_anynonarray Oid = 2776
+ T_pg_authid Oid = 2842
+ T_pg_auth_members Oid = 2843
+ T__txid_snapshot Oid = 2949
+ T_uuid Oid = 2950
+ T__uuid Oid = 2951
+ T_txid_snapshot Oid = 2970
+ T_fdw_handler Oid = 3115
+ T_pg_lsn Oid = 3220
+ T__pg_lsn Oid = 3221
+ T_tsm_handler Oid = 3310
+ T_anyenum Oid = 3500
+ T_tsvector Oid = 3614
+ T_tsquery Oid = 3615
+ T_gtsvector Oid = 3642
+ T__tsvector Oid = 3643
+ T__gtsvector Oid = 3644
+ T__tsquery Oid = 3645
+ T_regconfig Oid = 3734
+ T__regconfig Oid = 3735
+ T_regdictionary Oid = 3769
+ T__regdictionary Oid = 3770
+ T_jsonb Oid = 3802
+ T__jsonb Oid = 3807
+ T_anyrange Oid = 3831
+ T_event_trigger Oid = 3838
+ T_int4range Oid = 3904
+ T__int4range Oid = 3905
+ T_numrange Oid = 3906
+ T__numrange Oid = 3907
+ T_tsrange Oid = 3908
+ T__tsrange Oid = 3909
+ T_tstzrange Oid = 3910
+ T__tstzrange Oid = 3911
+ T_daterange Oid = 3912
+ T__daterange Oid = 3913
+ T_int8range Oid = 3926
+ T__int8range Oid = 3927
+ T_pg_shseclabel Oid = 4066
+ T_regnamespace Oid = 4089
+ T__regnamespace Oid = 4090
+ T_regrole Oid = 4096
+ T__regrole Oid = 4097
+)
+
+var TypeName = map[Oid]string{
+ T_bool: "BOOL",
+ T_bytea: "BYTEA",
+ T_char: "CHAR",
+ T_name: "NAME",
+ T_int8: "INT8",
+ T_int2: "INT2",
+ T_int2vector: "INT2VECTOR",
+ T_int4: "INT4",
+ T_regproc: "REGPROC",
+ T_text: "TEXT",
+ T_oid: "OID",
+ T_tid: "TID",
+ T_xid: "XID",
+ T_cid: "CID",
+ T_oidvector: "OIDVECTOR",
+ T_pg_ddl_command: "PG_DDL_COMMAND",
+ T_pg_type: "PG_TYPE",
+ T_pg_attribute: "PG_ATTRIBUTE",
+ T_pg_proc: "PG_PROC",
+ T_pg_class: "PG_CLASS",
+ T_json: "JSON",
+ T_xml: "XML",
+ T__xml: "_XML",
+ T_pg_node_tree: "PG_NODE_TREE",
+ T__json: "_JSON",
+ T_smgr: "SMGR",
+ T_index_am_handler: "INDEX_AM_HANDLER",
+ T_point: "POINT",
+ T_lseg: "LSEG",
+ T_path: "PATH",
+ T_box: "BOX",
+ T_polygon: "POLYGON",
+ T_line: "LINE",
+ T__line: "_LINE",
+ T_cidr: "CIDR",
+ T__cidr: "_CIDR",
+ T_float4: "FLOAT4",
+ T_float8: "FLOAT8",
+ T_abstime: "ABSTIME",
+ T_reltime: "RELTIME",
+ T_tinterval: "TINTERVAL",
+ T_unknown: "UNKNOWN",
+ T_circle: "CIRCLE",
+ T__circle: "_CIRCLE",
+ T_money: "MONEY",
+ T__money: "_MONEY",
+ T_macaddr: "MACADDR",
+ T_inet: "INET",
+ T__bool: "_BOOL",
+ T__bytea: "_BYTEA",
+ T__char: "_CHAR",
+ T__name: "_NAME",
+ T__int2: "_INT2",
+ T__int2vector: "_INT2VECTOR",
+ T__int4: "_INT4",
+ T__regproc: "_REGPROC",
+ T__text: "_TEXT",
+ T__tid: "_TID",
+ T__xid: "_XID",
+ T__cid: "_CID",
+ T__oidvector: "_OIDVECTOR",
+ T__bpchar: "_BPCHAR",
+ T__varchar: "_VARCHAR",
+ T__int8: "_INT8",
+ T__point: "_POINT",
+ T__lseg: "_LSEG",
+ T__path: "_PATH",
+ T__box: "_BOX",
+ T__float4: "_FLOAT4",
+ T__float8: "_FLOAT8",
+ T__abstime: "_ABSTIME",
+ T__reltime: "_RELTIME",
+ T__tinterval: "_TINTERVAL",
+ T__polygon: "_POLYGON",
+ T__oid: "_OID",
+ T_aclitem: "ACLITEM",
+ T__aclitem: "_ACLITEM",
+ T__macaddr: "_MACADDR",
+ T__inet: "_INET",
+ T_bpchar: "BPCHAR",
+ T_varchar: "VARCHAR",
+ T_date: "DATE",
+ T_time: "TIME",
+ T_timestamp: "TIMESTAMP",
+ T__timestamp: "_TIMESTAMP",
+ T__date: "_DATE",
+ T__time: "_TIME",
+ T_timestamptz: "TIMESTAMPTZ",
+ T__timestamptz: "_TIMESTAMPTZ",
+ T_interval: "INTERVAL",
+ T__interval: "_INTERVAL",
+ T__numeric: "_NUMERIC",
+ T_pg_database: "PG_DATABASE",
+ T__cstring: "_CSTRING",
+ T_timetz: "TIMETZ",
+ T__timetz: "_TIMETZ",
+ T_bit: "BIT",
+ T__bit: "_BIT",
+ T_varbit: "VARBIT",
+ T__varbit: "_VARBIT",
+ T_numeric: "NUMERIC",
+ T_refcursor: "REFCURSOR",
+ T__refcursor: "_REFCURSOR",
+ T_regprocedure: "REGPROCEDURE",
+ T_regoper: "REGOPER",
+ T_regoperator: "REGOPERATOR",
+ T_regclass: "REGCLASS",
+ T_regtype: "REGTYPE",
+ T__regprocedure: "_REGPROCEDURE",
+ T__regoper: "_REGOPER",
+ T__regoperator: "_REGOPERATOR",
+ T__regclass: "_REGCLASS",
+ T__regtype: "_REGTYPE",
+ T_record: "RECORD",
+ T_cstring: "CSTRING",
+ T_any: "ANY",
+ T_anyarray: "ANYARRAY",
+ T_void: "VOID",
+ T_trigger: "TRIGGER",
+ T_language_handler: "LANGUAGE_HANDLER",
+ T_internal: "INTERNAL",
+ T_opaque: "OPAQUE",
+ T_anyelement: "ANYELEMENT",
+ T__record: "_RECORD",
+ T_anynonarray: "ANYNONARRAY",
+ T_pg_authid: "PG_AUTHID",
+ T_pg_auth_members: "PG_AUTH_MEMBERS",
+ T__txid_snapshot: "_TXID_SNAPSHOT",
+ T_uuid: "UUID",
+ T__uuid: "_UUID",
+ T_txid_snapshot: "TXID_SNAPSHOT",
+ T_fdw_handler: "FDW_HANDLER",
+ T_pg_lsn: "PG_LSN",
+ T__pg_lsn: "_PG_LSN",
+ T_tsm_handler: "TSM_HANDLER",
+ T_anyenum: "ANYENUM",
+ T_tsvector: "TSVECTOR",
+ T_tsquery: "TSQUERY",
+ T_gtsvector: "GTSVECTOR",
+ T__tsvector: "_TSVECTOR",
+ T__gtsvector: "_GTSVECTOR",
+ T__tsquery: "_TSQUERY",
+ T_regconfig: "REGCONFIG",
+ T__regconfig: "_REGCONFIG",
+ T_regdictionary: "REGDICTIONARY",
+ T__regdictionary: "_REGDICTIONARY",
+ T_jsonb: "JSONB",
+ T__jsonb: "_JSONB",
+ T_anyrange: "ANYRANGE",
+ T_event_trigger: "EVENT_TRIGGER",
+ T_int4range: "INT4RANGE",
+ T__int4range: "_INT4RANGE",
+ T_numrange: "NUMRANGE",
+ T__numrange: "_NUMRANGE",
+ T_tsrange: "TSRANGE",
+ T__tsrange: "_TSRANGE",
+ T_tstzrange: "TSTZRANGE",
+ T__tstzrange: "_TSTZRANGE",
+ T_daterange: "DATERANGE",
+ T__daterange: "_DATERANGE",
+ T_int8range: "INT8RANGE",
+ T__int8range: "_INT8RANGE",
+ T_pg_shseclabel: "PG_SHSECLABEL",
+ T_regnamespace: "REGNAMESPACE",
+ T__regnamespace: "_REGNAMESPACE",
+ T_regrole: "REGROLE",
+ T__regrole: "_REGROLE",
+}
diff --git a/vendor/github.com/lib/pq/rows.go b/vendor/github.com/lib/pq/rows.go
new file mode 100644
index 0000000..c6aa5b9
--- /dev/null
+++ b/vendor/github.com/lib/pq/rows.go
@@ -0,0 +1,93 @@
+package pq
+
+import (
+ "math"
+ "reflect"
+ "time"
+
+ "github.com/lib/pq/oid"
+)
+
+const headerSize = 4
+
+type fieldDesc struct {
+ // The object ID of the data type.
+ OID oid.Oid
+ // The data type size (see pg_type.typlen).
+ // Note that negative values denote variable-width types.
+ Len int
+ // The type modifier (see pg_attribute.atttypmod).
+ // The meaning of the modifier is type-specific.
+ Mod int
+}
+
+func (fd fieldDesc) Type() reflect.Type {
+ switch fd.OID {
+ case oid.T_int8:
+ return reflect.TypeOf(int64(0))
+ case oid.T_int4:
+ return reflect.TypeOf(int32(0))
+ case oid.T_int2:
+ return reflect.TypeOf(int16(0))
+ case oid.T_varchar, oid.T_text:
+ return reflect.TypeOf("")
+ case oid.T_bool:
+ return reflect.TypeOf(false)
+ case oid.T_date, oid.T_time, oid.T_timetz, oid.T_timestamp, oid.T_timestamptz:
+ return reflect.TypeOf(time.Time{})
+ case oid.T_bytea:
+ return reflect.TypeOf([]byte(nil))
+ default:
+ return reflect.TypeOf(new(interface{})).Elem()
+ }
+}
+
+func (fd fieldDesc) Name() string {
+ return oid.TypeName[fd.OID]
+}
+
+func (fd fieldDesc) Length() (length int64, ok bool) {
+ switch fd.OID {
+ case oid.T_text, oid.T_bytea:
+ return math.MaxInt64, true
+ case oid.T_varchar, oid.T_bpchar:
+ return int64(fd.Mod - headerSize), true
+ default:
+ return 0, false
+ }
+}
+
+func (fd fieldDesc) PrecisionScale() (precision, scale int64, ok bool) {
+ switch fd.OID {
+ case oid.T_numeric, oid.T__numeric:
+ mod := fd.Mod - headerSize
+ precision = int64((mod >> 16) & 0xffff)
+ scale = int64(mod & 0xffff)
+ return precision, scale, true
+ default:
+ return 0, 0, false
+ }
+}
+
+// ColumnTypeScanType returns the value type that can be used to scan types into.
+func (rs *rows) ColumnTypeScanType(index int) reflect.Type {
+ return rs.colTyps[index].Type()
+}
+
+// ColumnTypeDatabaseTypeName return the database system type name.
+func (rs *rows) ColumnTypeDatabaseTypeName(index int) string {
+ return rs.colTyps[index].Name()
+}
+
+// ColumnTypeLength returns the length of the column type if the column is a
+// variable length type. If the column is not a variable length type ok
+// should return false.
+func (rs *rows) ColumnTypeLength(index int) (length int64, ok bool) {
+ return rs.colTyps[index].Length()
+}
+
+// ColumnTypePrecisionScale should return the precision and scale for decimal
+// types. If not applicable, ok should be false.
+func (rs *rows) ColumnTypePrecisionScale(index int) (precision, scale int64, ok bool) {
+ return rs.colTyps[index].PrecisionScale()
+}
diff --git a/vendor/github.com/lib/pq/scram/scram.go b/vendor/github.com/lib/pq/scram/scram.go
new file mode 100644
index 0000000..477216b
--- /dev/null
+++ b/vendor/github.com/lib/pq/scram/scram.go
@@ -0,0 +1,264 @@
+// Copyright (c) 2014 - Gustavo Niemeyer
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+// 2. 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.
+//
+// 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.
+
+// Package scram implements a SCRAM-{SHA-1,etc} client per RFC5802.
+//
+// http://tools.ietf.org/html/rfc5802
+//
+package scram
+
+import (
+ "bytes"
+ "crypto/hmac"
+ "crypto/rand"
+ "encoding/base64"
+ "fmt"
+ "hash"
+ "strconv"
+ "strings"
+)
+
+// Client implements a SCRAM-* client (SCRAM-SHA-1, SCRAM-SHA-256, etc).
+//
+// A Client may be used within a SASL conversation with logic resembling:
+//
+// var in []byte
+// var client = scram.NewClient(sha1.New, user, pass)
+// for client.Step(in) {
+// out := client.Out()
+// // send out to server
+// in := serverOut
+// }
+// if client.Err() != nil {
+// // auth failed
+// }
+//
+type Client struct {
+ newHash func() hash.Hash
+
+ user string
+ pass string
+ step int
+ out bytes.Buffer
+ err error
+
+ clientNonce []byte
+ serverNonce []byte
+ saltedPass []byte
+ authMsg bytes.Buffer
+}
+
+// NewClient returns a new SCRAM-* client with the provided hash algorithm.
+//
+// For SCRAM-SHA-256, for example, use:
+//
+// client := scram.NewClient(sha256.New, user, pass)
+//
+func NewClient(newHash func() hash.Hash, user, pass string) *Client {
+ c := &Client{
+ newHash: newHash,
+ user: user,
+ pass: pass,
+ }
+ c.out.Grow(256)
+ c.authMsg.Grow(256)
+ return c
+}
+
+// Out returns the data to be sent to the server in the current step.
+func (c *Client) Out() []byte {
+ if c.out.Len() == 0 {
+ return nil
+ }
+ return c.out.Bytes()
+}
+
+// Err returns the error that occurred, or nil if there were no errors.
+func (c *Client) Err() error {
+ return c.err
+}
+
+// SetNonce sets the client nonce to the provided value.
+// If not set, the nonce is generated automatically out of crypto/rand on the first step.
+func (c *Client) SetNonce(nonce []byte) {
+ c.clientNonce = nonce
+}
+
+var escaper = strings.NewReplacer("=", "=3D", ",", "=2C")
+
+// Step processes the incoming data from the server and makes the
+// next round of data for the server available via Client.Out.
+// Step returns false if there are no errors and more data is
+// still expected.
+func (c *Client) Step(in []byte) bool {
+ c.out.Reset()
+ if c.step > 2 || c.err != nil {
+ return false
+ }
+ c.step++
+ switch c.step {
+ case 1:
+ c.err = c.step1(in)
+ case 2:
+ c.err = c.step2(in)
+ case 3:
+ c.err = c.step3(in)
+ }
+ return c.step > 2 || c.err != nil
+}
+
+func (c *Client) step1(in []byte) error {
+ if len(c.clientNonce) == 0 {
+ const nonceLen = 16
+ buf := make([]byte, nonceLen+b64.EncodedLen(nonceLen))
+ if _, err := rand.Read(buf[:nonceLen]); err != nil {
+ return fmt.Errorf("cannot read random SCRAM-SHA-256 nonce from operating system: %v", err)
+ }
+ c.clientNonce = buf[nonceLen:]
+ b64.Encode(c.clientNonce, buf[:nonceLen])
+ }
+ c.authMsg.WriteString("n=")
+ escaper.WriteString(&c.authMsg, c.user)
+ c.authMsg.WriteString(",r=")
+ c.authMsg.Write(c.clientNonce)
+
+ c.out.WriteString("n,,")
+ c.out.Write(c.authMsg.Bytes())
+ return nil
+}
+
+var b64 = base64.StdEncoding
+
+func (c *Client) step2(in []byte) error {
+ c.authMsg.WriteByte(',')
+ c.authMsg.Write(in)
+
+ fields := bytes.Split(in, []byte(","))
+ if len(fields) != 3 {
+ return fmt.Errorf("expected 3 fields in first SCRAM-SHA-256 server message, got %d: %q", len(fields), in)
+ }
+ if !bytes.HasPrefix(fields[0], []byte("r=")) || len(fields[0]) < 2 {
+ return fmt.Errorf("server sent an invalid SCRAM-SHA-256 nonce: %q", fields[0])
+ }
+ if !bytes.HasPrefix(fields[1], []byte("s=")) || len(fields[1]) < 6 {
+ return fmt.Errorf("server sent an invalid SCRAM-SHA-256 salt: %q", fields[1])
+ }
+ if !bytes.HasPrefix(fields[2], []byte("i=")) || len(fields[2]) < 6 {
+ return fmt.Errorf("server sent an invalid SCRAM-SHA-256 iteration count: %q", fields[2])
+ }
+
+ c.serverNonce = fields[0][2:]
+ if !bytes.HasPrefix(c.serverNonce, c.clientNonce) {
+ return fmt.Errorf("server SCRAM-SHA-256 nonce is not prefixed by client nonce: got %q, want %q+\"...\"", c.serverNonce, c.clientNonce)
+ }
+
+ salt := make([]byte, b64.DecodedLen(len(fields[1][2:])))
+ n, err := b64.Decode(salt, fields[1][2:])
+ if err != nil {
+ return fmt.Errorf("cannot decode SCRAM-SHA-256 salt sent by server: %q", fields[1])
+ }
+ salt = salt[:n]
+ iterCount, err := strconv.Atoi(string(fields[2][2:]))
+ if err != nil {
+ return fmt.Errorf("server sent an invalid SCRAM-SHA-256 iteration count: %q", fields[2])
+ }
+ c.saltPassword(salt, iterCount)
+
+ c.authMsg.WriteString(",c=biws,r=")
+ c.authMsg.Write(c.serverNonce)
+
+ c.out.WriteString("c=biws,r=")
+ c.out.Write(c.serverNonce)
+ c.out.WriteString(",p=")
+ c.out.Write(c.clientProof())
+ return nil
+}
+
+func (c *Client) step3(in []byte) error {
+ var isv, ise bool
+ var fields = bytes.Split(in, []byte(","))
+ if len(fields) == 1 {
+ isv = bytes.HasPrefix(fields[0], []byte("v="))
+ ise = bytes.HasPrefix(fields[0], []byte("e="))
+ }
+ if ise {
+ return fmt.Errorf("SCRAM-SHA-256 authentication error: %s", fields[0][2:])
+ } else if !isv {
+ return fmt.Errorf("unsupported SCRAM-SHA-256 final message from server: %q", in)
+ }
+ if !bytes.Equal(c.serverSignature(), fields[0][2:]) {
+ return fmt.Errorf("cannot authenticate SCRAM-SHA-256 server signature: %q", fields[0][2:])
+ }
+ return nil
+}
+
+func (c *Client) saltPassword(salt []byte, iterCount int) {
+ mac := hmac.New(c.newHash, []byte(c.pass))
+ mac.Write(salt)
+ mac.Write([]byte{0, 0, 0, 1})
+ ui := mac.Sum(nil)
+ hi := make([]byte, len(ui))
+ copy(hi, ui)
+ for i := 1; i < iterCount; i++ {
+ mac.Reset()
+ mac.Write(ui)
+ mac.Sum(ui[:0])
+ for j, b := range ui {
+ hi[j] ^= b
+ }
+ }
+ c.saltedPass = hi
+}
+
+func (c *Client) clientProof() []byte {
+ mac := hmac.New(c.newHash, c.saltedPass)
+ mac.Write([]byte("Client Key"))
+ clientKey := mac.Sum(nil)
+ hash := c.newHash()
+ hash.Write(clientKey)
+ storedKey := hash.Sum(nil)
+ mac = hmac.New(c.newHash, storedKey)
+ mac.Write(c.authMsg.Bytes())
+ clientProof := mac.Sum(nil)
+ for i, b := range clientKey {
+ clientProof[i] ^= b
+ }
+ clientProof64 := make([]byte, b64.EncodedLen(len(clientProof)))
+ b64.Encode(clientProof64, clientProof)
+ return clientProof64
+}
+
+func (c *Client) serverSignature() []byte {
+ mac := hmac.New(c.newHash, c.saltedPass)
+ mac.Write([]byte("Server Key"))
+ serverKey := mac.Sum(nil)
+
+ mac = hmac.New(c.newHash, serverKey)
+ mac.Write(c.authMsg.Bytes())
+ serverSignature := mac.Sum(nil)
+
+ encoded := make([]byte, b64.EncodedLen(len(serverSignature)))
+ b64.Encode(encoded, serverSignature)
+ return encoded
+}
diff --git a/vendor/github.com/lib/pq/ssl.go b/vendor/github.com/lib/pq/ssl.go
new file mode 100644
index 0000000..36b61ba
--- /dev/null
+++ b/vendor/github.com/lib/pq/ssl.go
@@ -0,0 +1,204 @@
+package pq
+
+import (
+ "crypto/tls"
+ "crypto/x509"
+ "io/ioutil"
+ "net"
+ "os"
+ "os/user"
+ "path/filepath"
+ "strings"
+)
+
+// ssl generates a function to upgrade a net.Conn based on the "sslmode" and
+// related settings. The function is nil when no upgrade should take place.
+func ssl(o values) (func(net.Conn) (net.Conn, error), error) {
+ verifyCaOnly := false
+ tlsConf := tls.Config{}
+ switch mode := o["sslmode"]; mode {
+ // "require" is the default.
+ case "", "require":
+ // We must skip TLS's own verification since it requires full
+ // verification since Go 1.3.
+ tlsConf.InsecureSkipVerify = true
+
+ // From http://www.postgresql.org/docs/current/static/libpq-ssl.html:
+ //
+ // Note: For backwards compatibility with earlier versions of
+ // PostgreSQL, if a root CA file exists, the behavior of
+ // sslmode=require will be the same as that of verify-ca, meaning the
+ // server certificate is validated against the CA. Relying on this
+ // behavior is discouraged, and applications that need certificate
+ // validation should always use verify-ca or verify-full.
+ if sslrootcert, ok := o["sslrootcert"]; ok {
+ if _, err := os.Stat(sslrootcert); err == nil {
+ verifyCaOnly = true
+ } else {
+ delete(o, "sslrootcert")
+ }
+ }
+ case "verify-ca":
+ // We must skip TLS's own verification since it requires full
+ // verification since Go 1.3.
+ tlsConf.InsecureSkipVerify = true
+ verifyCaOnly = true
+ case "verify-full":
+ tlsConf.ServerName = o["host"]
+ case "disable":
+ return nil, nil
+ default:
+ return nil, fmterrorf(`unsupported sslmode %q; only "require" (default), "verify-full", "verify-ca", and "disable" supported`, mode)
+ }
+
+ // Set Server Name Indication (SNI), if enabled by connection parameters.
+ // By default SNI is on, any value which is not starting with "1" disables
+ // SNI -- that is the same check vanilla libpq uses.
+ if sslsni := o["sslsni"]; sslsni == "" || strings.HasPrefix(sslsni, "1") {
+ // RFC 6066 asks to not set SNI if the host is a literal IP address (IPv4
+ // or IPv6). This check is coded already crypto.tls.hostnameInSNI, so
+ // just always set ServerName here and let crypto/tls do the filtering.
+ tlsConf.ServerName = o["host"]
+ }
+
+ err := sslClientCertificates(&tlsConf, o)
+ if err != nil {
+ return nil, err
+ }
+ err = sslCertificateAuthority(&tlsConf, o)
+ if err != nil {
+ return nil, err
+ }
+
+ // Accept renegotiation requests initiated by the backend.
+ //
+ // Renegotiation was deprecated then removed from PostgreSQL 9.5, but
+ // the default configuration of older versions has it enabled. Redshift
+ // also initiates renegotiations and cannot be reconfigured.
+ tlsConf.Renegotiation = tls.RenegotiateFreelyAsClient
+
+ return func(conn net.Conn) (net.Conn, error) {
+ client := tls.Client(conn, &tlsConf)
+ if verifyCaOnly {
+ err := sslVerifyCertificateAuthority(client, &tlsConf)
+ if err != nil {
+ return nil, err
+ }
+ }
+ return client, nil
+ }, nil
+}
+
+// sslClientCertificates adds the certificate specified in the "sslcert" and
+// "sslkey" settings, or if they aren't set, from the .postgresql directory
+// in the user's home directory. The configured files must exist and have
+// the correct permissions.
+func sslClientCertificates(tlsConf *tls.Config, o values) error {
+ sslinline := o["sslinline"]
+ if sslinline == "true" {
+ cert, err := tls.X509KeyPair([]byte(o["sslcert"]), []byte(o["sslkey"]))
+ if err != nil {
+ return err
+ }
+ tlsConf.Certificates = []tls.Certificate{cert}
+ return nil
+ }
+
+ // user.Current() might fail when cross-compiling. We have to ignore the
+ // error and continue without home directory defaults, since we wouldn't
+ // know from where to load them.
+ user, _ := user.Current()
+
+ // In libpq, the client certificate is only loaded if the setting is not blank.
+ //
+ // https://github.com/postgres/postgres/blob/REL9_6_2/src/interfaces/libpq/fe-secure-openssl.c#L1036-L1037
+ sslcert := o["sslcert"]
+ if len(sslcert) == 0 && user != nil {
+ sslcert = filepath.Join(user.HomeDir, ".postgresql", "postgresql.crt")
+ }
+ // https://github.com/postgres/postgres/blob/REL9_6_2/src/interfaces/libpq/fe-secure-openssl.c#L1045
+ if len(sslcert) == 0 {
+ return nil
+ }
+ // https://github.com/postgres/postgres/blob/REL9_6_2/src/interfaces/libpq/fe-secure-openssl.c#L1050:L1054
+ if _, err := os.Stat(sslcert); os.IsNotExist(err) {
+ return nil
+ } else if err != nil {
+ return err
+ }
+
+ // In libpq, the ssl key is only loaded if the setting is not blank.
+ //
+ // https://github.com/postgres/postgres/blob/REL9_6_2/src/interfaces/libpq/fe-secure-openssl.c#L1123-L1222
+ sslkey := o["sslkey"]
+ if len(sslkey) == 0 && user != nil {
+ sslkey = filepath.Join(user.HomeDir, ".postgresql", "postgresql.key")
+ }
+
+ if len(sslkey) > 0 {
+ if err := sslKeyPermissions(sslkey); err != nil {
+ return err
+ }
+ }
+
+ cert, err := tls.LoadX509KeyPair(sslcert, sslkey)
+ if err != nil {
+ return err
+ }
+
+ tlsConf.Certificates = []tls.Certificate{cert}
+ return nil
+}
+
+// sslCertificateAuthority adds the RootCA specified in the "sslrootcert" setting.
+func sslCertificateAuthority(tlsConf *tls.Config, o values) error {
+ // In libpq, the root certificate is only loaded if the setting is not blank.
+ //
+ // https://github.com/postgres/postgres/blob/REL9_6_2/src/interfaces/libpq/fe-secure-openssl.c#L950-L951
+ if sslrootcert := o["sslrootcert"]; len(sslrootcert) > 0 {
+ tlsConf.RootCAs = x509.NewCertPool()
+
+ sslinline := o["sslinline"]
+
+ var cert []byte
+ if sslinline == "true" {
+ cert = []byte(sslrootcert)
+ } else {
+ var err error
+ cert, err = ioutil.ReadFile(sslrootcert)
+ if err != nil {
+ return err
+ }
+ }
+
+ if !tlsConf.RootCAs.AppendCertsFromPEM(cert) {
+ return fmterrorf("couldn't parse pem in sslrootcert")
+ }
+ }
+
+ return nil
+}
+
+// sslVerifyCertificateAuthority carries out a TLS handshake to the server and
+// verifies the presented certificate against the CA, i.e. the one specified in
+// sslrootcert or the system CA if sslrootcert was not specified.
+func sslVerifyCertificateAuthority(client *tls.Conn, tlsConf *tls.Config) error {
+ err := client.Handshake()
+ if err != nil {
+ return err
+ }
+ certs := client.ConnectionState().PeerCertificates
+ opts := x509.VerifyOptions{
+ DNSName: client.ConnectionState().ServerName,
+ Intermediates: x509.NewCertPool(),
+ Roots: tlsConf.RootCAs,
+ }
+ for i, cert := range certs {
+ if i == 0 {
+ continue
+ }
+ opts.Intermediates.AddCert(cert)
+ }
+ _, err = certs[0].Verify(opts)
+ return err
+}
diff --git a/vendor/github.com/lib/pq/ssl_permissions.go b/vendor/github.com/lib/pq/ssl_permissions.go
new file mode 100644
index 0000000..d587f10
--- /dev/null
+++ b/vendor/github.com/lib/pq/ssl_permissions.go
@@ -0,0 +1,93 @@
+//go:build !windows
+// +build !windows
+
+package pq
+
+import (
+ "errors"
+ "os"
+ "syscall"
+)
+
+const (
+ rootUserID = uint32(0)
+
+ // The maximum permissions that a private key file owned by a regular user
+ // is allowed to have. This translates to u=rw.
+ maxUserOwnedKeyPermissions os.FileMode = 0600
+
+ // The maximum permissions that a private key file owned by root is allowed
+ // to have. This translates to u=rw,g=r.
+ maxRootOwnedKeyPermissions os.FileMode = 0640
+)
+
+var (
+ errSSLKeyHasUnacceptableUserPermissions = errors.New("permissions for files not owned by root should be u=rw (0600) or less")
+ errSSLKeyHasUnacceptableRootPermissions = errors.New("permissions for root owned files should be u=rw,g=r (0640) or less")
+)
+
+// sslKeyPermissions checks the permissions on user-supplied ssl key files.
+// The key file should have very little access.
+//
+// libpq does not check key file permissions on Windows.
+func sslKeyPermissions(sslkey string) error {
+ info, err := os.Stat(sslkey)
+ if err != nil {
+ return err
+ }
+
+ err = hasCorrectPermissions(info)
+
+ // return ErrSSLKeyHasWorldPermissions for backwards compatability with
+ // existing code.
+ if err == errSSLKeyHasUnacceptableUserPermissions || err == errSSLKeyHasUnacceptableRootPermissions {
+ err = ErrSSLKeyHasWorldPermissions
+ }
+ return err
+}
+
+// hasCorrectPermissions checks the file info (and the unix-specific stat_t
+// output) to verify that the permissions on the file are correct.
+//
+// If the file is owned by the same user the process is running as,
+// the file should only have 0600 (u=rw). If the file is owned by root,
+// and the group matches the group that the process is running in, the
+// permissions cannot be more than 0640 (u=rw,g=r). The file should
+// never have world permissions.
+//
+// Returns an error when the permission check fails.
+func hasCorrectPermissions(info os.FileInfo) error {
+ // if file's permission matches 0600, allow access.
+ userPermissionMask := (os.FileMode(0777) ^ maxUserOwnedKeyPermissions)
+
+ // regardless of if we're running as root or not, 0600 is acceptable,
+ // so we return if we match the regular user permission mask.
+ if info.Mode().Perm()&userPermissionMask == 0 {
+ return nil
+ }
+
+ // We need to pull the Unix file information to get the file's owner.
+ // If we can't access it, there's some sort of operating system level error
+ // and we should fail rather than attempting to use faulty information.
+ sysInfo := info.Sys()
+ if sysInfo == nil {
+ return ErrSSLKeyUnknownOwnership
+ }
+
+ unixStat, ok := sysInfo.(*syscall.Stat_t)
+ if !ok {
+ return ErrSSLKeyUnknownOwnership
+ }
+
+ // if the file is owned by root, we allow 0640 (u=rw,g=r) to match what
+ // Postgres does.
+ if unixStat.Uid == rootUserID {
+ rootPermissionMask := (os.FileMode(0777) ^ maxRootOwnedKeyPermissions)
+ if info.Mode().Perm()&rootPermissionMask != 0 {
+ return errSSLKeyHasUnacceptableRootPermissions
+ }
+ return nil
+ }
+
+ return errSSLKeyHasUnacceptableUserPermissions
+}
diff --git a/vendor/github.com/lib/pq/ssl_windows.go b/vendor/github.com/lib/pq/ssl_windows.go
new file mode 100644
index 0000000..73663c8
--- /dev/null
+++ b/vendor/github.com/lib/pq/ssl_windows.go
@@ -0,0 +1,10 @@
+//go:build windows
+// +build windows
+
+package pq
+
+// sslKeyPermissions checks the permissions on user-supplied ssl key files.
+// The key file should have very little access.
+//
+// libpq does not check key file permissions on Windows.
+func sslKeyPermissions(string) error { return nil }
diff --git a/vendor/github.com/lib/pq/url.go b/vendor/github.com/lib/pq/url.go
new file mode 100644
index 0000000..aec6e95
--- /dev/null
+++ b/vendor/github.com/lib/pq/url.go
@@ -0,0 +1,76 @@
+package pq
+
+import (
+ "fmt"
+ "net"
+ nurl "net/url"
+ "sort"
+ "strings"
+)
+
+// ParseURL no longer needs to be used by clients of this library since supplying a URL as a
+// connection string to sql.Open() is now supported:
+//
+// sql.Open("postgres", "postgres://bob:secret@1.2.3.4:5432/mydb?sslmode=verify-full")
+//
+// It remains exported here for backwards-compatibility.
+//
+// ParseURL converts a url to a connection string for driver.Open.
+// Example:
+//
+// "postgres://bob:secret@1.2.3.4:5432/mydb?sslmode=verify-full"
+//
+// converts to:
+//
+// "user=bob password=secret host=1.2.3.4 port=5432 dbname=mydb sslmode=verify-full"
+//
+// A minimal example:
+//
+// "postgres://"
+//
+// This will be blank, causing driver.Open to use all of the defaults
+func ParseURL(url string) (string, error) {
+ u, err := nurl.Parse(url)
+ if err != nil {
+ return "", err
+ }
+
+ if u.Scheme != "postgres" && u.Scheme != "postgresql" {
+ return "", fmt.Errorf("invalid connection protocol: %s", u.Scheme)
+ }
+
+ var kvs []string
+ escaper := strings.NewReplacer(`'`, `\'`, `\`, `\\`)
+ accrue := func(k, v string) {
+ if v != "" {
+ kvs = append(kvs, k+"='"+escaper.Replace(v)+"'")
+ }
+ }
+
+ if u.User != nil {
+ v := u.User.Username()
+ accrue("user", v)
+
+ v, _ = u.User.Password()
+ accrue("password", v)
+ }
+
+ if host, port, err := net.SplitHostPort(u.Host); err != nil {
+ accrue("host", u.Host)
+ } else {
+ accrue("host", host)
+ accrue("port", port)
+ }
+
+ if u.Path != "" {
+ accrue("dbname", u.Path[1:])
+ }
+
+ q := u.Query()
+ for k := range q {
+ accrue(k, q.Get(k))
+ }
+
+ sort.Strings(kvs) // Makes testing easier (not a performance concern)
+ return strings.Join(kvs, " "), nil
+}
diff --git a/vendor/github.com/lib/pq/user_other.go b/vendor/github.com/lib/pq/user_other.go
new file mode 100644
index 0000000..3dae8f5
--- /dev/null
+++ b/vendor/github.com/lib/pq/user_other.go
@@ -0,0 +1,10 @@
+// Package pq is a pure Go Postgres driver for the database/sql package.
+
+//go:build js || android || hurd || zos
+// +build js android hurd zos
+
+package pq
+
+func userCurrent() (string, error) {
+ return "", ErrCouldNotDetectUsername
+}
diff --git a/vendor/github.com/lib/pq/user_posix.go b/vendor/github.com/lib/pq/user_posix.go
new file mode 100644
index 0000000..5f2d439
--- /dev/null
+++ b/vendor/github.com/lib/pq/user_posix.go
@@ -0,0 +1,25 @@
+// Package pq is a pure Go Postgres driver for the database/sql package.
+
+//go:build aix || darwin || dragonfly || freebsd || (linux && !android) || nacl || netbsd || openbsd || plan9 || solaris || rumprun || illumos
+// +build aix darwin dragonfly freebsd linux,!android nacl netbsd openbsd plan9 solaris rumprun illumos
+
+package pq
+
+import (
+ "os"
+ "os/user"
+)
+
+func userCurrent() (string, error) {
+ u, err := user.Current()
+ if err == nil {
+ return u.Username, nil
+ }
+
+ name := os.Getenv("USER")
+ if name != "" {
+ return name, nil
+ }
+
+ return "", ErrCouldNotDetectUsername
+}
diff --git a/vendor/github.com/lib/pq/user_windows.go b/vendor/github.com/lib/pq/user_windows.go
new file mode 100644
index 0000000..2b69126
--- /dev/null
+++ b/vendor/github.com/lib/pq/user_windows.go
@@ -0,0 +1,27 @@
+// Package pq is a pure Go Postgres driver for the database/sql package.
+package pq
+
+import (
+ "path/filepath"
+ "syscall"
+)
+
+// Perform Windows user name lookup identically to libpq.
+//
+// The PostgreSQL code makes use of the legacy Win32 function
+// GetUserName, and that function has not been imported into stock Go.
+// GetUserNameEx is available though, the difference being that a
+// wider range of names are available. To get the output to be the
+// same as GetUserName, only the base (or last) component of the
+// result is returned.
+func userCurrent() (string, error) {
+ pw_name := make([]uint16, 128)
+ pwname_size := uint32(len(pw_name)) - 1
+ err := syscall.GetUserNameEx(syscall.NameSamCompatible, &pw_name[0], &pwname_size)
+ if err != nil {
+ return "", ErrCouldNotDetectUsername
+ }
+ s := syscall.UTF16ToString(pw_name)
+ u := filepath.Base(s)
+ return u, nil
+}
diff --git a/vendor/github.com/lib/pq/uuid.go b/vendor/github.com/lib/pq/uuid.go
new file mode 100644
index 0000000..9a1b9e0
--- /dev/null
+++ b/vendor/github.com/lib/pq/uuid.go
@@ -0,0 +1,23 @@
+package pq
+
+import (
+ "encoding/hex"
+ "fmt"
+)
+
+// decodeUUIDBinary interprets the binary format of a uuid, returning it in text format.
+func decodeUUIDBinary(src []byte) ([]byte, error) {
+ if len(src) != 16 {
+ return nil, fmt.Errorf("pq: unable to decode uuid; bad length: %d", len(src))
+ }
+
+ dst := make([]byte, 36)
+ dst[8], dst[13], dst[18], dst[23] = '-', '-', '-', '-'
+ hex.Encode(dst[0:], src[0:4])
+ hex.Encode(dst[9:], src[4:6])
+ hex.Encode(dst[14:], src[6:8])
+ hex.Encode(dst[19:], src[8:10])
+ hex.Encode(dst[24:], src[10:16])
+
+ return dst, nil
+}
diff --git a/vendor/github.com/mailru/easyjson/.gitignore b/vendor/github.com/mailru/easyjson/.gitignore
new file mode 100644
index 0000000..fbfaf7a
--- /dev/null
+++ b/vendor/github.com/mailru/easyjson/.gitignore
@@ -0,0 +1,6 @@
+.root
+*_easyjson.go
+*.iml
+.idea
+*.swp
+bin/*
diff --git a/vendor/github.com/mailru/easyjson/.travis.yml b/vendor/github.com/mailru/easyjson/.travis.yml
new file mode 100644
index 0000000..1e0fa4c
--- /dev/null
+++ b/vendor/github.com/mailru/easyjson/.travis.yml
@@ -0,0 +1,15 @@
+arch:
+ - amd64
+ - ppc64le
+language: go
+
+go:
+ - tip
+ - stable
+
+matrix:
+ allow_failures:
+ - go: tip
+
+install:
+ - go get golang.org/x/lint/golint
diff --git a/vendor/github.com/mailru/easyjson/LICENSE b/vendor/github.com/mailru/easyjson/LICENSE
new file mode 100644
index 0000000..fbff658
--- /dev/null
+++ b/vendor/github.com/mailru/easyjson/LICENSE
@@ -0,0 +1,7 @@
+Copyright (c) 2016 Mail.Ru Group
+
+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/mailru/easyjson/Makefile b/vendor/github.com/mailru/easyjson/Makefile
new file mode 100644
index 0000000..c527340
--- /dev/null
+++ b/vendor/github.com/mailru/easyjson/Makefile
@@ -0,0 +1,72 @@
+all: test
+
+clean:
+ rm -rf bin
+ rm -rf tests/*_easyjson.go
+ rm -rf benchmark/*_easyjson.go
+
+build:
+ go build -i -o ./bin/easyjson ./easyjson
+
+generate: build
+ bin/easyjson -stubs \
+ ./tests/snake.go \
+ ./tests/data.go \
+ ./tests/omitempty.go \
+ ./tests/nothing.go \
+ ./tests/named_type.go \
+ ./tests/custom_map_key_type.go \
+ ./tests/embedded_type.go \
+ ./tests/reference_to_pointer.go \
+ ./tests/html.go \
+ ./tests/unknown_fields.go \
+ ./tests/type_declaration.go \
+ ./tests/type_declaration_skip.go \
+ ./tests/members_escaped.go \
+ ./tests/members_unescaped.go \
+ ./tests/intern.go \
+ ./tests/nocopy.go \
+ ./tests/escaping.go
+ bin/easyjson -all \
+ ./tests/data.go \
+ ./tests/nothing.go \
+ ./tests/errors.go \
+ ./tests/html.go \
+ ./tests/type_declaration_skip.go
+ bin/easyjson \
+ ./tests/nested_easy.go \
+ ./tests/named_type.go \
+ ./tests/custom_map_key_type.go \
+ ./tests/embedded_type.go \
+ ./tests/reference_to_pointer.go \
+ ./tests/key_marshaler_map.go \
+ ./tests/unknown_fields.go \
+ ./tests/type_declaration.go \
+ ./tests/members_escaped.go \
+ ./tests/intern.go \
+ ./tests/nocopy.go \
+ ./tests/escaping.go \
+ ./tests/nested_marshaler.go
+ bin/easyjson -snake_case ./tests/snake.go
+ bin/easyjson -omit_empty ./tests/omitempty.go
+ bin/easyjson -build_tags=use_easyjson -disable_members_unescape ./benchmark/data.go
+ bin/easyjson -disallow_unknown_fields ./tests/disallow_unknown.go
+ bin/easyjson -disable_members_unescape ./tests/members_unescaped.go
+
+test: generate
+ go test \
+ ./tests \
+ ./jlexer \
+ ./gen \
+ ./buffer
+ cd benchmark && go test -benchmem -tags use_easyjson -bench .
+ golint -set_exit_status ./tests/*_easyjson.go
+
+bench-other: generate
+ cd benchmark && make
+
+bench-python:
+ benchmark/ujson.sh
+
+
+.PHONY: clean generate test build
diff --git a/vendor/github.com/mailru/easyjson/README.md b/vendor/github.com/mailru/easyjson/README.md
new file mode 100644
index 0000000..952575b
--- /dev/null
+++ b/vendor/github.com/mailru/easyjson/README.md
@@ -0,0 +1,387 @@
+# easyjson [![Build Status](https://travis-ci.org/mailru/easyjson.svg?branch=master)](https://travis-ci.org/mailru/easyjson) [![Go Report Card](https://goreportcard.com/badge/github.com/mailru/easyjson)](https://goreportcard.com/report/github.com/mailru/easyjson)
+
+Package easyjson provides a fast and easy way to marshal/unmarshal Go structs
+to/from JSON without the use of reflection. In performance tests, easyjson
+outperforms the standard `encoding/json` package by a factor of 4-5x, and other
+JSON encoding packages by a factor of 2-3x.
+
+easyjson aims to keep generated Go code simple enough so that it can be easily
+optimized or fixed. Another goal is to provide users with the ability to
+customize the generated code by providing options not available with the
+standard `encoding/json` package, such as generating "snake_case" names or
+enabling `omitempty` behavior by default.
+
+## Usage
+```sh
+# install
+go get -u github.com/mailru/easyjson/...
+
+# run
+easyjson -all .go
+```
+
+The above will generate `_easyjson.go` containing the appropriate marshaler and
+unmarshaler funcs for all structs contained in `.go`.
+
+Please note that easyjson requires a full Go build environment and the `GOPATH`
+environment variable to be set. This is because easyjson code generation
+invokes `go run` on a temporary file (an approach to code generation borrowed
+from [ffjson](https://github.com/pquerna/ffjson)).
+
+## Options
+```txt
+Usage of easyjson:
+ -all
+ generate marshaler/unmarshalers for all structs in a file
+ -build_tags string
+ build tags to add to generated file
+ -gen_build_flags string
+ build flags when running the generator while bootstrapping
+ -byte
+ use simple bytes instead of Base64Bytes for slice of bytes
+ -leave_temps
+ do not delete temporary files
+ -no_std_marshalers
+ don't generate MarshalJSON/UnmarshalJSON funcs
+ -noformat
+ do not run 'gofmt -w' on output file
+ -omit_empty
+ omit empty fields by default
+ -output_filename string
+ specify the filename of the output
+ -pkg
+ process the whole package instead of just the given file
+ -snake_case
+ use snake_case names instead of CamelCase by default
+ -lower_camel_case
+ use lowerCamelCase instead of CamelCase by default
+ -stubs
+ only generate stubs for marshaler/unmarshaler funcs
+ -disallow_unknown_fields
+ return error if some unknown field in json appeared
+ -disable_members_unescape
+ disable unescaping of \uXXXX string sequences in member names
+```
+
+Using `-all` will generate marshalers/unmarshalers for all Go structs in the
+file excluding those structs whose preceding comment starts with `easyjson:skip`.
+For example:
+
+```go
+//easyjson:skip
+type A struct {}
+```
+
+If `-all` is not provided, then only those structs whose preceding
+comment starts with `easyjson:json` will have marshalers/unmarshalers
+generated. For example:
+
+```go
+//easyjson:json
+type A struct {}
+```
+
+Additional option notes:
+
+* `-snake_case` tells easyjson to generate snake\_case field names by default
+ (unless overridden by a field tag). The CamelCase to snake\_case conversion
+ algorithm should work in most cases (ie, HTTPVersion will be converted to
+ "http_version").
+
+* `-build_tags` will add the specified build tags to generated Go sources.
+
+* `-gen_build_flags` will execute the easyjson bootstapping code to launch the
+ actual generator command with provided flags. Multiple arguments should be
+ separated by space e.g. `-gen_build_flags="-mod=mod -x"`.
+
+## Structure json tag options
+
+Besides standart json tag options like 'omitempty' the following are supported:
+
+* 'nocopy' - disables allocation and copying of string values, making them
+ refer to original json buffer memory. This works great for short lived
+ objects which are not hold in memory after decoding and immediate usage.
+ Note if string requires unescaping it will be processed as normally.
+* 'intern' - string "interning" (deduplication) to save memory when the very
+ same string dictionary values are often met all over the structure.
+ See below for more details.
+
+## Generated Marshaler/Unmarshaler Funcs
+
+For Go struct types, easyjson generates the funcs `MarshalEasyJSON` /
+`UnmarshalEasyJSON` for marshaling/unmarshaling JSON. In turn, these satisfy
+the `easyjson.Marshaler` and `easyjson.Unmarshaler` interfaces and when used in
+conjunction with `easyjson.Marshal` / `easyjson.Unmarshal` avoid unnecessary
+reflection / type assertions during marshaling/unmarshaling to/from JSON for Go
+structs.
+
+easyjson also generates `MarshalJSON` and `UnmarshalJSON` funcs for Go struct
+types compatible with the standard `json.Marshaler` and `json.Unmarshaler`
+interfaces. Please be aware that using the standard `json.Marshal` /
+`json.Unmarshal` for marshaling/unmarshaling will incur a significant
+performance penalty when compared to using `easyjson.Marshal` /
+`easyjson.Unmarshal`.
+
+Additionally, easyjson exposes utility funcs that use the `MarshalEasyJSON` and
+`UnmarshalEasyJSON` for marshaling/unmarshaling to and from standard readers
+and writers. For example, easyjson provides `easyjson.MarshalToHTTPResponseWriter`
+which marshals to the standard `http.ResponseWriter`. Please see the [GoDoc
+listing](https://godoc.org/github.com/mailru/easyjson) for the full listing of
+utility funcs that are available.
+
+## Controlling easyjson Marshaling and Unmarshaling Behavior
+
+Go types can provide their own `MarshalEasyJSON` and `UnmarshalEasyJSON` funcs
+that satisfy the `easyjson.Marshaler` / `easyjson.Unmarshaler` interfaces.
+These will be used by `easyjson.Marshal` and `easyjson.Unmarshal` when defined
+for a Go type.
+
+Go types can also satisfy the `easyjson.Optional` interface, which allows the
+type to define its own `omitempty` logic.
+
+## Type Wrappers
+
+easyjson provides additional type wrappers defined in the `easyjson/opt`
+package. These wrap the standard Go primitives and in turn satisfy the
+easyjson interfaces.
+
+The `easyjson/opt` type wrappers are useful when needing to distinguish between
+a missing value and/or when needing to specifying a default value. Type
+wrappers allow easyjson to avoid additional pointers and heap allocations and
+can significantly increase performance when used properly.
+
+## Memory Pooling
+
+easyjson uses a buffer pool that allocates data in increasing chunks from 128
+to 32768 bytes. Chunks of 512 bytes and larger will be reused with the help of
+`sync.Pool`. The maximum size of a chunk is bounded to reduce redundant memory
+allocation and to allow larger reusable buffers.
+
+easyjson's custom allocation buffer pool is defined in the `easyjson/buffer`
+package, and the default behavior pool behavior can be modified (if necessary)
+through a call to `buffer.Init()` prior to any marshaling or unmarshaling.
+Please see the [GoDoc listing](https://godoc.org/github.com/mailru/easyjson/buffer)
+for more information.
+
+## String interning
+
+During unmarshaling, `string` field values can be optionally
+[interned](https://en.wikipedia.org/wiki/String_interning) to reduce memory
+allocations and usage by deduplicating strings in memory, at the expense of slightly
+increased CPU usage.
+
+This will work effectively only for `string` fields being decoded that have frequently
+the same value (e.g. if you have a string field that can only assume a small number
+of possible values).
+
+To enable string interning, add the `intern` keyword tag to your `json` tag on `string`
+fields, e.g.:
+
+```go
+type Foo struct {
+ UUID string `json:"uuid"` // will not be interned during unmarshaling
+ State string `json:"state,intern"` // will be interned during unmarshaling
+}
+```
+
+## Issues, Notes, and Limitations
+
+* easyjson is still early in its development. As such, there are likely to be
+ bugs and missing features when compared to `encoding/json`. In the case of a
+ missing feature or bug, please create a GitHub issue. Pull requests are
+ welcome!
+
+* Unlike `encoding/json`, object keys are case-sensitive. Case-insensitive
+ matching is not currently provided due to the significant performance hit
+ when doing case-insensitive key matching. In the future, case-insensitive
+ object key matching may be provided via an option to the generator.
+
+* easyjson makes use of `unsafe`, which simplifies the code and
+ provides significant performance benefits by allowing no-copy
+ conversion from `[]byte` to `string`. That said, `unsafe` is used
+ only when unmarshaling and parsing JSON, and any `unsafe` operations
+ / memory allocations done will be safely deallocated by
+ easyjson. Set the build tag `easyjson_nounsafe` to compile it
+ without `unsafe`.
+
+* easyjson is compatible with Google App Engine. The `appengine` build
+ tag (set by App Engine's environment) will automatically disable the
+ use of `unsafe`, which is not allowed in App Engine's Standard
+ Environment. Note that the use with App Engine is still experimental.
+
+* Floats are formatted using the default precision from Go's `strconv` package.
+ As such, easyjson will not correctly handle high precision floats when
+ marshaling/unmarshaling JSON. Note, however, that there are very few/limited
+ uses where this behavior is not sufficient for general use. That said, a
+ different package may be needed if precise marshaling/unmarshaling of high
+ precision floats to/from JSON is required.
+
+* While unmarshaling, the JSON parser does the minimal amount of work needed to
+ skip over unmatching parens, and as such full validation is not done for the
+ entire JSON value being unmarshaled/parsed.
+
+* Currently there is no true streaming support for encoding/decoding as
+ typically for many uses/protocols the final, marshaled length of the JSON
+ needs to be known prior to sending the data. Currently this is not possible
+ with easyjson's architecture.
+
+* easyjson parser and codegen based on reflection, so it won't work on `package main`
+ files, because they cant be imported by parser.
+
+## Benchmarks
+
+Most benchmarks were done using the example
+[13kB example JSON](https://dev.twitter.com/rest/reference/get/search/tweets)
+(9k after eliminating whitespace). This example is similar to real-world data,
+is well-structured, and contains a healthy variety of different types, making
+it ideal for JSON serialization benchmarks.
+
+Note:
+
+* For small request benchmarks, an 80 byte portion of the above example was
+ used.
+
+* For large request marshaling benchmarks, a struct containing 50 regular
+ samples was used, making a ~500kB output JSON.
+
+* Benchmarks are showing the results of easyjson's default behaviour,
+ which makes use of `unsafe`.
+
+Benchmarks are available in the repository and can be run by invoking `make`.
+
+### easyjson vs. encoding/json
+
+easyjson is roughly 5-6 times faster than the standard `encoding/json` for
+unmarshaling, and 3-4 times faster for non-concurrent marshaling. Concurrent
+marshaling is 6-7x faster if marshaling to a writer.
+
+### easyjson vs. ffjson
+
+easyjson uses the same approach for JSON marshaling as
+[ffjson](https://github.com/pquerna/ffjson), but takes a significantly
+different approach to lexing and parsing JSON during unmarshaling. This means
+easyjson is roughly 2-3x faster for unmarshaling and 1.5-2x faster for
+non-concurrent unmarshaling.
+
+As of this writing, `ffjson` seems to have issues when used concurrently:
+specifically, large request pooling hurts `ffjson`'s performance and causes
+scalability issues. These issues with `ffjson` can likely be fixed, but as of
+writing remain outstanding/known issues with `ffjson`.
+
+easyjson and `ffjson` have similar performance for small requests, however
+easyjson outperforms `ffjson` by roughly 2-5x times for large requests when
+used with a writer.
+
+### easyjson vs. go/codec
+
+[go/codec](https://github.com/ugorji/go) provides
+compile-time helpers for JSON generation. In this case, helpers do not work
+like marshalers as they are encoding-independent.
+
+easyjson is generally 2x faster than `go/codec` for non-concurrent benchmarks
+and about 3x faster for concurrent encoding (without marshaling to a writer).
+
+In an attempt to measure marshaling performance of `go/codec` (as opposed to
+allocations/memcpy/writer interface invocations), a benchmark was done with
+resetting length of a byte slice rather than resetting the whole slice to nil.
+However, the optimization in this exact form may not be applicable in practice,
+since the memory is not freed between marshaling operations.
+
+### easyjson vs 'ujson' python module
+
+[ujson](https://github.com/esnme/ultrajson) is using C code for parsing, so it
+is interesting to see how plain golang compares to that. It is important to note
+that the resulting object for python is slower to access, since the library
+parses JSON object into dictionaries.
+
+easyjson is slightly faster for unmarshaling and 2-3x faster than `ujson` for
+marshaling.
+
+### Benchmark Results
+
+`ffjson` results are from February 4th, 2016, using the latest `ffjson` and go1.6.
+`go/codec` results are from March 4th, 2016, using the latest `go/codec` and go1.6.
+
+#### Unmarshaling
+
+| lib | json size | MB/s | allocs/op | B/op |
+|:---------|:----------|-----:|----------:|------:|
+| standard | regular | 22 | 218 | 10229 |
+| standard | small | 9.7 | 14 | 720 |
+| | | | | |
+| easyjson | regular | 125 | 128 | 9794 |
+| easyjson | small | 67 | 3 | 128 |
+| | | | | |
+| ffjson | regular | 66 | 141 | 9985 |
+| ffjson | small | 17.6 | 10 | 488 |
+| | | | | |
+| codec | regular | 55 | 434 | 19299 |
+| codec | small | 29 | 7 | 336 |
+| | | | | |
+| ujson | regular | 103 | N/A | N/A |
+
+#### Marshaling, one goroutine.
+
+| lib | json size | MB/s | allocs/op | B/op |
+|:----------|:----------|-----:|----------:|------:|
+| standard | regular | 75 | 9 | 23256 |
+| standard | small | 32 | 3 | 328 |
+| standard | large | 80 | 17 | 1.2M |
+| | | | | |
+| easyjson | regular | 213 | 9 | 10260 |
+| easyjson* | regular | 263 | 8 | 742 |
+| easyjson | small | 125 | 1 | 128 |
+| easyjson | large | 212 | 33 | 490k |
+| easyjson* | large | 262 | 25 | 2879 |
+| | | | | |
+| ffjson | regular | 122 | 153 | 21340 |
+| ffjson** | regular | 146 | 152 | 4897 |
+| ffjson | small | 36 | 5 | 384 |
+| ffjson** | small | 64 | 4 | 128 |
+| ffjson | large | 134 | 7317 | 818k |
+| ffjson** | large | 125 | 7320 | 827k |
+| | | | | |
+| codec | regular | 80 | 17 | 33601 |
+| codec*** | regular | 108 | 9 | 1153 |
+| codec | small | 42 | 3 | 304 |
+| codec*** | small | 56 | 1 | 48 |
+| codec | large | 73 | 483 | 2.5M |
+| codec*** | large | 103 | 451 | 66007 |
+| | | | | |
+| ujson | regular | 92 | N/A | N/A |
+
+\* marshaling to a writer,
+\*\* using `ffjson.Pool()`,
+\*\*\* reusing output slice instead of resetting it to nil
+
+#### Marshaling, concurrent.
+
+| lib | json size | MB/s | allocs/op | B/op |
+|:----------|:----------|-----:|----------:|------:|
+| standard | regular | 252 | 9 | 23257 |
+| standard | small | 124 | 3 | 328 |
+| standard | large | 289 | 17 | 1.2M |
+| | | | | |
+| easyjson | regular | 792 | 9 | 10597 |
+| easyjson* | regular | 1748 | 8 | 779 |
+| easyjson | small | 333 | 1 | 128 |
+| easyjson | large | 718 | 36 | 548k |
+| easyjson* | large | 2134 | 25 | 4957 |
+| | | | | |
+| ffjson | regular | 301 | 153 | 21629 |
+| ffjson** | regular | 707 | 152 | 5148 |
+| ffjson | small | 62 | 5 | 384 |
+| ffjson** | small | 282 | 4 | 128 |
+| ffjson | large | 438 | 7330 | 1.0M |
+| ffjson** | large | 131 | 7319 | 820k |
+| | | | | |
+| codec | regular | 183 | 17 | 33603 |
+| codec*** | regular | 671 | 9 | 1157 |
+| codec | small | 147 | 3 | 304 |
+| codec*** | small | 299 | 1 | 48 |
+| codec | large | 190 | 483 | 2.5M |
+| codec*** | large | 752 | 451 | 77574 |
+
+\* marshaling to a writer,
+\*\* using `ffjson.Pool()`,
+\*\*\* reusing output slice instead of resetting it to nil
diff --git a/vendor/github.com/mailru/easyjson/buffer/pool.go b/vendor/github.com/mailru/easyjson/buffer/pool.go
new file mode 100644
index 0000000..598a54a
--- /dev/null
+++ b/vendor/github.com/mailru/easyjson/buffer/pool.go
@@ -0,0 +1,278 @@
+// Package buffer implements a buffer for serialization, consisting of a chain of []byte-s to
+// reduce copying and to allow reuse of individual chunks.
+package buffer
+
+import (
+ "io"
+ "net"
+ "sync"
+)
+
+// PoolConfig contains configuration for the allocation and reuse strategy.
+type PoolConfig struct {
+ StartSize int // Minimum chunk size that is allocated.
+ PooledSize int // Minimum chunk size that is reused, reusing chunks too small will result in overhead.
+ MaxSize int // Maximum chunk size that will be allocated.
+}
+
+var config = PoolConfig{
+ StartSize: 128,
+ PooledSize: 512,
+ MaxSize: 32768,
+}
+
+// Reuse pool: chunk size -> pool.
+var buffers = map[int]*sync.Pool{}
+
+func initBuffers() {
+ for l := config.PooledSize; l <= config.MaxSize; l *= 2 {
+ buffers[l] = new(sync.Pool)
+ }
+}
+
+func init() {
+ initBuffers()
+}
+
+// Init sets up a non-default pooling and allocation strategy. Should be run before serialization is done.
+func Init(cfg PoolConfig) {
+ config = cfg
+ initBuffers()
+}
+
+// putBuf puts a chunk to reuse pool if it can be reused.
+func putBuf(buf []byte) {
+ size := cap(buf)
+ if size < config.PooledSize {
+ return
+ }
+ if c := buffers[size]; c != nil {
+ c.Put(buf[:0])
+ }
+}
+
+// getBuf gets a chunk from reuse pool or creates a new one if reuse failed.
+func getBuf(size int) []byte {
+ if size >= config.PooledSize {
+ if c := buffers[size]; c != nil {
+ v := c.Get()
+ if v != nil {
+ return v.([]byte)
+ }
+ }
+ }
+ return make([]byte, 0, size)
+}
+
+// Buffer is a buffer optimized for serialization without extra copying.
+type Buffer struct {
+
+ // Buf is the current chunk that can be used for serialization.
+ Buf []byte
+
+ toPool []byte
+ bufs [][]byte
+}
+
+// EnsureSpace makes sure that the current chunk contains at least s free bytes,
+// possibly creating a new chunk.
+func (b *Buffer) EnsureSpace(s int) {
+ if cap(b.Buf)-len(b.Buf) < s {
+ b.ensureSpaceSlow(s)
+ }
+}
+
+func (b *Buffer) ensureSpaceSlow(s int) {
+ l := len(b.Buf)
+ if l > 0 {
+ if cap(b.toPool) != cap(b.Buf) {
+ // Chunk was reallocated, toPool can be pooled.
+ putBuf(b.toPool)
+ }
+ if cap(b.bufs) == 0 {
+ b.bufs = make([][]byte, 0, 8)
+ }
+ b.bufs = append(b.bufs, b.Buf)
+ l = cap(b.toPool) * 2
+ } else {
+ l = config.StartSize
+ }
+
+ if l > config.MaxSize {
+ l = config.MaxSize
+ }
+ b.Buf = getBuf(l)
+ b.toPool = b.Buf
+}
+
+// AppendByte appends a single byte to buffer.
+func (b *Buffer) AppendByte(data byte) {
+ b.EnsureSpace(1)
+ b.Buf = append(b.Buf, data)
+}
+
+// AppendBytes appends a byte slice to buffer.
+func (b *Buffer) AppendBytes(data []byte) {
+ if len(data) <= cap(b.Buf)-len(b.Buf) {
+ b.Buf = append(b.Buf, data...) // fast path
+ } else {
+ b.appendBytesSlow(data)
+ }
+}
+
+func (b *Buffer) appendBytesSlow(data []byte) {
+ for len(data) > 0 {
+ b.EnsureSpace(1)
+
+ sz := cap(b.Buf) - len(b.Buf)
+ if sz > len(data) {
+ sz = len(data)
+ }
+
+ b.Buf = append(b.Buf, data[:sz]...)
+ data = data[sz:]
+ }
+}
+
+// AppendString appends a string to buffer.
+func (b *Buffer) AppendString(data string) {
+ if len(data) <= cap(b.Buf)-len(b.Buf) {
+ b.Buf = append(b.Buf, data...) // fast path
+ } else {
+ b.appendStringSlow(data)
+ }
+}
+
+func (b *Buffer) appendStringSlow(data string) {
+ for len(data) > 0 {
+ b.EnsureSpace(1)
+
+ sz := cap(b.Buf) - len(b.Buf)
+ if sz > len(data) {
+ sz = len(data)
+ }
+
+ b.Buf = append(b.Buf, data[:sz]...)
+ data = data[sz:]
+ }
+}
+
+// Size computes the size of a buffer by adding sizes of every chunk.
+func (b *Buffer) Size() int {
+ size := len(b.Buf)
+ for _, buf := range b.bufs {
+ size += len(buf)
+ }
+ return size
+}
+
+// DumpTo outputs the contents of a buffer to a writer and resets the buffer.
+func (b *Buffer) DumpTo(w io.Writer) (written int, err error) {
+ bufs := net.Buffers(b.bufs)
+ if len(b.Buf) > 0 {
+ bufs = append(bufs, b.Buf)
+ }
+ n, err := bufs.WriteTo(w)
+
+ for _, buf := range b.bufs {
+ putBuf(buf)
+ }
+ putBuf(b.toPool)
+
+ b.bufs = nil
+ b.Buf = nil
+ b.toPool = nil
+
+ return int(n), err
+}
+
+// BuildBytes creates a single byte slice with all the contents of the buffer. Data is
+// copied if it does not fit in a single chunk. You can optionally provide one byte
+// slice as argument that it will try to reuse.
+func (b *Buffer) BuildBytes(reuse ...[]byte) []byte {
+ if len(b.bufs) == 0 {
+ ret := b.Buf
+ b.toPool = nil
+ b.Buf = nil
+ return ret
+ }
+
+ var ret []byte
+ size := b.Size()
+
+ // If we got a buffer as argument and it is big enough, reuse it.
+ if len(reuse) == 1 && cap(reuse[0]) >= size {
+ ret = reuse[0][:0]
+ } else {
+ ret = make([]byte, 0, size)
+ }
+ for _, buf := range b.bufs {
+ ret = append(ret, buf...)
+ putBuf(buf)
+ }
+
+ ret = append(ret, b.Buf...)
+ putBuf(b.toPool)
+
+ b.bufs = nil
+ b.toPool = nil
+ b.Buf = nil
+
+ return ret
+}
+
+type readCloser struct {
+ offset int
+ bufs [][]byte
+}
+
+func (r *readCloser) Read(p []byte) (n int, err error) {
+ for _, buf := range r.bufs {
+ // Copy as much as we can.
+ x := copy(p[n:], buf[r.offset:])
+ n += x // Increment how much we filled.
+
+ // Did we empty the whole buffer?
+ if r.offset+x == len(buf) {
+ // On to the next buffer.
+ r.offset = 0
+ r.bufs = r.bufs[1:]
+
+ // We can release this buffer.
+ putBuf(buf)
+ } else {
+ r.offset += x
+ }
+
+ if n == len(p) {
+ break
+ }
+ }
+ // No buffers left or nothing read?
+ if len(r.bufs) == 0 {
+ err = io.EOF
+ }
+ return
+}
+
+func (r *readCloser) Close() error {
+ // Release all remaining buffers.
+ for _, buf := range r.bufs {
+ putBuf(buf)
+ }
+ // In case Close gets called multiple times.
+ r.bufs = nil
+
+ return nil
+}
+
+// ReadCloser creates an io.ReadCloser with all the contents of the buffer.
+func (b *Buffer) ReadCloser() io.ReadCloser {
+ ret := &readCloser{0, append(b.bufs, b.Buf)}
+
+ b.bufs = nil
+ b.toPool = nil
+ b.Buf = nil
+
+ return ret
+}
diff --git a/vendor/github.com/mailru/easyjson/helpers.go b/vendor/github.com/mailru/easyjson/helpers.go
new file mode 100644
index 0000000..78dacb1
--- /dev/null
+++ b/vendor/github.com/mailru/easyjson/helpers.go
@@ -0,0 +1,114 @@
+// Package easyjson contains marshaler/unmarshaler interfaces and helper functions.
+package easyjson
+
+import (
+ "io"
+ "io/ioutil"
+ "net/http"
+ "strconv"
+ "unsafe"
+
+ "github.com/mailru/easyjson/jlexer"
+ "github.com/mailru/easyjson/jwriter"
+)
+
+// Marshaler is an easyjson-compatible marshaler interface.
+type Marshaler interface {
+ MarshalEasyJSON(w *jwriter.Writer)
+}
+
+// Marshaler is an easyjson-compatible unmarshaler interface.
+type Unmarshaler interface {
+ UnmarshalEasyJSON(w *jlexer.Lexer)
+}
+
+// MarshalerUnmarshaler is an easyjson-compatible marshaler/unmarshaler interface.
+type MarshalerUnmarshaler interface {
+ Marshaler
+ Unmarshaler
+}
+
+// Optional defines an undefined-test method for a type to integrate with 'omitempty' logic.
+type Optional interface {
+ IsDefined() bool
+}
+
+// UnknownsUnmarshaler provides a method to unmarshal unknown struct fileds and save them as you want
+type UnknownsUnmarshaler interface {
+ UnmarshalUnknown(in *jlexer.Lexer, key string)
+}
+
+// UnknownsMarshaler provides a method to write additional struct fields
+type UnknownsMarshaler interface {
+ MarshalUnknowns(w *jwriter.Writer, first bool)
+}
+
+func isNilInterface(i interface{}) bool {
+ return (*[2]uintptr)(unsafe.Pointer(&i))[1] == 0
+}
+
+// Marshal returns data as a single byte slice. Method is suboptimal as the data is likely to be copied
+// from a chain of smaller chunks.
+func Marshal(v Marshaler) ([]byte, error) {
+ if isNilInterface(v) {
+ return nullBytes, nil
+ }
+
+ w := jwriter.Writer{}
+ v.MarshalEasyJSON(&w)
+ return w.BuildBytes()
+}
+
+// MarshalToWriter marshals the data to an io.Writer.
+func MarshalToWriter(v Marshaler, w io.Writer) (written int, err error) {
+ if isNilInterface(v) {
+ return w.Write(nullBytes)
+ }
+
+ jw := jwriter.Writer{}
+ v.MarshalEasyJSON(&jw)
+ return jw.DumpTo(w)
+}
+
+// MarshalToHTTPResponseWriter sets Content-Length and Content-Type headers for the
+// http.ResponseWriter, and send the data to the writer. started will be equal to
+// false if an error occurred before any http.ResponseWriter methods were actually
+// invoked (in this case a 500 reply is possible).
+func MarshalToHTTPResponseWriter(v Marshaler, w http.ResponseWriter) (started bool, written int, err error) {
+ if isNilInterface(v) {
+ w.Header().Set("Content-Type", "application/json")
+ w.Header().Set("Content-Length", strconv.Itoa(len(nullBytes)))
+ written, err = w.Write(nullBytes)
+ return true, written, err
+ }
+
+ jw := jwriter.Writer{}
+ v.MarshalEasyJSON(&jw)
+ if jw.Error != nil {
+ return false, 0, jw.Error
+ }
+ w.Header().Set("Content-Type", "application/json")
+ w.Header().Set("Content-Length", strconv.Itoa(jw.Size()))
+
+ started = true
+ written, err = jw.DumpTo(w)
+ return
+}
+
+// Unmarshal decodes the JSON in data into the object.
+func Unmarshal(data []byte, v Unmarshaler) error {
+ l := jlexer.Lexer{Data: data}
+ v.UnmarshalEasyJSON(&l)
+ return l.Error()
+}
+
+// UnmarshalFromReader reads all the data in the reader and decodes as JSON into the object.
+func UnmarshalFromReader(r io.Reader, v Unmarshaler) error {
+ data, err := ioutil.ReadAll(r)
+ if err != nil {
+ return err
+ }
+ l := jlexer.Lexer{Data: data}
+ v.UnmarshalEasyJSON(&l)
+ return l.Error()
+}
diff --git a/vendor/github.com/mailru/easyjson/jlexer/bytestostr.go b/vendor/github.com/mailru/easyjson/jlexer/bytestostr.go
new file mode 100644
index 0000000..ff7b27c
--- /dev/null
+++ b/vendor/github.com/mailru/easyjson/jlexer/bytestostr.go
@@ -0,0 +1,24 @@
+// This file will only be included to the build if neither
+// easyjson_nounsafe nor appengine build tag is set. See README notes
+// for more details.
+
+//+build !easyjson_nounsafe
+//+build !appengine
+
+package jlexer
+
+import (
+ "reflect"
+ "unsafe"
+)
+
+// bytesToStr creates a string pointing at the slice to avoid copying.
+//
+// Warning: the string returned by the function should be used with care, as the whole input data
+// chunk may be either blocked from being freed by GC because of a single string or the buffer.Data
+// may be garbage-collected even when the string exists.
+func bytesToStr(data []byte) string {
+ h := (*reflect.SliceHeader)(unsafe.Pointer(&data))
+ shdr := reflect.StringHeader{Data: h.Data, Len: h.Len}
+ return *(*string)(unsafe.Pointer(&shdr))
+}
diff --git a/vendor/github.com/mailru/easyjson/jlexer/bytestostr_nounsafe.go b/vendor/github.com/mailru/easyjson/jlexer/bytestostr_nounsafe.go
new file mode 100644
index 0000000..864d1be
--- /dev/null
+++ b/vendor/github.com/mailru/easyjson/jlexer/bytestostr_nounsafe.go
@@ -0,0 +1,13 @@
+// This file is included to the build if any of the buildtags below
+// are defined. Refer to README notes for more details.
+
+//+build easyjson_nounsafe appengine
+
+package jlexer
+
+// bytesToStr creates a string normally from []byte
+//
+// Note that this method is roughly 1.5x slower than using the 'unsafe' method.
+func bytesToStr(data []byte) string {
+ return string(data)
+}
diff --git a/vendor/github.com/mailru/easyjson/jlexer/error.go b/vendor/github.com/mailru/easyjson/jlexer/error.go
new file mode 100644
index 0000000..e90ec40
--- /dev/null
+++ b/vendor/github.com/mailru/easyjson/jlexer/error.go
@@ -0,0 +1,15 @@
+package jlexer
+
+import "fmt"
+
+// LexerError implements the error interface and represents all possible errors that can be
+// generated during parsing the JSON data.
+type LexerError struct {
+ Reason string
+ Offset int
+ Data string
+}
+
+func (l *LexerError) Error() string {
+ return fmt.Sprintf("parse error: %s near offset %d of '%s'", l.Reason, l.Offset, l.Data)
+}
diff --git a/vendor/github.com/mailru/easyjson/jlexer/lexer.go b/vendor/github.com/mailru/easyjson/jlexer/lexer.go
new file mode 100644
index 0000000..b5f5e26
--- /dev/null
+++ b/vendor/github.com/mailru/easyjson/jlexer/lexer.go
@@ -0,0 +1,1244 @@
+// Package jlexer contains a JSON lexer implementation.
+//
+// It is expected that it is mostly used with generated parser code, so the interface is tuned
+// for a parser that knows what kind of data is expected.
+package jlexer
+
+import (
+ "bytes"
+ "encoding/base64"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "io"
+ "strconv"
+ "unicode"
+ "unicode/utf16"
+ "unicode/utf8"
+
+ "github.com/josharian/intern"
+)
+
+// tokenKind determines type of a token.
+type tokenKind byte
+
+const (
+ tokenUndef tokenKind = iota // No token.
+ tokenDelim // Delimiter: one of '{', '}', '[' or ']'.
+ tokenString // A string literal, e.g. "abc\u1234"
+ tokenNumber // Number literal, e.g. 1.5e5
+ tokenBool // Boolean literal: true or false.
+ tokenNull // null keyword.
+)
+
+// token describes a single token: type, position in the input and value.
+type token struct {
+ kind tokenKind // Type of a token.
+
+ boolValue bool // Value if a boolean literal token.
+ byteValueCloned bool // true if byteValue was allocated and does not refer to original json body
+ byteValue []byte // Raw value of a token.
+ delimValue byte
+}
+
+// Lexer is a JSON lexer: it iterates over JSON tokens in a byte slice.
+type Lexer struct {
+ Data []byte // Input data given to the lexer.
+
+ start int // Start of the current token.
+ pos int // Current unscanned position in the input stream.
+ token token // Last scanned token, if token.kind != tokenUndef.
+
+ firstElement bool // Whether current element is the first in array or an object.
+ wantSep byte // A comma or a colon character, which need to occur before a token.
+
+ UseMultipleErrors bool // If we want to use multiple errors.
+ fatalError error // Fatal error occurred during lexing. It is usually a syntax error.
+ multipleErrors []*LexerError // Semantic errors occurred during lexing. Marshalling will be continued after finding this errors.
+}
+
+// FetchToken scans the input for the next token.
+func (r *Lexer) FetchToken() {
+ r.token.kind = tokenUndef
+ r.start = r.pos
+
+ // Check if r.Data has r.pos element
+ // If it doesn't, it mean corrupted input data
+ if len(r.Data) < r.pos {
+ r.errParse("Unexpected end of data")
+ return
+ }
+ // Determine the type of a token by skipping whitespace and reading the
+ // first character.
+ for _, c := range r.Data[r.pos:] {
+ switch c {
+ case ':', ',':
+ if r.wantSep == c {
+ r.pos++
+ r.start++
+ r.wantSep = 0
+ } else {
+ r.errSyntax()
+ }
+
+ case ' ', '\t', '\r', '\n':
+ r.pos++
+ r.start++
+
+ case '"':
+ if r.wantSep != 0 {
+ r.errSyntax()
+ }
+
+ r.token.kind = tokenString
+ r.fetchString()
+ return
+
+ case '{', '[':
+ if r.wantSep != 0 {
+ r.errSyntax()
+ }
+ r.firstElement = true
+ r.token.kind = tokenDelim
+ r.token.delimValue = r.Data[r.pos]
+ r.pos++
+ return
+
+ case '}', ']':
+ if !r.firstElement && (r.wantSep != ',') {
+ r.errSyntax()
+ }
+ r.wantSep = 0
+ r.token.kind = tokenDelim
+ r.token.delimValue = r.Data[r.pos]
+ r.pos++
+ return
+
+ case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-':
+ if r.wantSep != 0 {
+ r.errSyntax()
+ }
+ r.token.kind = tokenNumber
+ r.fetchNumber()
+ return
+
+ case 'n':
+ if r.wantSep != 0 {
+ r.errSyntax()
+ }
+
+ r.token.kind = tokenNull
+ r.fetchNull()
+ return
+
+ case 't':
+ if r.wantSep != 0 {
+ r.errSyntax()
+ }
+
+ r.token.kind = tokenBool
+ r.token.boolValue = true
+ r.fetchTrue()
+ return
+
+ case 'f':
+ if r.wantSep != 0 {
+ r.errSyntax()
+ }
+
+ r.token.kind = tokenBool
+ r.token.boolValue = false
+ r.fetchFalse()
+ return
+
+ default:
+ r.errSyntax()
+ return
+ }
+ }
+ r.fatalError = io.EOF
+ return
+}
+
+// isTokenEnd returns true if the char can follow a non-delimiter token
+func isTokenEnd(c byte) bool {
+ return c == ' ' || c == '\t' || c == '\r' || c == '\n' || c == '[' || c == ']' || c == '{' || c == '}' || c == ',' || c == ':'
+}
+
+// fetchNull fetches and checks remaining bytes of null keyword.
+func (r *Lexer) fetchNull() {
+ r.pos += 4
+ if r.pos > len(r.Data) ||
+ r.Data[r.pos-3] != 'u' ||
+ r.Data[r.pos-2] != 'l' ||
+ r.Data[r.pos-1] != 'l' ||
+ (r.pos != len(r.Data) && !isTokenEnd(r.Data[r.pos])) {
+
+ r.pos -= 4
+ r.errSyntax()
+ }
+}
+
+// fetchTrue fetches and checks remaining bytes of true keyword.
+func (r *Lexer) fetchTrue() {
+ r.pos += 4
+ if r.pos > len(r.Data) ||
+ r.Data[r.pos-3] != 'r' ||
+ r.Data[r.pos-2] != 'u' ||
+ r.Data[r.pos-1] != 'e' ||
+ (r.pos != len(r.Data) && !isTokenEnd(r.Data[r.pos])) {
+
+ r.pos -= 4
+ r.errSyntax()
+ }
+}
+
+// fetchFalse fetches and checks remaining bytes of false keyword.
+func (r *Lexer) fetchFalse() {
+ r.pos += 5
+ if r.pos > len(r.Data) ||
+ r.Data[r.pos-4] != 'a' ||
+ r.Data[r.pos-3] != 'l' ||
+ r.Data[r.pos-2] != 's' ||
+ r.Data[r.pos-1] != 'e' ||
+ (r.pos != len(r.Data) && !isTokenEnd(r.Data[r.pos])) {
+
+ r.pos -= 5
+ r.errSyntax()
+ }
+}
+
+// fetchNumber scans a number literal token.
+func (r *Lexer) fetchNumber() {
+ hasE := false
+ afterE := false
+ hasDot := false
+
+ r.pos++
+ for i, c := range r.Data[r.pos:] {
+ switch {
+ case c >= '0' && c <= '9':
+ afterE = false
+ case c == '.' && !hasDot:
+ hasDot = true
+ case (c == 'e' || c == 'E') && !hasE:
+ hasE = true
+ hasDot = true
+ afterE = true
+ case (c == '+' || c == '-') && afterE:
+ afterE = false
+ default:
+ r.pos += i
+ if !isTokenEnd(c) {
+ r.errSyntax()
+ } else {
+ r.token.byteValue = r.Data[r.start:r.pos]
+ }
+ return
+ }
+ }
+
+ r.pos = len(r.Data)
+ r.token.byteValue = r.Data[r.start:]
+}
+
+// findStringLen tries to scan into the string literal for ending quote char to determine required size.
+// The size will be exact if no escapes are present and may be inexact if there are escaped chars.
+func findStringLen(data []byte) (isValid bool, length int) {
+ for {
+ idx := bytes.IndexByte(data, '"')
+ if idx == -1 {
+ return false, len(data)
+ }
+ if idx == 0 || (idx > 0 && data[idx-1] != '\\') {
+ return true, length + idx
+ }
+
+ // count \\\\\\\ sequences. even number of slashes means quote is not really escaped
+ cnt := 1
+ for idx-cnt-1 >= 0 && data[idx-cnt-1] == '\\' {
+ cnt++
+ }
+ if cnt%2 == 0 {
+ return true, length + idx
+ }
+
+ length += idx + 1
+ data = data[idx+1:]
+ }
+}
+
+// unescapeStringToken performs unescaping of string token.
+// if no escaping is needed, original string is returned, otherwise - a new one allocated
+func (r *Lexer) unescapeStringToken() (err error) {
+ data := r.token.byteValue
+ var unescapedData []byte
+
+ for {
+ i := bytes.IndexByte(data, '\\')
+ if i == -1 {
+ break
+ }
+
+ escapedRune, escapedBytes, err := decodeEscape(data[i:])
+ if err != nil {
+ r.errParse(err.Error())
+ return err
+ }
+
+ if unescapedData == nil {
+ unescapedData = make([]byte, 0, len(r.token.byteValue))
+ }
+
+ var d [4]byte
+ s := utf8.EncodeRune(d[:], escapedRune)
+ unescapedData = append(unescapedData, data[:i]...)
+ unescapedData = append(unescapedData, d[:s]...)
+
+ data = data[i+escapedBytes:]
+ }
+
+ if unescapedData != nil {
+ r.token.byteValue = append(unescapedData, data...)
+ r.token.byteValueCloned = true
+ }
+ return
+}
+
+// getu4 decodes \uXXXX from the beginning of s, returning the hex value,
+// or it returns -1.
+func getu4(s []byte) rune {
+ if len(s) < 6 || s[0] != '\\' || s[1] != 'u' {
+ return -1
+ }
+ var val rune
+ for i := 2; i < len(s) && i < 6; i++ {
+ var v byte
+ c := s[i]
+ switch c {
+ case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
+ v = c - '0'
+ case 'a', 'b', 'c', 'd', 'e', 'f':
+ v = c - 'a' + 10
+ case 'A', 'B', 'C', 'D', 'E', 'F':
+ v = c - 'A' + 10
+ default:
+ return -1
+ }
+
+ val <<= 4
+ val |= rune(v)
+ }
+ return val
+}
+
+// decodeEscape processes a single escape sequence and returns number of bytes processed.
+func decodeEscape(data []byte) (decoded rune, bytesProcessed int, err error) {
+ if len(data) < 2 {
+ return 0, 0, errors.New("incorrect escape symbol \\ at the end of token")
+ }
+
+ c := data[1]
+ switch c {
+ case '"', '/', '\\':
+ return rune(c), 2, nil
+ case 'b':
+ return '\b', 2, nil
+ case 'f':
+ return '\f', 2, nil
+ case 'n':
+ return '\n', 2, nil
+ case 'r':
+ return '\r', 2, nil
+ case 't':
+ return '\t', 2, nil
+ case 'u':
+ rr := getu4(data)
+ if rr < 0 {
+ return 0, 0, errors.New("incorrectly escaped \\uXXXX sequence")
+ }
+
+ read := 6
+ if utf16.IsSurrogate(rr) {
+ rr1 := getu4(data[read:])
+ if dec := utf16.DecodeRune(rr, rr1); dec != unicode.ReplacementChar {
+ read += 6
+ rr = dec
+ } else {
+ rr = unicode.ReplacementChar
+ }
+ }
+ return rr, read, nil
+ }
+
+ return 0, 0, errors.New("incorrectly escaped bytes")
+}
+
+// fetchString scans a string literal token.
+func (r *Lexer) fetchString() {
+ r.pos++
+ data := r.Data[r.pos:]
+
+ isValid, length := findStringLen(data)
+ if !isValid {
+ r.pos += length
+ r.errParse("unterminated string literal")
+ return
+ }
+ r.token.byteValue = data[:length]
+ r.pos += length + 1 // skip closing '"' as well
+}
+
+// scanToken scans the next token if no token is currently available in the lexer.
+func (r *Lexer) scanToken() {
+ if r.token.kind != tokenUndef || r.fatalError != nil {
+ return
+ }
+
+ r.FetchToken()
+}
+
+// consume resets the current token to allow scanning the next one.
+func (r *Lexer) consume() {
+ r.token.kind = tokenUndef
+ r.token.byteValueCloned = false
+ r.token.delimValue = 0
+}
+
+// Ok returns true if no error (including io.EOF) was encountered during scanning.
+func (r *Lexer) Ok() bool {
+ return r.fatalError == nil
+}
+
+const maxErrorContextLen = 13
+
+func (r *Lexer) errParse(what string) {
+ if r.fatalError == nil {
+ var str string
+ if len(r.Data)-r.pos <= maxErrorContextLen {
+ str = string(r.Data)
+ } else {
+ str = string(r.Data[r.pos:r.pos+maxErrorContextLen-3]) + "..."
+ }
+ r.fatalError = &LexerError{
+ Reason: what,
+ Offset: r.pos,
+ Data: str,
+ }
+ }
+}
+
+func (r *Lexer) errSyntax() {
+ r.errParse("syntax error")
+}
+
+func (r *Lexer) errInvalidToken(expected string) {
+ if r.fatalError != nil {
+ return
+ }
+ if r.UseMultipleErrors {
+ r.pos = r.start
+ r.consume()
+ r.SkipRecursive()
+ switch expected {
+ case "[":
+ r.token.delimValue = ']'
+ r.token.kind = tokenDelim
+ case "{":
+ r.token.delimValue = '}'
+ r.token.kind = tokenDelim
+ }
+ r.addNonfatalError(&LexerError{
+ Reason: fmt.Sprintf("expected %s", expected),
+ Offset: r.start,
+ Data: string(r.Data[r.start:r.pos]),
+ })
+ return
+ }
+
+ var str string
+ if len(r.token.byteValue) <= maxErrorContextLen {
+ str = string(r.token.byteValue)
+ } else {
+ str = string(r.token.byteValue[:maxErrorContextLen-3]) + "..."
+ }
+ r.fatalError = &LexerError{
+ Reason: fmt.Sprintf("expected %s", expected),
+ Offset: r.pos,
+ Data: str,
+ }
+}
+
+func (r *Lexer) GetPos() int {
+ return r.pos
+}
+
+// Delim consumes a token and verifies that it is the given delimiter.
+func (r *Lexer) Delim(c byte) {
+ if r.token.kind == tokenUndef && r.Ok() {
+ r.FetchToken()
+ }
+
+ if !r.Ok() || r.token.delimValue != c {
+ r.consume() // errInvalidToken can change token if UseMultipleErrors is enabled.
+ r.errInvalidToken(string([]byte{c}))
+ } else {
+ r.consume()
+ }
+}
+
+// IsDelim returns true if there was no scanning error and next token is the given delimiter.
+func (r *Lexer) IsDelim(c byte) bool {
+ if r.token.kind == tokenUndef && r.Ok() {
+ r.FetchToken()
+ }
+ return !r.Ok() || r.token.delimValue == c
+}
+
+// Null verifies that the next token is null and consumes it.
+func (r *Lexer) Null() {
+ if r.token.kind == tokenUndef && r.Ok() {
+ r.FetchToken()
+ }
+ if !r.Ok() || r.token.kind != tokenNull {
+ r.errInvalidToken("null")
+ }
+ r.consume()
+}
+
+// IsNull returns true if the next token is a null keyword.
+func (r *Lexer) IsNull() bool {
+ if r.token.kind == tokenUndef && r.Ok() {
+ r.FetchToken()
+ }
+ return r.Ok() && r.token.kind == tokenNull
+}
+
+// Skip skips a single token.
+func (r *Lexer) Skip() {
+ if r.token.kind == tokenUndef && r.Ok() {
+ r.FetchToken()
+ }
+ r.consume()
+}
+
+// SkipRecursive skips next array or object completely, or just skips a single token if not
+// an array/object.
+//
+// Note: no syntax validation is performed on the skipped data.
+func (r *Lexer) SkipRecursive() {
+ r.scanToken()
+ var start, end byte
+ startPos := r.start
+
+ switch r.token.delimValue {
+ case '{':
+ start, end = '{', '}'
+ case '[':
+ start, end = '[', ']'
+ default:
+ r.consume()
+ return
+ }
+
+ r.consume()
+
+ level := 1
+ inQuotes := false
+ wasEscape := false
+
+ for i, c := range r.Data[r.pos:] {
+ switch {
+ case c == start && !inQuotes:
+ level++
+ case c == end && !inQuotes:
+ level--
+ if level == 0 {
+ r.pos += i + 1
+ if !json.Valid(r.Data[startPos:r.pos]) {
+ r.pos = len(r.Data)
+ r.fatalError = &LexerError{
+ Reason: "skipped array/object json value is invalid",
+ Offset: r.pos,
+ Data: string(r.Data[r.pos:]),
+ }
+ }
+ return
+ }
+ case c == '\\' && inQuotes:
+ wasEscape = !wasEscape
+ continue
+ case c == '"' && inQuotes:
+ inQuotes = wasEscape
+ case c == '"':
+ inQuotes = true
+ }
+ wasEscape = false
+ }
+ r.pos = len(r.Data)
+ r.fatalError = &LexerError{
+ Reason: "EOF reached while skipping array/object or token",
+ Offset: r.pos,
+ Data: string(r.Data[r.pos:]),
+ }
+}
+
+// Raw fetches the next item recursively as a data slice
+func (r *Lexer) Raw() []byte {
+ r.SkipRecursive()
+ if !r.Ok() {
+ return nil
+ }
+ return r.Data[r.start:r.pos]
+}
+
+// IsStart returns whether the lexer is positioned at the start
+// of an input string.
+func (r *Lexer) IsStart() bool {
+ return r.pos == 0
+}
+
+// Consumed reads all remaining bytes from the input, publishing an error if
+// there is anything but whitespace remaining.
+func (r *Lexer) Consumed() {
+ if r.pos > len(r.Data) || !r.Ok() {
+ return
+ }
+
+ for _, c := range r.Data[r.pos:] {
+ if c != ' ' && c != '\t' && c != '\r' && c != '\n' {
+ r.AddError(&LexerError{
+ Reason: "invalid character '" + string(c) + "' after top-level value",
+ Offset: r.pos,
+ Data: string(r.Data[r.pos:]),
+ })
+ return
+ }
+
+ r.pos++
+ r.start++
+ }
+}
+
+func (r *Lexer) unsafeString(skipUnescape bool) (string, []byte) {
+ if r.token.kind == tokenUndef && r.Ok() {
+ r.FetchToken()
+ }
+ if !r.Ok() || r.token.kind != tokenString {
+ r.errInvalidToken("string")
+ return "", nil
+ }
+ if !skipUnescape {
+ if err := r.unescapeStringToken(); err != nil {
+ r.errInvalidToken("string")
+ return "", nil
+ }
+ }
+
+ bytes := r.token.byteValue
+ ret := bytesToStr(r.token.byteValue)
+ r.consume()
+ return ret, bytes
+}
+
+// UnsafeString returns the string value if the token is a string literal.
+//
+// Warning: returned string may point to the input buffer, so the string should not outlive
+// the input buffer. Intended pattern of usage is as an argument to a switch statement.
+func (r *Lexer) UnsafeString() string {
+ ret, _ := r.unsafeString(false)
+ return ret
+}
+
+// UnsafeBytes returns the byte slice if the token is a string literal.
+func (r *Lexer) UnsafeBytes() []byte {
+ _, ret := r.unsafeString(false)
+ return ret
+}
+
+// UnsafeFieldName returns current member name string token
+func (r *Lexer) UnsafeFieldName(skipUnescape bool) string {
+ ret, _ := r.unsafeString(skipUnescape)
+ return ret
+}
+
+// String reads a string literal.
+func (r *Lexer) String() string {
+ if r.token.kind == tokenUndef && r.Ok() {
+ r.FetchToken()
+ }
+ if !r.Ok() || r.token.kind != tokenString {
+ r.errInvalidToken("string")
+ return ""
+ }
+ if err := r.unescapeStringToken(); err != nil {
+ r.errInvalidToken("string")
+ return ""
+ }
+ var ret string
+ if r.token.byteValueCloned {
+ ret = bytesToStr(r.token.byteValue)
+ } else {
+ ret = string(r.token.byteValue)
+ }
+ r.consume()
+ return ret
+}
+
+// StringIntern reads a string literal, and performs string interning on it.
+func (r *Lexer) StringIntern() string {
+ if r.token.kind == tokenUndef && r.Ok() {
+ r.FetchToken()
+ }
+ if !r.Ok() || r.token.kind != tokenString {
+ r.errInvalidToken("string")
+ return ""
+ }
+ if err := r.unescapeStringToken(); err != nil {
+ r.errInvalidToken("string")
+ return ""
+ }
+ ret := intern.Bytes(r.token.byteValue)
+ r.consume()
+ return ret
+}
+
+// Bytes reads a string literal and base64 decodes it into a byte slice.
+func (r *Lexer) Bytes() []byte {
+ if r.token.kind == tokenUndef && r.Ok() {
+ r.FetchToken()
+ }
+ if !r.Ok() || r.token.kind != tokenString {
+ r.errInvalidToken("string")
+ return nil
+ }
+ if err := r.unescapeStringToken(); err != nil {
+ r.errInvalidToken("string")
+ return nil
+ }
+ ret := make([]byte, base64.StdEncoding.DecodedLen(len(r.token.byteValue)))
+ n, err := base64.StdEncoding.Decode(ret, r.token.byteValue)
+ if err != nil {
+ r.fatalError = &LexerError{
+ Reason: err.Error(),
+ }
+ return nil
+ }
+
+ r.consume()
+ return ret[:n]
+}
+
+// Bool reads a true or false boolean keyword.
+func (r *Lexer) Bool() bool {
+ if r.token.kind == tokenUndef && r.Ok() {
+ r.FetchToken()
+ }
+ if !r.Ok() || r.token.kind != tokenBool {
+ r.errInvalidToken("bool")
+ return false
+ }
+ ret := r.token.boolValue
+ r.consume()
+ return ret
+}
+
+func (r *Lexer) number() string {
+ if r.token.kind == tokenUndef && r.Ok() {
+ r.FetchToken()
+ }
+ if !r.Ok() || r.token.kind != tokenNumber {
+ r.errInvalidToken("number")
+ return ""
+ }
+ ret := bytesToStr(r.token.byteValue)
+ r.consume()
+ return ret
+}
+
+func (r *Lexer) Uint8() uint8 {
+ s := r.number()
+ if !r.Ok() {
+ return 0
+ }
+
+ n, err := strconv.ParseUint(s, 10, 8)
+ if err != nil {
+ r.addNonfatalError(&LexerError{
+ Offset: r.start,
+ Reason: err.Error(),
+ Data: s,
+ })
+ }
+ return uint8(n)
+}
+
+func (r *Lexer) Uint16() uint16 {
+ s := r.number()
+ if !r.Ok() {
+ return 0
+ }
+
+ n, err := strconv.ParseUint(s, 10, 16)
+ if err != nil {
+ r.addNonfatalError(&LexerError{
+ Offset: r.start,
+ Reason: err.Error(),
+ Data: s,
+ })
+ }
+ return uint16(n)
+}
+
+func (r *Lexer) Uint32() uint32 {
+ s := r.number()
+ if !r.Ok() {
+ return 0
+ }
+
+ n, err := strconv.ParseUint(s, 10, 32)
+ if err != nil {
+ r.addNonfatalError(&LexerError{
+ Offset: r.start,
+ Reason: err.Error(),
+ Data: s,
+ })
+ }
+ return uint32(n)
+}
+
+func (r *Lexer) Uint64() uint64 {
+ s := r.number()
+ if !r.Ok() {
+ return 0
+ }
+
+ n, err := strconv.ParseUint(s, 10, 64)
+ if err != nil {
+ r.addNonfatalError(&LexerError{
+ Offset: r.start,
+ Reason: err.Error(),
+ Data: s,
+ })
+ }
+ return n
+}
+
+func (r *Lexer) Uint() uint {
+ return uint(r.Uint64())
+}
+
+func (r *Lexer) Int8() int8 {
+ s := r.number()
+ if !r.Ok() {
+ return 0
+ }
+
+ n, err := strconv.ParseInt(s, 10, 8)
+ if err != nil {
+ r.addNonfatalError(&LexerError{
+ Offset: r.start,
+ Reason: err.Error(),
+ Data: s,
+ })
+ }
+ return int8(n)
+}
+
+func (r *Lexer) Int16() int16 {
+ s := r.number()
+ if !r.Ok() {
+ return 0
+ }
+
+ n, err := strconv.ParseInt(s, 10, 16)
+ if err != nil {
+ r.addNonfatalError(&LexerError{
+ Offset: r.start,
+ Reason: err.Error(),
+ Data: s,
+ })
+ }
+ return int16(n)
+}
+
+func (r *Lexer) Int32() int32 {
+ s := r.number()
+ if !r.Ok() {
+ return 0
+ }
+
+ n, err := strconv.ParseInt(s, 10, 32)
+ if err != nil {
+ r.addNonfatalError(&LexerError{
+ Offset: r.start,
+ Reason: err.Error(),
+ Data: s,
+ })
+ }
+ return int32(n)
+}
+
+func (r *Lexer) Int64() int64 {
+ s := r.number()
+ if !r.Ok() {
+ return 0
+ }
+
+ n, err := strconv.ParseInt(s, 10, 64)
+ if err != nil {
+ r.addNonfatalError(&LexerError{
+ Offset: r.start,
+ Reason: err.Error(),
+ Data: s,
+ })
+ }
+ return n
+}
+
+func (r *Lexer) Int() int {
+ return int(r.Int64())
+}
+
+func (r *Lexer) Uint8Str() uint8 {
+ s, b := r.unsafeString(false)
+ if !r.Ok() {
+ return 0
+ }
+
+ n, err := strconv.ParseUint(s, 10, 8)
+ if err != nil {
+ r.addNonfatalError(&LexerError{
+ Offset: r.start,
+ Reason: err.Error(),
+ Data: string(b),
+ })
+ }
+ return uint8(n)
+}
+
+func (r *Lexer) Uint16Str() uint16 {
+ s, b := r.unsafeString(false)
+ if !r.Ok() {
+ return 0
+ }
+
+ n, err := strconv.ParseUint(s, 10, 16)
+ if err != nil {
+ r.addNonfatalError(&LexerError{
+ Offset: r.start,
+ Reason: err.Error(),
+ Data: string(b),
+ })
+ }
+ return uint16(n)
+}
+
+func (r *Lexer) Uint32Str() uint32 {
+ s, b := r.unsafeString(false)
+ if !r.Ok() {
+ return 0
+ }
+
+ n, err := strconv.ParseUint(s, 10, 32)
+ if err != nil {
+ r.addNonfatalError(&LexerError{
+ Offset: r.start,
+ Reason: err.Error(),
+ Data: string(b),
+ })
+ }
+ return uint32(n)
+}
+
+func (r *Lexer) Uint64Str() uint64 {
+ s, b := r.unsafeString(false)
+ if !r.Ok() {
+ return 0
+ }
+
+ n, err := strconv.ParseUint(s, 10, 64)
+ if err != nil {
+ r.addNonfatalError(&LexerError{
+ Offset: r.start,
+ Reason: err.Error(),
+ Data: string(b),
+ })
+ }
+ return n
+}
+
+func (r *Lexer) UintStr() uint {
+ return uint(r.Uint64Str())
+}
+
+func (r *Lexer) UintptrStr() uintptr {
+ return uintptr(r.Uint64Str())
+}
+
+func (r *Lexer) Int8Str() int8 {
+ s, b := r.unsafeString(false)
+ if !r.Ok() {
+ return 0
+ }
+
+ n, err := strconv.ParseInt(s, 10, 8)
+ if err != nil {
+ r.addNonfatalError(&LexerError{
+ Offset: r.start,
+ Reason: err.Error(),
+ Data: string(b),
+ })
+ }
+ return int8(n)
+}
+
+func (r *Lexer) Int16Str() int16 {
+ s, b := r.unsafeString(false)
+ if !r.Ok() {
+ return 0
+ }
+
+ n, err := strconv.ParseInt(s, 10, 16)
+ if err != nil {
+ r.addNonfatalError(&LexerError{
+ Offset: r.start,
+ Reason: err.Error(),
+ Data: string(b),
+ })
+ }
+ return int16(n)
+}
+
+func (r *Lexer) Int32Str() int32 {
+ s, b := r.unsafeString(false)
+ if !r.Ok() {
+ return 0
+ }
+
+ n, err := strconv.ParseInt(s, 10, 32)
+ if err != nil {
+ r.addNonfatalError(&LexerError{
+ Offset: r.start,
+ Reason: err.Error(),
+ Data: string(b),
+ })
+ }
+ return int32(n)
+}
+
+func (r *Lexer) Int64Str() int64 {
+ s, b := r.unsafeString(false)
+ if !r.Ok() {
+ return 0
+ }
+
+ n, err := strconv.ParseInt(s, 10, 64)
+ if err != nil {
+ r.addNonfatalError(&LexerError{
+ Offset: r.start,
+ Reason: err.Error(),
+ Data: string(b),
+ })
+ }
+ return n
+}
+
+func (r *Lexer) IntStr() int {
+ return int(r.Int64Str())
+}
+
+func (r *Lexer) Float32() float32 {
+ s := r.number()
+ if !r.Ok() {
+ return 0
+ }
+
+ n, err := strconv.ParseFloat(s, 32)
+ if err != nil {
+ r.addNonfatalError(&LexerError{
+ Offset: r.start,
+ Reason: err.Error(),
+ Data: s,
+ })
+ }
+ return float32(n)
+}
+
+func (r *Lexer) Float32Str() float32 {
+ s, b := r.unsafeString(false)
+ if !r.Ok() {
+ return 0
+ }
+ n, err := strconv.ParseFloat(s, 32)
+ if err != nil {
+ r.addNonfatalError(&LexerError{
+ Offset: r.start,
+ Reason: err.Error(),
+ Data: string(b),
+ })
+ }
+ return float32(n)
+}
+
+func (r *Lexer) Float64() float64 {
+ s := r.number()
+ if !r.Ok() {
+ return 0
+ }
+
+ n, err := strconv.ParseFloat(s, 64)
+ if err != nil {
+ r.addNonfatalError(&LexerError{
+ Offset: r.start,
+ Reason: err.Error(),
+ Data: s,
+ })
+ }
+ return n
+}
+
+func (r *Lexer) Float64Str() float64 {
+ s, b := r.unsafeString(false)
+ if !r.Ok() {
+ return 0
+ }
+ n, err := strconv.ParseFloat(s, 64)
+ if err != nil {
+ r.addNonfatalError(&LexerError{
+ Offset: r.start,
+ Reason: err.Error(),
+ Data: string(b),
+ })
+ }
+ return n
+}
+
+func (r *Lexer) Error() error {
+ return r.fatalError
+}
+
+func (r *Lexer) AddError(e error) {
+ if r.fatalError == nil {
+ r.fatalError = e
+ }
+}
+
+func (r *Lexer) AddNonFatalError(e error) {
+ r.addNonfatalError(&LexerError{
+ Offset: r.start,
+ Data: string(r.Data[r.start:r.pos]),
+ Reason: e.Error(),
+ })
+}
+
+func (r *Lexer) addNonfatalError(err *LexerError) {
+ if r.UseMultipleErrors {
+ // We don't want to add errors with the same offset.
+ if len(r.multipleErrors) != 0 && r.multipleErrors[len(r.multipleErrors)-1].Offset == err.Offset {
+ return
+ }
+ r.multipleErrors = append(r.multipleErrors, err)
+ return
+ }
+ r.fatalError = err
+}
+
+func (r *Lexer) GetNonFatalErrors() []*LexerError {
+ return r.multipleErrors
+}
+
+// JsonNumber fetches and json.Number from 'encoding/json' package.
+// Both int, float or string, contains them are valid values
+func (r *Lexer) JsonNumber() json.Number {
+ if r.token.kind == tokenUndef && r.Ok() {
+ r.FetchToken()
+ }
+ if !r.Ok() {
+ r.errInvalidToken("json.Number")
+ return json.Number("")
+ }
+
+ switch r.token.kind {
+ case tokenString:
+ return json.Number(r.String())
+ case tokenNumber:
+ return json.Number(r.Raw())
+ case tokenNull:
+ r.Null()
+ return json.Number("")
+ default:
+ r.errSyntax()
+ return json.Number("")
+ }
+}
+
+// Interface fetches an interface{} analogous to the 'encoding/json' package.
+func (r *Lexer) Interface() interface{} {
+ if r.token.kind == tokenUndef && r.Ok() {
+ r.FetchToken()
+ }
+
+ if !r.Ok() {
+ return nil
+ }
+ switch r.token.kind {
+ case tokenString:
+ return r.String()
+ case tokenNumber:
+ return r.Float64()
+ case tokenBool:
+ return r.Bool()
+ case tokenNull:
+ r.Null()
+ return nil
+ }
+
+ if r.token.delimValue == '{' {
+ r.consume()
+
+ ret := map[string]interface{}{}
+ for !r.IsDelim('}') {
+ key := r.String()
+ r.WantColon()
+ ret[key] = r.Interface()
+ r.WantComma()
+ }
+ r.Delim('}')
+
+ if r.Ok() {
+ return ret
+ } else {
+ return nil
+ }
+ } else if r.token.delimValue == '[' {
+ r.consume()
+
+ ret := []interface{}{}
+ for !r.IsDelim(']') {
+ ret = append(ret, r.Interface())
+ r.WantComma()
+ }
+ r.Delim(']')
+
+ if r.Ok() {
+ return ret
+ } else {
+ return nil
+ }
+ }
+ r.errSyntax()
+ return nil
+}
+
+// WantComma requires a comma to be present before fetching next token.
+func (r *Lexer) WantComma() {
+ r.wantSep = ','
+ r.firstElement = false
+}
+
+// WantColon requires a colon to be present before fetching next token.
+func (r *Lexer) WantColon() {
+ r.wantSep = ':'
+ r.firstElement = false
+}
diff --git a/vendor/github.com/mailru/easyjson/jwriter/writer.go b/vendor/github.com/mailru/easyjson/jwriter/writer.go
new file mode 100644
index 0000000..2c5b201
--- /dev/null
+++ b/vendor/github.com/mailru/easyjson/jwriter/writer.go
@@ -0,0 +1,405 @@
+// Package jwriter contains a JSON writer.
+package jwriter
+
+import (
+ "io"
+ "strconv"
+ "unicode/utf8"
+
+ "github.com/mailru/easyjson/buffer"
+)
+
+// Flags describe various encoding options. The behavior may be actually implemented in the encoder, but
+// Flags field in Writer is used to set and pass them around.
+type Flags int
+
+const (
+ NilMapAsEmpty Flags = 1 << iota // Encode nil map as '{}' rather than 'null'.
+ NilSliceAsEmpty // Encode nil slice as '[]' rather than 'null'.
+)
+
+// Writer is a JSON writer.
+type Writer struct {
+ Flags Flags
+
+ Error error
+ Buffer buffer.Buffer
+ NoEscapeHTML bool
+}
+
+// Size returns the size of the data that was written out.
+func (w *Writer) Size() int {
+ return w.Buffer.Size()
+}
+
+// DumpTo outputs the data to given io.Writer, resetting the buffer.
+func (w *Writer) DumpTo(out io.Writer) (written int, err error) {
+ return w.Buffer.DumpTo(out)
+}
+
+// BuildBytes returns writer data as a single byte slice. You can optionally provide one byte slice
+// as argument that it will try to reuse.
+func (w *Writer) BuildBytes(reuse ...[]byte) ([]byte, error) {
+ if w.Error != nil {
+ return nil, w.Error
+ }
+
+ return w.Buffer.BuildBytes(reuse...), nil
+}
+
+// ReadCloser returns an io.ReadCloser that can be used to read the data.
+// ReadCloser also resets the buffer.
+func (w *Writer) ReadCloser() (io.ReadCloser, error) {
+ if w.Error != nil {
+ return nil, w.Error
+ }
+
+ return w.Buffer.ReadCloser(), nil
+}
+
+// RawByte appends raw binary data to the buffer.
+func (w *Writer) RawByte(c byte) {
+ w.Buffer.AppendByte(c)
+}
+
+// RawByte appends raw binary data to the buffer.
+func (w *Writer) RawString(s string) {
+ w.Buffer.AppendString(s)
+}
+
+// Raw appends raw binary data to the buffer or sets the error if it is given. Useful for
+// calling with results of MarshalJSON-like functions.
+func (w *Writer) Raw(data []byte, err error) {
+ switch {
+ case w.Error != nil:
+ return
+ case err != nil:
+ w.Error = err
+ case len(data) > 0:
+ w.Buffer.AppendBytes(data)
+ default:
+ w.RawString("null")
+ }
+}
+
+// RawText encloses raw binary data in quotes and appends in to the buffer.
+// Useful for calling with results of MarshalText-like functions.
+func (w *Writer) RawText(data []byte, err error) {
+ switch {
+ case w.Error != nil:
+ return
+ case err != nil:
+ w.Error = err
+ case len(data) > 0:
+ w.String(string(data))
+ default:
+ w.RawString("null")
+ }
+}
+
+// Base64Bytes appends data to the buffer after base64 encoding it
+func (w *Writer) Base64Bytes(data []byte) {
+ if data == nil {
+ w.Buffer.AppendString("null")
+ return
+ }
+ w.Buffer.AppendByte('"')
+ w.base64(data)
+ w.Buffer.AppendByte('"')
+}
+
+func (w *Writer) Uint8(n uint8) {
+ w.Buffer.EnsureSpace(3)
+ w.Buffer.Buf = strconv.AppendUint(w.Buffer.Buf, uint64(n), 10)
+}
+
+func (w *Writer) Uint16(n uint16) {
+ w.Buffer.EnsureSpace(5)
+ w.Buffer.Buf = strconv.AppendUint(w.Buffer.Buf, uint64(n), 10)
+}
+
+func (w *Writer) Uint32(n uint32) {
+ w.Buffer.EnsureSpace(10)
+ w.Buffer.Buf = strconv.AppendUint(w.Buffer.Buf, uint64(n), 10)
+}
+
+func (w *Writer) Uint(n uint) {
+ w.Buffer.EnsureSpace(20)
+ w.Buffer.Buf = strconv.AppendUint(w.Buffer.Buf, uint64(n), 10)
+}
+
+func (w *Writer) Uint64(n uint64) {
+ w.Buffer.EnsureSpace(20)
+ w.Buffer.Buf = strconv.AppendUint(w.Buffer.Buf, n, 10)
+}
+
+func (w *Writer) Int8(n int8) {
+ w.Buffer.EnsureSpace(4)
+ w.Buffer.Buf = strconv.AppendInt(w.Buffer.Buf, int64(n), 10)
+}
+
+func (w *Writer) Int16(n int16) {
+ w.Buffer.EnsureSpace(6)
+ w.Buffer.Buf = strconv.AppendInt(w.Buffer.Buf, int64(n), 10)
+}
+
+func (w *Writer) Int32(n int32) {
+ w.Buffer.EnsureSpace(11)
+ w.Buffer.Buf = strconv.AppendInt(w.Buffer.Buf, int64(n), 10)
+}
+
+func (w *Writer) Int(n int) {
+ w.Buffer.EnsureSpace(21)
+ w.Buffer.Buf = strconv.AppendInt(w.Buffer.Buf, int64(n), 10)
+}
+
+func (w *Writer) Int64(n int64) {
+ w.Buffer.EnsureSpace(21)
+ w.Buffer.Buf = strconv.AppendInt(w.Buffer.Buf, n, 10)
+}
+
+func (w *Writer) Uint8Str(n uint8) {
+ w.Buffer.EnsureSpace(3)
+ w.Buffer.Buf = append(w.Buffer.Buf, '"')
+ w.Buffer.Buf = strconv.AppendUint(w.Buffer.Buf, uint64(n), 10)
+ w.Buffer.Buf = append(w.Buffer.Buf, '"')
+}
+
+func (w *Writer) Uint16Str(n uint16) {
+ w.Buffer.EnsureSpace(5)
+ w.Buffer.Buf = append(w.Buffer.Buf, '"')
+ w.Buffer.Buf = strconv.AppendUint(w.Buffer.Buf, uint64(n), 10)
+ w.Buffer.Buf = append(w.Buffer.Buf, '"')
+}
+
+func (w *Writer) Uint32Str(n uint32) {
+ w.Buffer.EnsureSpace(10)
+ w.Buffer.Buf = append(w.Buffer.Buf, '"')
+ w.Buffer.Buf = strconv.AppendUint(w.Buffer.Buf, uint64(n), 10)
+ w.Buffer.Buf = append(w.Buffer.Buf, '"')
+}
+
+func (w *Writer) UintStr(n uint) {
+ w.Buffer.EnsureSpace(20)
+ w.Buffer.Buf = append(w.Buffer.Buf, '"')
+ w.Buffer.Buf = strconv.AppendUint(w.Buffer.Buf, uint64(n), 10)
+ w.Buffer.Buf = append(w.Buffer.Buf, '"')
+}
+
+func (w *Writer) Uint64Str(n uint64) {
+ w.Buffer.EnsureSpace(20)
+ w.Buffer.Buf = append(w.Buffer.Buf, '"')
+ w.Buffer.Buf = strconv.AppendUint(w.Buffer.Buf, n, 10)
+ w.Buffer.Buf = append(w.Buffer.Buf, '"')
+}
+
+func (w *Writer) UintptrStr(n uintptr) {
+ w.Buffer.EnsureSpace(20)
+ w.Buffer.Buf = append(w.Buffer.Buf, '"')
+ w.Buffer.Buf = strconv.AppendUint(w.Buffer.Buf, uint64(n), 10)
+ w.Buffer.Buf = append(w.Buffer.Buf, '"')
+}
+
+func (w *Writer) Int8Str(n int8) {
+ w.Buffer.EnsureSpace(4)
+ w.Buffer.Buf = append(w.Buffer.Buf, '"')
+ w.Buffer.Buf = strconv.AppendInt(w.Buffer.Buf, int64(n), 10)
+ w.Buffer.Buf = append(w.Buffer.Buf, '"')
+}
+
+func (w *Writer) Int16Str(n int16) {
+ w.Buffer.EnsureSpace(6)
+ w.Buffer.Buf = append(w.Buffer.Buf, '"')
+ w.Buffer.Buf = strconv.AppendInt(w.Buffer.Buf, int64(n), 10)
+ w.Buffer.Buf = append(w.Buffer.Buf, '"')
+}
+
+func (w *Writer) Int32Str(n int32) {
+ w.Buffer.EnsureSpace(11)
+ w.Buffer.Buf = append(w.Buffer.Buf, '"')
+ w.Buffer.Buf = strconv.AppendInt(w.Buffer.Buf, int64(n), 10)
+ w.Buffer.Buf = append(w.Buffer.Buf, '"')
+}
+
+func (w *Writer) IntStr(n int) {
+ w.Buffer.EnsureSpace(21)
+ w.Buffer.Buf = append(w.Buffer.Buf, '"')
+ w.Buffer.Buf = strconv.AppendInt(w.Buffer.Buf, int64(n), 10)
+ w.Buffer.Buf = append(w.Buffer.Buf, '"')
+}
+
+func (w *Writer) Int64Str(n int64) {
+ w.Buffer.EnsureSpace(21)
+ w.Buffer.Buf = append(w.Buffer.Buf, '"')
+ w.Buffer.Buf = strconv.AppendInt(w.Buffer.Buf, n, 10)
+ w.Buffer.Buf = append(w.Buffer.Buf, '"')
+}
+
+func (w *Writer) Float32(n float32) {
+ w.Buffer.EnsureSpace(20)
+ w.Buffer.Buf = strconv.AppendFloat(w.Buffer.Buf, float64(n), 'g', -1, 32)
+}
+
+func (w *Writer) Float32Str(n float32) {
+ w.Buffer.EnsureSpace(20)
+ w.Buffer.Buf = append(w.Buffer.Buf, '"')
+ w.Buffer.Buf = strconv.AppendFloat(w.Buffer.Buf, float64(n), 'g', -1, 32)
+ w.Buffer.Buf = append(w.Buffer.Buf, '"')
+}
+
+func (w *Writer) Float64(n float64) {
+ w.Buffer.EnsureSpace(20)
+ w.Buffer.Buf = strconv.AppendFloat(w.Buffer.Buf, n, 'g', -1, 64)
+}
+
+func (w *Writer) Float64Str(n float64) {
+ w.Buffer.EnsureSpace(20)
+ w.Buffer.Buf = append(w.Buffer.Buf, '"')
+ w.Buffer.Buf = strconv.AppendFloat(w.Buffer.Buf, float64(n), 'g', -1, 64)
+ w.Buffer.Buf = append(w.Buffer.Buf, '"')
+}
+
+func (w *Writer) Bool(v bool) {
+ w.Buffer.EnsureSpace(5)
+ if v {
+ w.Buffer.Buf = append(w.Buffer.Buf, "true"...)
+ } else {
+ w.Buffer.Buf = append(w.Buffer.Buf, "false"...)
+ }
+}
+
+const chars = "0123456789abcdef"
+
+func getTable(falseValues ...int) [128]bool {
+ table := [128]bool{}
+
+ for i := 0; i < 128; i++ {
+ table[i] = true
+ }
+
+ for _, v := range falseValues {
+ table[v] = false
+ }
+
+ return table
+}
+
+var (
+ htmlEscapeTable = getTable(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, '"', '&', '<', '>', '\\')
+ htmlNoEscapeTable = getTable(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, '"', '\\')
+)
+
+func (w *Writer) String(s string) {
+ w.Buffer.AppendByte('"')
+
+ // Portions of the string that contain no escapes are appended as
+ // byte slices.
+
+ p := 0 // last non-escape symbol
+
+ escapeTable := &htmlEscapeTable
+ if w.NoEscapeHTML {
+ escapeTable = &htmlNoEscapeTable
+ }
+
+ for i := 0; i < len(s); {
+ c := s[i]
+
+ if c < utf8.RuneSelf {
+ if escapeTable[c] {
+ // single-width character, no escaping is required
+ i++
+ continue
+ }
+
+ w.Buffer.AppendString(s[p:i])
+ switch c {
+ case '\t':
+ w.Buffer.AppendString(`\t`)
+ case '\r':
+ w.Buffer.AppendString(`\r`)
+ case '\n':
+ w.Buffer.AppendString(`\n`)
+ case '\\':
+ w.Buffer.AppendString(`\\`)
+ case '"':
+ w.Buffer.AppendString(`\"`)
+ default:
+ w.Buffer.AppendString(`\u00`)
+ w.Buffer.AppendByte(chars[c>>4])
+ w.Buffer.AppendByte(chars[c&0xf])
+ }
+
+ i++
+ p = i
+ continue
+ }
+
+ // broken utf
+ runeValue, runeWidth := utf8.DecodeRuneInString(s[i:])
+ if runeValue == utf8.RuneError && runeWidth == 1 {
+ w.Buffer.AppendString(s[p:i])
+ w.Buffer.AppendString(`\ufffd`)
+ i++
+ p = i
+ continue
+ }
+
+ // jsonp stuff - tab separator and line separator
+ if runeValue == '\u2028' || runeValue == '\u2029' {
+ w.Buffer.AppendString(s[p:i])
+ w.Buffer.AppendString(`\u202`)
+ w.Buffer.AppendByte(chars[runeValue&0xf])
+ i += runeWidth
+ p = i
+ continue
+ }
+ i += runeWidth
+ }
+ w.Buffer.AppendString(s[p:])
+ w.Buffer.AppendByte('"')
+}
+
+const encode = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
+const padChar = '='
+
+func (w *Writer) base64(in []byte) {
+
+ if len(in) == 0 {
+ return
+ }
+
+ w.Buffer.EnsureSpace(((len(in)-1)/3 + 1) * 4)
+
+ si := 0
+ n := (len(in) / 3) * 3
+
+ for si < n {
+ // Convert 3x 8bit source bytes into 4 bytes
+ val := uint(in[si+0])<<16 | uint(in[si+1])<<8 | uint(in[si+2])
+
+ w.Buffer.Buf = append(w.Buffer.Buf, encode[val>>18&0x3F], encode[val>>12&0x3F], encode[val>>6&0x3F], encode[val&0x3F])
+
+ si += 3
+ }
+
+ remain := len(in) - si
+ if remain == 0 {
+ return
+ }
+
+ // Add the remaining small block
+ val := uint(in[si+0]) << 16
+ if remain == 2 {
+ val |= uint(in[si+1]) << 8
+ }
+
+ w.Buffer.Buf = append(w.Buffer.Buf, encode[val>>18&0x3F], encode[val>>12&0x3F])
+
+ switch remain {
+ case 2:
+ w.Buffer.Buf = append(w.Buffer.Buf, encode[val>>6&0x3F], byte(padChar))
+ case 1:
+ w.Buffer.Buf = append(w.Buffer.Buf, byte(padChar), byte(padChar))
+ }
+}
diff --git a/vendor/github.com/mailru/easyjson/raw.go b/vendor/github.com/mailru/easyjson/raw.go
new file mode 100644
index 0000000..81bd002
--- /dev/null
+++ b/vendor/github.com/mailru/easyjson/raw.go
@@ -0,0 +1,45 @@
+package easyjson
+
+import (
+ "github.com/mailru/easyjson/jlexer"
+ "github.com/mailru/easyjson/jwriter"
+)
+
+// RawMessage is a raw piece of JSON (number, string, bool, object, array or
+// null) that is extracted without parsing and output as is during marshaling.
+type RawMessage []byte
+
+// MarshalEasyJSON does JSON marshaling using easyjson interface.
+func (v *RawMessage) MarshalEasyJSON(w *jwriter.Writer) {
+ if len(*v) == 0 {
+ w.RawString("null")
+ } else {
+ w.Raw(*v, nil)
+ }
+}
+
+// UnmarshalEasyJSON does JSON unmarshaling using easyjson interface.
+func (v *RawMessage) UnmarshalEasyJSON(l *jlexer.Lexer) {
+ *v = RawMessage(l.Raw())
+}
+
+// UnmarshalJSON implements encoding/json.Unmarshaler interface.
+func (v *RawMessage) UnmarshalJSON(data []byte) error {
+ *v = data
+ return nil
+}
+
+var nullBytes = []byte("null")
+
+// MarshalJSON implements encoding/json.Marshaler interface.
+func (v RawMessage) MarshalJSON() ([]byte, error) {
+ if len(v) == 0 {
+ return nullBytes, nil
+ }
+ return v, nil
+}
+
+// IsDefined is required for integration with omitempty easyjson logic.
+func (v *RawMessage) IsDefined() bool {
+ return len(*v) > 0
+}
diff --git a/vendor/github.com/mailru/easyjson/unknown_fields.go b/vendor/github.com/mailru/easyjson/unknown_fields.go
new file mode 100644
index 0000000..55538ea
--- /dev/null
+++ b/vendor/github.com/mailru/easyjson/unknown_fields.go
@@ -0,0 +1,32 @@
+package easyjson
+
+import (
+ jlexer "github.com/mailru/easyjson/jlexer"
+ "github.com/mailru/easyjson/jwriter"
+)
+
+// UnknownFieldsProxy implemets UnknownsUnmarshaler and UnknownsMarshaler
+// use it as embedded field in your structure to parse and then serialize unknown struct fields
+type UnknownFieldsProxy struct {
+ unknownFields map[string][]byte
+}
+
+func (s *UnknownFieldsProxy) UnmarshalUnknown(in *jlexer.Lexer, key string) {
+ if s.unknownFields == nil {
+ s.unknownFields = make(map[string][]byte, 1)
+ }
+ s.unknownFields[key] = in.Raw()
+}
+
+func (s UnknownFieldsProxy) MarshalUnknowns(out *jwriter.Writer, first bool) {
+ for key, val := range s.unknownFields {
+ if first {
+ first = false
+ } else {
+ out.RawByte(',')
+ }
+ out.String(string(key))
+ out.RawByte(':')
+ out.Raw(val, nil)
+ }
+}
diff --git a/vendor/github.com/mattn/go-colorable/LICENSE b/vendor/github.com/mattn/go-colorable/LICENSE
new file mode 100644
index 0000000..91b5cef
--- /dev/null
+++ b/vendor/github.com/mattn/go-colorable/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2016 Yasuhiro Matsumoto
+
+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/mattn/go-colorable/README.md b/vendor/github.com/mattn/go-colorable/README.md
new file mode 100644
index 0000000..ca04837
--- /dev/null
+++ b/vendor/github.com/mattn/go-colorable/README.md
@@ -0,0 +1,48 @@
+# go-colorable
+
+[![Build Status](https://github.com/mattn/go-colorable/workflows/test/badge.svg)](https://github.com/mattn/go-colorable/actions?query=workflow%3Atest)
+[![Codecov](https://codecov.io/gh/mattn/go-colorable/branch/master/graph/badge.svg)](https://codecov.io/gh/mattn/go-colorable)
+[![GoDoc](https://godoc.org/github.com/mattn/go-colorable?status.svg)](http://godoc.org/github.com/mattn/go-colorable)
+[![Go Report Card](https://goreportcard.com/badge/mattn/go-colorable)](https://goreportcard.com/report/mattn/go-colorable)
+
+Colorable writer for windows.
+
+For example, most of logger packages doesn't show colors on windows. (I know we can do it with ansicon. But I don't want.)
+This package is possible to handle escape sequence for ansi color on windows.
+
+## Too Bad!
+
+![](https://raw.githubusercontent.com/mattn/go-colorable/gh-pages/bad.png)
+
+
+## So Good!
+
+![](https://raw.githubusercontent.com/mattn/go-colorable/gh-pages/good.png)
+
+## Usage
+
+```go
+logrus.SetFormatter(&logrus.TextFormatter{ForceColors: true})
+logrus.SetOutput(colorable.NewColorableStdout())
+
+logrus.Info("succeeded")
+logrus.Warn("not correct")
+logrus.Error("something error")
+logrus.Fatal("panic")
+```
+
+You can compile above code on non-windows OSs.
+
+## Installation
+
+```
+$ go get github.com/mattn/go-colorable
+```
+
+# License
+
+MIT
+
+# Author
+
+Yasuhiro Matsumoto (a.k.a mattn)
diff --git a/vendor/github.com/mattn/go-colorable/colorable_appengine.go b/vendor/github.com/mattn/go-colorable/colorable_appengine.go
new file mode 100644
index 0000000..416d1bb
--- /dev/null
+++ b/vendor/github.com/mattn/go-colorable/colorable_appengine.go
@@ -0,0 +1,38 @@
+//go:build appengine
+// +build appengine
+
+package colorable
+
+import (
+ "io"
+ "os"
+
+ _ "github.com/mattn/go-isatty"
+)
+
+// NewColorable returns new instance of Writer which handles escape sequence.
+func NewColorable(file *os.File) io.Writer {
+ if file == nil {
+ panic("nil passed instead of *os.File to NewColorable()")
+ }
+
+ return file
+}
+
+// NewColorableStdout returns new instance of Writer which handles escape sequence for stdout.
+func NewColorableStdout() io.Writer {
+ return os.Stdout
+}
+
+// NewColorableStderr returns new instance of Writer which handles escape sequence for stderr.
+func NewColorableStderr() io.Writer {
+ return os.Stderr
+}
+
+// EnableColorsStdout enable colors if possible.
+func EnableColorsStdout(enabled *bool) func() {
+ if enabled != nil {
+ *enabled = true
+ }
+ return func() {}
+}
diff --git a/vendor/github.com/mattn/go-colorable/colorable_others.go b/vendor/github.com/mattn/go-colorable/colorable_others.go
new file mode 100644
index 0000000..766d946
--- /dev/null
+++ b/vendor/github.com/mattn/go-colorable/colorable_others.go
@@ -0,0 +1,38 @@
+//go:build !windows && !appengine
+// +build !windows,!appengine
+
+package colorable
+
+import (
+ "io"
+ "os"
+
+ _ "github.com/mattn/go-isatty"
+)
+
+// NewColorable returns new instance of Writer which handles escape sequence.
+func NewColorable(file *os.File) io.Writer {
+ if file == nil {
+ panic("nil passed instead of *os.File to NewColorable()")
+ }
+
+ return file
+}
+
+// NewColorableStdout returns new instance of Writer which handles escape sequence for stdout.
+func NewColorableStdout() io.Writer {
+ return os.Stdout
+}
+
+// NewColorableStderr returns new instance of Writer which handles escape sequence for stderr.
+func NewColorableStderr() io.Writer {
+ return os.Stderr
+}
+
+// EnableColorsStdout enable colors if possible.
+func EnableColorsStdout(enabled *bool) func() {
+ if enabled != nil {
+ *enabled = true
+ }
+ return func() {}
+}
diff --git a/vendor/github.com/mattn/go-colorable/colorable_windows.go b/vendor/github.com/mattn/go-colorable/colorable_windows.go
new file mode 100644
index 0000000..1846ad5
--- /dev/null
+++ b/vendor/github.com/mattn/go-colorable/colorable_windows.go
@@ -0,0 +1,1047 @@
+//go:build windows && !appengine
+// +build windows,!appengine
+
+package colorable
+
+import (
+ "bytes"
+ "io"
+ "math"
+ "os"
+ "strconv"
+ "strings"
+ "sync"
+ "syscall"
+ "unsafe"
+
+ "github.com/mattn/go-isatty"
+)
+
+const (
+ foregroundBlue = 0x1
+ foregroundGreen = 0x2
+ foregroundRed = 0x4
+ foregroundIntensity = 0x8
+ foregroundMask = (foregroundRed | foregroundBlue | foregroundGreen | foregroundIntensity)
+ backgroundBlue = 0x10
+ backgroundGreen = 0x20
+ backgroundRed = 0x40
+ backgroundIntensity = 0x80
+ backgroundMask = (backgroundRed | backgroundBlue | backgroundGreen | backgroundIntensity)
+ commonLvbUnderscore = 0x8000
+
+ cENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x4
+)
+
+const (
+ genericRead = 0x80000000
+ genericWrite = 0x40000000
+)
+
+const (
+ consoleTextmodeBuffer = 0x1
+)
+
+type wchar uint16
+type short int16
+type dword uint32
+type word uint16
+
+type coord struct {
+ x short
+ y short
+}
+
+type smallRect struct {
+ left short
+ top short
+ right short
+ bottom short
+}
+
+type consoleScreenBufferInfo struct {
+ size coord
+ cursorPosition coord
+ attributes word
+ window smallRect
+ maximumWindowSize coord
+}
+
+type consoleCursorInfo struct {
+ size dword
+ visible int32
+}
+
+var (
+ kernel32 = syscall.NewLazyDLL("kernel32.dll")
+ procGetConsoleScreenBufferInfo = kernel32.NewProc("GetConsoleScreenBufferInfo")
+ procSetConsoleTextAttribute = kernel32.NewProc("SetConsoleTextAttribute")
+ procSetConsoleCursorPosition = kernel32.NewProc("SetConsoleCursorPosition")
+ procFillConsoleOutputCharacter = kernel32.NewProc("FillConsoleOutputCharacterW")
+ procFillConsoleOutputAttribute = kernel32.NewProc("FillConsoleOutputAttribute")
+ procGetConsoleCursorInfo = kernel32.NewProc("GetConsoleCursorInfo")
+ procSetConsoleCursorInfo = kernel32.NewProc("SetConsoleCursorInfo")
+ procSetConsoleTitle = kernel32.NewProc("SetConsoleTitleW")
+ procGetConsoleMode = kernel32.NewProc("GetConsoleMode")
+ procSetConsoleMode = kernel32.NewProc("SetConsoleMode")
+ procCreateConsoleScreenBuffer = kernel32.NewProc("CreateConsoleScreenBuffer")
+)
+
+// Writer provides colorable Writer to the console
+type Writer struct {
+ out io.Writer
+ handle syscall.Handle
+ althandle syscall.Handle
+ oldattr word
+ oldpos coord
+ rest bytes.Buffer
+ mutex sync.Mutex
+}
+
+// NewColorable returns new instance of Writer which handles escape sequence from File.
+func NewColorable(file *os.File) io.Writer {
+ if file == nil {
+ panic("nil passed instead of *os.File to NewColorable()")
+ }
+
+ if isatty.IsTerminal(file.Fd()) {
+ var mode uint32
+ if r, _, _ := procGetConsoleMode.Call(file.Fd(), uintptr(unsafe.Pointer(&mode))); r != 0 && mode&cENABLE_VIRTUAL_TERMINAL_PROCESSING != 0 {
+ return file
+ }
+ var csbi consoleScreenBufferInfo
+ handle := syscall.Handle(file.Fd())
+ procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
+ return &Writer{out: file, handle: handle, oldattr: csbi.attributes, oldpos: coord{0, 0}}
+ }
+ return file
+}
+
+// NewColorableStdout returns new instance of Writer which handles escape sequence for stdout.
+func NewColorableStdout() io.Writer {
+ return NewColorable(os.Stdout)
+}
+
+// NewColorableStderr returns new instance of Writer which handles escape sequence for stderr.
+func NewColorableStderr() io.Writer {
+ return NewColorable(os.Stderr)
+}
+
+var color256 = map[int]int{
+ 0: 0x000000,
+ 1: 0x800000,
+ 2: 0x008000,
+ 3: 0x808000,
+ 4: 0x000080,
+ 5: 0x800080,
+ 6: 0x008080,
+ 7: 0xc0c0c0,
+ 8: 0x808080,
+ 9: 0xff0000,
+ 10: 0x00ff00,
+ 11: 0xffff00,
+ 12: 0x0000ff,
+ 13: 0xff00ff,
+ 14: 0x00ffff,
+ 15: 0xffffff,
+ 16: 0x000000,
+ 17: 0x00005f,
+ 18: 0x000087,
+ 19: 0x0000af,
+ 20: 0x0000d7,
+ 21: 0x0000ff,
+ 22: 0x005f00,
+ 23: 0x005f5f,
+ 24: 0x005f87,
+ 25: 0x005faf,
+ 26: 0x005fd7,
+ 27: 0x005fff,
+ 28: 0x008700,
+ 29: 0x00875f,
+ 30: 0x008787,
+ 31: 0x0087af,
+ 32: 0x0087d7,
+ 33: 0x0087ff,
+ 34: 0x00af00,
+ 35: 0x00af5f,
+ 36: 0x00af87,
+ 37: 0x00afaf,
+ 38: 0x00afd7,
+ 39: 0x00afff,
+ 40: 0x00d700,
+ 41: 0x00d75f,
+ 42: 0x00d787,
+ 43: 0x00d7af,
+ 44: 0x00d7d7,
+ 45: 0x00d7ff,
+ 46: 0x00ff00,
+ 47: 0x00ff5f,
+ 48: 0x00ff87,
+ 49: 0x00ffaf,
+ 50: 0x00ffd7,
+ 51: 0x00ffff,
+ 52: 0x5f0000,
+ 53: 0x5f005f,
+ 54: 0x5f0087,
+ 55: 0x5f00af,
+ 56: 0x5f00d7,
+ 57: 0x5f00ff,
+ 58: 0x5f5f00,
+ 59: 0x5f5f5f,
+ 60: 0x5f5f87,
+ 61: 0x5f5faf,
+ 62: 0x5f5fd7,
+ 63: 0x5f5fff,
+ 64: 0x5f8700,
+ 65: 0x5f875f,
+ 66: 0x5f8787,
+ 67: 0x5f87af,
+ 68: 0x5f87d7,
+ 69: 0x5f87ff,
+ 70: 0x5faf00,
+ 71: 0x5faf5f,
+ 72: 0x5faf87,
+ 73: 0x5fafaf,
+ 74: 0x5fafd7,
+ 75: 0x5fafff,
+ 76: 0x5fd700,
+ 77: 0x5fd75f,
+ 78: 0x5fd787,
+ 79: 0x5fd7af,
+ 80: 0x5fd7d7,
+ 81: 0x5fd7ff,
+ 82: 0x5fff00,
+ 83: 0x5fff5f,
+ 84: 0x5fff87,
+ 85: 0x5fffaf,
+ 86: 0x5fffd7,
+ 87: 0x5fffff,
+ 88: 0x870000,
+ 89: 0x87005f,
+ 90: 0x870087,
+ 91: 0x8700af,
+ 92: 0x8700d7,
+ 93: 0x8700ff,
+ 94: 0x875f00,
+ 95: 0x875f5f,
+ 96: 0x875f87,
+ 97: 0x875faf,
+ 98: 0x875fd7,
+ 99: 0x875fff,
+ 100: 0x878700,
+ 101: 0x87875f,
+ 102: 0x878787,
+ 103: 0x8787af,
+ 104: 0x8787d7,
+ 105: 0x8787ff,
+ 106: 0x87af00,
+ 107: 0x87af5f,
+ 108: 0x87af87,
+ 109: 0x87afaf,
+ 110: 0x87afd7,
+ 111: 0x87afff,
+ 112: 0x87d700,
+ 113: 0x87d75f,
+ 114: 0x87d787,
+ 115: 0x87d7af,
+ 116: 0x87d7d7,
+ 117: 0x87d7ff,
+ 118: 0x87ff00,
+ 119: 0x87ff5f,
+ 120: 0x87ff87,
+ 121: 0x87ffaf,
+ 122: 0x87ffd7,
+ 123: 0x87ffff,
+ 124: 0xaf0000,
+ 125: 0xaf005f,
+ 126: 0xaf0087,
+ 127: 0xaf00af,
+ 128: 0xaf00d7,
+ 129: 0xaf00ff,
+ 130: 0xaf5f00,
+ 131: 0xaf5f5f,
+ 132: 0xaf5f87,
+ 133: 0xaf5faf,
+ 134: 0xaf5fd7,
+ 135: 0xaf5fff,
+ 136: 0xaf8700,
+ 137: 0xaf875f,
+ 138: 0xaf8787,
+ 139: 0xaf87af,
+ 140: 0xaf87d7,
+ 141: 0xaf87ff,
+ 142: 0xafaf00,
+ 143: 0xafaf5f,
+ 144: 0xafaf87,
+ 145: 0xafafaf,
+ 146: 0xafafd7,
+ 147: 0xafafff,
+ 148: 0xafd700,
+ 149: 0xafd75f,
+ 150: 0xafd787,
+ 151: 0xafd7af,
+ 152: 0xafd7d7,
+ 153: 0xafd7ff,
+ 154: 0xafff00,
+ 155: 0xafff5f,
+ 156: 0xafff87,
+ 157: 0xafffaf,
+ 158: 0xafffd7,
+ 159: 0xafffff,
+ 160: 0xd70000,
+ 161: 0xd7005f,
+ 162: 0xd70087,
+ 163: 0xd700af,
+ 164: 0xd700d7,
+ 165: 0xd700ff,
+ 166: 0xd75f00,
+ 167: 0xd75f5f,
+ 168: 0xd75f87,
+ 169: 0xd75faf,
+ 170: 0xd75fd7,
+ 171: 0xd75fff,
+ 172: 0xd78700,
+ 173: 0xd7875f,
+ 174: 0xd78787,
+ 175: 0xd787af,
+ 176: 0xd787d7,
+ 177: 0xd787ff,
+ 178: 0xd7af00,
+ 179: 0xd7af5f,
+ 180: 0xd7af87,
+ 181: 0xd7afaf,
+ 182: 0xd7afd7,
+ 183: 0xd7afff,
+ 184: 0xd7d700,
+ 185: 0xd7d75f,
+ 186: 0xd7d787,
+ 187: 0xd7d7af,
+ 188: 0xd7d7d7,
+ 189: 0xd7d7ff,
+ 190: 0xd7ff00,
+ 191: 0xd7ff5f,
+ 192: 0xd7ff87,
+ 193: 0xd7ffaf,
+ 194: 0xd7ffd7,
+ 195: 0xd7ffff,
+ 196: 0xff0000,
+ 197: 0xff005f,
+ 198: 0xff0087,
+ 199: 0xff00af,
+ 200: 0xff00d7,
+ 201: 0xff00ff,
+ 202: 0xff5f00,
+ 203: 0xff5f5f,
+ 204: 0xff5f87,
+ 205: 0xff5faf,
+ 206: 0xff5fd7,
+ 207: 0xff5fff,
+ 208: 0xff8700,
+ 209: 0xff875f,
+ 210: 0xff8787,
+ 211: 0xff87af,
+ 212: 0xff87d7,
+ 213: 0xff87ff,
+ 214: 0xffaf00,
+ 215: 0xffaf5f,
+ 216: 0xffaf87,
+ 217: 0xffafaf,
+ 218: 0xffafd7,
+ 219: 0xffafff,
+ 220: 0xffd700,
+ 221: 0xffd75f,
+ 222: 0xffd787,
+ 223: 0xffd7af,
+ 224: 0xffd7d7,
+ 225: 0xffd7ff,
+ 226: 0xffff00,
+ 227: 0xffff5f,
+ 228: 0xffff87,
+ 229: 0xffffaf,
+ 230: 0xffffd7,
+ 231: 0xffffff,
+ 232: 0x080808,
+ 233: 0x121212,
+ 234: 0x1c1c1c,
+ 235: 0x262626,
+ 236: 0x303030,
+ 237: 0x3a3a3a,
+ 238: 0x444444,
+ 239: 0x4e4e4e,
+ 240: 0x585858,
+ 241: 0x626262,
+ 242: 0x6c6c6c,
+ 243: 0x767676,
+ 244: 0x808080,
+ 245: 0x8a8a8a,
+ 246: 0x949494,
+ 247: 0x9e9e9e,
+ 248: 0xa8a8a8,
+ 249: 0xb2b2b2,
+ 250: 0xbcbcbc,
+ 251: 0xc6c6c6,
+ 252: 0xd0d0d0,
+ 253: 0xdadada,
+ 254: 0xe4e4e4,
+ 255: 0xeeeeee,
+}
+
+// `\033]0;TITLESTR\007`
+func doTitleSequence(er *bytes.Reader) error {
+ var c byte
+ var err error
+
+ c, err = er.ReadByte()
+ if err != nil {
+ return err
+ }
+ if c != '0' && c != '2' {
+ return nil
+ }
+ c, err = er.ReadByte()
+ if err != nil {
+ return err
+ }
+ if c != ';' {
+ return nil
+ }
+ title := make([]byte, 0, 80)
+ for {
+ c, err = er.ReadByte()
+ if err != nil {
+ return err
+ }
+ if c == 0x07 || c == '\n' {
+ break
+ }
+ title = append(title, c)
+ }
+ if len(title) > 0 {
+ title8, err := syscall.UTF16PtrFromString(string(title))
+ if err == nil {
+ procSetConsoleTitle.Call(uintptr(unsafe.Pointer(title8)))
+ }
+ }
+ return nil
+}
+
+// returns Atoi(s) unless s == "" in which case it returns def
+func atoiWithDefault(s string, def int) (int, error) {
+ if s == "" {
+ return def, nil
+ }
+ return strconv.Atoi(s)
+}
+
+// Write writes data on console
+func (w *Writer) Write(data []byte) (n int, err error) {
+ w.mutex.Lock()
+ defer w.mutex.Unlock()
+ var csbi consoleScreenBufferInfo
+ procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
+
+ handle := w.handle
+
+ var er *bytes.Reader
+ if w.rest.Len() > 0 {
+ var rest bytes.Buffer
+ w.rest.WriteTo(&rest)
+ w.rest.Reset()
+ rest.Write(data)
+ er = bytes.NewReader(rest.Bytes())
+ } else {
+ er = bytes.NewReader(data)
+ }
+ var plaintext bytes.Buffer
+loop:
+ for {
+ c1, err := er.ReadByte()
+ if err != nil {
+ plaintext.WriteTo(w.out)
+ break loop
+ }
+ if c1 != 0x1b {
+ plaintext.WriteByte(c1)
+ continue
+ }
+ _, err = plaintext.WriteTo(w.out)
+ if err != nil {
+ break loop
+ }
+ c2, err := er.ReadByte()
+ if err != nil {
+ break loop
+ }
+
+ switch c2 {
+ case '>':
+ continue
+ case ']':
+ w.rest.WriteByte(c1)
+ w.rest.WriteByte(c2)
+ er.WriteTo(&w.rest)
+ if bytes.IndexByte(w.rest.Bytes(), 0x07) == -1 {
+ break loop
+ }
+ er = bytes.NewReader(w.rest.Bytes()[2:])
+ err := doTitleSequence(er)
+ if err != nil {
+ break loop
+ }
+ w.rest.Reset()
+ continue
+ // https://github.com/mattn/go-colorable/issues/27
+ case '7':
+ procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
+ w.oldpos = csbi.cursorPosition
+ continue
+ case '8':
+ procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&w.oldpos)))
+ continue
+ case 0x5b:
+ // execute part after switch
+ default:
+ continue
+ }
+
+ w.rest.WriteByte(c1)
+ w.rest.WriteByte(c2)
+ er.WriteTo(&w.rest)
+
+ var buf bytes.Buffer
+ var m byte
+ for i, c := range w.rest.Bytes()[2:] {
+ if ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || c == '@' {
+ m = c
+ er = bytes.NewReader(w.rest.Bytes()[2+i+1:])
+ w.rest.Reset()
+ break
+ }
+ buf.Write([]byte(string(c)))
+ }
+ if m == 0 {
+ break loop
+ }
+
+ switch m {
+ case 'A':
+ n, err = atoiWithDefault(buf.String(), 1)
+ if err != nil {
+ continue
+ }
+ procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
+ csbi.cursorPosition.y -= short(n)
+ procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
+ case 'B':
+ n, err = atoiWithDefault(buf.String(), 1)
+ if err != nil {
+ continue
+ }
+ procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
+ csbi.cursorPosition.y += short(n)
+ procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
+ case 'C':
+ n, err = atoiWithDefault(buf.String(), 1)
+ if err != nil {
+ continue
+ }
+ procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
+ csbi.cursorPosition.x += short(n)
+ procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
+ case 'D':
+ n, err = atoiWithDefault(buf.String(), 1)
+ if err != nil {
+ continue
+ }
+ procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
+ csbi.cursorPosition.x -= short(n)
+ if csbi.cursorPosition.x < 0 {
+ csbi.cursorPosition.x = 0
+ }
+ procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
+ case 'E':
+ n, err = strconv.Atoi(buf.String())
+ if err != nil {
+ continue
+ }
+ procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
+ csbi.cursorPosition.x = 0
+ csbi.cursorPosition.y += short(n)
+ procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
+ case 'F':
+ n, err = strconv.Atoi(buf.String())
+ if err != nil {
+ continue
+ }
+ procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
+ csbi.cursorPosition.x = 0
+ csbi.cursorPosition.y -= short(n)
+ procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
+ case 'G':
+ n, err = strconv.Atoi(buf.String())
+ if err != nil {
+ continue
+ }
+ if n < 1 {
+ n = 1
+ }
+ procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
+ csbi.cursorPosition.x = short(n - 1)
+ procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
+ case 'H', 'f':
+ procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
+ if buf.Len() > 0 {
+ token := strings.Split(buf.String(), ";")
+ switch len(token) {
+ case 1:
+ n1, err := strconv.Atoi(token[0])
+ if err != nil {
+ continue
+ }
+ csbi.cursorPosition.y = short(n1 - 1)
+ case 2:
+ n1, err := strconv.Atoi(token[0])
+ if err != nil {
+ continue
+ }
+ n2, err := strconv.Atoi(token[1])
+ if err != nil {
+ continue
+ }
+ csbi.cursorPosition.x = short(n2 - 1)
+ csbi.cursorPosition.y = short(n1 - 1)
+ }
+ } else {
+ csbi.cursorPosition.y = 0
+ }
+ procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
+ case 'J':
+ n := 0
+ if buf.Len() > 0 {
+ n, err = strconv.Atoi(buf.String())
+ if err != nil {
+ continue
+ }
+ }
+ var count, written dword
+ var cursor coord
+ procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
+ switch n {
+ case 0:
+ cursor = coord{x: csbi.cursorPosition.x, y: csbi.cursorPosition.y}
+ count = dword(csbi.size.x) - dword(csbi.cursorPosition.x) + dword(csbi.size.y-csbi.cursorPosition.y)*dword(csbi.size.x)
+ case 1:
+ cursor = coord{x: csbi.window.left, y: csbi.window.top}
+ count = dword(csbi.size.x) - dword(csbi.cursorPosition.x) + dword(csbi.window.top-csbi.cursorPosition.y)*dword(csbi.size.x)
+ case 2:
+ cursor = coord{x: csbi.window.left, y: csbi.window.top}
+ count = dword(csbi.size.x) - dword(csbi.cursorPosition.x) + dword(csbi.size.y-csbi.cursorPosition.y)*dword(csbi.size.x)
+ }
+ procFillConsoleOutputCharacter.Call(uintptr(handle), uintptr(' '), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written)))
+ procFillConsoleOutputAttribute.Call(uintptr(handle), uintptr(csbi.attributes), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written)))
+ case 'K':
+ n := 0
+ if buf.Len() > 0 {
+ n, err = strconv.Atoi(buf.String())
+ if err != nil {
+ continue
+ }
+ }
+ procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
+ var cursor coord
+ var count, written dword
+ switch n {
+ case 0:
+ cursor = coord{x: csbi.cursorPosition.x, y: csbi.cursorPosition.y}
+ count = dword(csbi.size.x - csbi.cursorPosition.x)
+ case 1:
+ cursor = coord{x: csbi.window.left, y: csbi.cursorPosition.y}
+ count = dword(csbi.size.x - csbi.cursorPosition.x)
+ case 2:
+ cursor = coord{x: csbi.window.left, y: csbi.cursorPosition.y}
+ count = dword(csbi.size.x)
+ }
+ procFillConsoleOutputCharacter.Call(uintptr(handle), uintptr(' '), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written)))
+ procFillConsoleOutputAttribute.Call(uintptr(handle), uintptr(csbi.attributes), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written)))
+ case 'X':
+ n := 0
+ if buf.Len() > 0 {
+ n, err = strconv.Atoi(buf.String())
+ if err != nil {
+ continue
+ }
+ }
+ procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
+ var cursor coord
+ var written dword
+ cursor = coord{x: csbi.cursorPosition.x, y: csbi.cursorPosition.y}
+ procFillConsoleOutputCharacter.Call(uintptr(handle), uintptr(' '), uintptr(n), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written)))
+ procFillConsoleOutputAttribute.Call(uintptr(handle), uintptr(csbi.attributes), uintptr(n), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written)))
+ case 'm':
+ procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
+ attr := csbi.attributes
+ cs := buf.String()
+ if cs == "" {
+ procSetConsoleTextAttribute.Call(uintptr(handle), uintptr(w.oldattr))
+ continue
+ }
+ token := strings.Split(cs, ";")
+ for i := 0; i < len(token); i++ {
+ ns := token[i]
+ if n, err = strconv.Atoi(ns); err == nil {
+ switch {
+ case n == 0 || n == 100:
+ attr = w.oldattr
+ case n == 4:
+ attr |= commonLvbUnderscore
+ case (1 <= n && n <= 3) || n == 5:
+ attr |= foregroundIntensity
+ case n == 7 || n == 27:
+ attr =
+ (attr &^ (foregroundMask | backgroundMask)) |
+ ((attr & foregroundMask) << 4) |
+ ((attr & backgroundMask) >> 4)
+ case n == 22:
+ attr &^= foregroundIntensity
+ case n == 24:
+ attr &^= commonLvbUnderscore
+ case 30 <= n && n <= 37:
+ attr &= backgroundMask
+ if (n-30)&1 != 0 {
+ attr |= foregroundRed
+ }
+ if (n-30)&2 != 0 {
+ attr |= foregroundGreen
+ }
+ if (n-30)&4 != 0 {
+ attr |= foregroundBlue
+ }
+ case n == 38: // set foreground color.
+ if i < len(token)-2 && (token[i+1] == "5" || token[i+1] == "05") {
+ if n256, err := strconv.Atoi(token[i+2]); err == nil {
+ if n256foreAttr == nil {
+ n256setup()
+ }
+ attr &= backgroundMask
+ attr |= n256foreAttr[n256%len(n256foreAttr)]
+ i += 2
+ }
+ } else if len(token) == 5 && token[i+1] == "2" {
+ var r, g, b int
+ r, _ = strconv.Atoi(token[i+2])
+ g, _ = strconv.Atoi(token[i+3])
+ b, _ = strconv.Atoi(token[i+4])
+ i += 4
+ if r > 127 {
+ attr |= foregroundRed
+ }
+ if g > 127 {
+ attr |= foregroundGreen
+ }
+ if b > 127 {
+ attr |= foregroundBlue
+ }
+ } else {
+ attr = attr & (w.oldattr & backgroundMask)
+ }
+ case n == 39: // reset foreground color.
+ attr &= backgroundMask
+ attr |= w.oldattr & foregroundMask
+ case 40 <= n && n <= 47:
+ attr &= foregroundMask
+ if (n-40)&1 != 0 {
+ attr |= backgroundRed
+ }
+ if (n-40)&2 != 0 {
+ attr |= backgroundGreen
+ }
+ if (n-40)&4 != 0 {
+ attr |= backgroundBlue
+ }
+ case n == 48: // set background color.
+ if i < len(token)-2 && token[i+1] == "5" {
+ if n256, err := strconv.Atoi(token[i+2]); err == nil {
+ if n256backAttr == nil {
+ n256setup()
+ }
+ attr &= foregroundMask
+ attr |= n256backAttr[n256%len(n256backAttr)]
+ i += 2
+ }
+ } else if len(token) == 5 && token[i+1] == "2" {
+ var r, g, b int
+ r, _ = strconv.Atoi(token[i+2])
+ g, _ = strconv.Atoi(token[i+3])
+ b, _ = strconv.Atoi(token[i+4])
+ i += 4
+ if r > 127 {
+ attr |= backgroundRed
+ }
+ if g > 127 {
+ attr |= backgroundGreen
+ }
+ if b > 127 {
+ attr |= backgroundBlue
+ }
+ } else {
+ attr = attr & (w.oldattr & foregroundMask)
+ }
+ case n == 49: // reset foreground color.
+ attr &= foregroundMask
+ attr |= w.oldattr & backgroundMask
+ case 90 <= n && n <= 97:
+ attr = (attr & backgroundMask)
+ attr |= foregroundIntensity
+ if (n-90)&1 != 0 {
+ attr |= foregroundRed
+ }
+ if (n-90)&2 != 0 {
+ attr |= foregroundGreen
+ }
+ if (n-90)&4 != 0 {
+ attr |= foregroundBlue
+ }
+ case 100 <= n && n <= 107:
+ attr = (attr & foregroundMask)
+ attr |= backgroundIntensity
+ if (n-100)&1 != 0 {
+ attr |= backgroundRed
+ }
+ if (n-100)&2 != 0 {
+ attr |= backgroundGreen
+ }
+ if (n-100)&4 != 0 {
+ attr |= backgroundBlue
+ }
+ }
+ procSetConsoleTextAttribute.Call(uintptr(handle), uintptr(attr))
+ }
+ }
+ case 'h':
+ var ci consoleCursorInfo
+ cs := buf.String()
+ if cs == "5>" {
+ procGetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&ci)))
+ ci.visible = 0
+ procSetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&ci)))
+ } else if cs == "?25" {
+ procGetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&ci)))
+ ci.visible = 1
+ procSetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&ci)))
+ } else if cs == "?1049" {
+ if w.althandle == 0 {
+ h, _, _ := procCreateConsoleScreenBuffer.Call(uintptr(genericRead|genericWrite), 0, 0, uintptr(consoleTextmodeBuffer), 0, 0)
+ w.althandle = syscall.Handle(h)
+ if w.althandle != 0 {
+ handle = w.althandle
+ }
+ }
+ }
+ case 'l':
+ var ci consoleCursorInfo
+ cs := buf.String()
+ if cs == "5>" {
+ procGetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&ci)))
+ ci.visible = 1
+ procSetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&ci)))
+ } else if cs == "?25" {
+ procGetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&ci)))
+ ci.visible = 0
+ procSetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&ci)))
+ } else if cs == "?1049" {
+ if w.althandle != 0 {
+ syscall.CloseHandle(w.althandle)
+ w.althandle = 0
+ handle = w.handle
+ }
+ }
+ case 's':
+ procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
+ w.oldpos = csbi.cursorPosition
+ case 'u':
+ procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&w.oldpos)))
+ }
+ }
+
+ return len(data), nil
+}
+
+type consoleColor struct {
+ rgb int
+ red bool
+ green bool
+ blue bool
+ intensity bool
+}
+
+func (c consoleColor) foregroundAttr() (attr word) {
+ if c.red {
+ attr |= foregroundRed
+ }
+ if c.green {
+ attr |= foregroundGreen
+ }
+ if c.blue {
+ attr |= foregroundBlue
+ }
+ if c.intensity {
+ attr |= foregroundIntensity
+ }
+ return
+}
+
+func (c consoleColor) backgroundAttr() (attr word) {
+ if c.red {
+ attr |= backgroundRed
+ }
+ if c.green {
+ attr |= backgroundGreen
+ }
+ if c.blue {
+ attr |= backgroundBlue
+ }
+ if c.intensity {
+ attr |= backgroundIntensity
+ }
+ return
+}
+
+var color16 = []consoleColor{
+ {0x000000, false, false, false, false},
+ {0x000080, false, false, true, false},
+ {0x008000, false, true, false, false},
+ {0x008080, false, true, true, false},
+ {0x800000, true, false, false, false},
+ {0x800080, true, false, true, false},
+ {0x808000, true, true, false, false},
+ {0xc0c0c0, true, true, true, false},
+ {0x808080, false, false, false, true},
+ {0x0000ff, false, false, true, true},
+ {0x00ff00, false, true, false, true},
+ {0x00ffff, false, true, true, true},
+ {0xff0000, true, false, false, true},
+ {0xff00ff, true, false, true, true},
+ {0xffff00, true, true, false, true},
+ {0xffffff, true, true, true, true},
+}
+
+type hsv struct {
+ h, s, v float32
+}
+
+func (a hsv) dist(b hsv) float32 {
+ dh := a.h - b.h
+ switch {
+ case dh > 0.5:
+ dh = 1 - dh
+ case dh < -0.5:
+ dh = -1 - dh
+ }
+ ds := a.s - b.s
+ dv := a.v - b.v
+ return float32(math.Sqrt(float64(dh*dh + ds*ds + dv*dv)))
+}
+
+func toHSV(rgb int) hsv {
+ r, g, b := float32((rgb&0xFF0000)>>16)/256.0,
+ float32((rgb&0x00FF00)>>8)/256.0,
+ float32(rgb&0x0000FF)/256.0
+ min, max := minmax3f(r, g, b)
+ h := max - min
+ if h > 0 {
+ if max == r {
+ h = (g - b) / h
+ if h < 0 {
+ h += 6
+ }
+ } else if max == g {
+ h = 2 + (b-r)/h
+ } else {
+ h = 4 + (r-g)/h
+ }
+ }
+ h /= 6.0
+ s := max - min
+ if max != 0 {
+ s /= max
+ }
+ v := max
+ return hsv{h: h, s: s, v: v}
+}
+
+type hsvTable []hsv
+
+func toHSVTable(rgbTable []consoleColor) hsvTable {
+ t := make(hsvTable, len(rgbTable))
+ for i, c := range rgbTable {
+ t[i] = toHSV(c.rgb)
+ }
+ return t
+}
+
+func (t hsvTable) find(rgb int) consoleColor {
+ hsv := toHSV(rgb)
+ n := 7
+ l := float32(5.0)
+ for i, p := range t {
+ d := hsv.dist(p)
+ if d < l {
+ l, n = d, i
+ }
+ }
+ return color16[n]
+}
+
+func minmax3f(a, b, c float32) (min, max float32) {
+ if a < b {
+ if b < c {
+ return a, c
+ } else if a < c {
+ return a, b
+ } else {
+ return c, b
+ }
+ } else {
+ if a < c {
+ return b, c
+ } else if b < c {
+ return b, a
+ } else {
+ return c, a
+ }
+ }
+}
+
+var n256foreAttr []word
+var n256backAttr []word
+
+func n256setup() {
+ n256foreAttr = make([]word, 256)
+ n256backAttr = make([]word, 256)
+ t := toHSVTable(color16)
+ for i, rgb := range color256 {
+ c := t.find(rgb)
+ n256foreAttr[i] = c.foregroundAttr()
+ n256backAttr[i] = c.backgroundAttr()
+ }
+}
+
+// EnableColorsStdout enable colors if possible.
+func EnableColorsStdout(enabled *bool) func() {
+ var mode uint32
+ h := os.Stdout.Fd()
+ if r, _, _ := procGetConsoleMode.Call(h, uintptr(unsafe.Pointer(&mode))); r != 0 {
+ if r, _, _ = procSetConsoleMode.Call(h, uintptr(mode|cENABLE_VIRTUAL_TERMINAL_PROCESSING)); r != 0 {
+ if enabled != nil {
+ *enabled = true
+ }
+ return func() {
+ procSetConsoleMode.Call(h, uintptr(mode))
+ }
+ }
+ }
+ if enabled != nil {
+ *enabled = true
+ }
+ return func() {}
+}
diff --git a/vendor/github.com/mattn/go-colorable/go.test.sh b/vendor/github.com/mattn/go-colorable/go.test.sh
new file mode 100644
index 0000000..012162b
--- /dev/null
+++ b/vendor/github.com/mattn/go-colorable/go.test.sh
@@ -0,0 +1,12 @@
+#!/usr/bin/env bash
+
+set -e
+echo "" > coverage.txt
+
+for d in $(go list ./... | grep -v vendor); do
+ go test -race -coverprofile=profile.out -covermode=atomic "$d"
+ if [ -f profile.out ]; then
+ cat profile.out >> coverage.txt
+ rm profile.out
+ fi
+done
diff --git a/vendor/github.com/mattn/go-colorable/noncolorable.go b/vendor/github.com/mattn/go-colorable/noncolorable.go
new file mode 100644
index 0000000..05d6f74
--- /dev/null
+++ b/vendor/github.com/mattn/go-colorable/noncolorable.go
@@ -0,0 +1,57 @@
+package colorable
+
+import (
+ "bytes"
+ "io"
+)
+
+// NonColorable holds writer but removes escape sequence.
+type NonColorable struct {
+ out io.Writer
+}
+
+// NewNonColorable returns new instance of Writer which removes escape sequence from Writer.
+func NewNonColorable(w io.Writer) io.Writer {
+ return &NonColorable{out: w}
+}
+
+// Write writes data on console
+func (w *NonColorable) Write(data []byte) (n int, err error) {
+ er := bytes.NewReader(data)
+ var plaintext bytes.Buffer
+loop:
+ for {
+ c1, err := er.ReadByte()
+ if err != nil {
+ plaintext.WriteTo(w.out)
+ break loop
+ }
+ if c1 != 0x1b {
+ plaintext.WriteByte(c1)
+ continue
+ }
+ _, err = plaintext.WriteTo(w.out)
+ if err != nil {
+ break loop
+ }
+ c2, err := er.ReadByte()
+ if err != nil {
+ break loop
+ }
+ if c2 != 0x5b {
+ continue
+ }
+
+ for {
+ c, err := er.ReadByte()
+ if err != nil {
+ break loop
+ }
+ if ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || c == '@' {
+ break
+ }
+ }
+ }
+
+ return len(data), nil
+}
diff --git a/vendor/github.com/mattn/go-isatty/LICENSE b/vendor/github.com/mattn/go-isatty/LICENSE
new file mode 100644
index 0000000..65dc692
--- /dev/null
+++ b/vendor/github.com/mattn/go-isatty/LICENSE
@@ -0,0 +1,9 @@
+Copyright (c) Yasuhiro MATSUMOTO
+
+MIT License (Expat)
+
+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/mattn/go-isatty/README.md b/vendor/github.com/mattn/go-isatty/README.md
new file mode 100644
index 0000000..3841835
--- /dev/null
+++ b/vendor/github.com/mattn/go-isatty/README.md
@@ -0,0 +1,50 @@
+# go-isatty
+
+[![Godoc Reference](https://godoc.org/github.com/mattn/go-isatty?status.svg)](http://godoc.org/github.com/mattn/go-isatty)
+[![Codecov](https://codecov.io/gh/mattn/go-isatty/branch/master/graph/badge.svg)](https://codecov.io/gh/mattn/go-isatty)
+[![Coverage Status](https://coveralls.io/repos/github/mattn/go-isatty/badge.svg?branch=master)](https://coveralls.io/github/mattn/go-isatty?branch=master)
+[![Go Report Card](https://goreportcard.com/badge/mattn/go-isatty)](https://goreportcard.com/report/mattn/go-isatty)
+
+isatty for golang
+
+## Usage
+
+```go
+package main
+
+import (
+ "fmt"
+ "github.com/mattn/go-isatty"
+ "os"
+)
+
+func main() {
+ if isatty.IsTerminal(os.Stdout.Fd()) {
+ fmt.Println("Is Terminal")
+ } else if isatty.IsCygwinTerminal(os.Stdout.Fd()) {
+ fmt.Println("Is Cygwin/MSYS2 Terminal")
+ } else {
+ fmt.Println("Is Not Terminal")
+ }
+}
+```
+
+## Installation
+
+```
+$ go get github.com/mattn/go-isatty
+```
+
+## License
+
+MIT
+
+## Author
+
+Yasuhiro Matsumoto (a.k.a mattn)
+
+## Thanks
+
+* k-takata: base idea for IsCygwinTerminal
+
+ https://github.com/k-takata/go-iscygpty
diff --git a/vendor/github.com/mattn/go-isatty/doc.go b/vendor/github.com/mattn/go-isatty/doc.go
new file mode 100644
index 0000000..17d4f90
--- /dev/null
+++ b/vendor/github.com/mattn/go-isatty/doc.go
@@ -0,0 +1,2 @@
+// Package isatty implements interface to isatty
+package isatty
diff --git a/vendor/github.com/mattn/go-isatty/go.test.sh b/vendor/github.com/mattn/go-isatty/go.test.sh
new file mode 100644
index 0000000..012162b
--- /dev/null
+++ b/vendor/github.com/mattn/go-isatty/go.test.sh
@@ -0,0 +1,12 @@
+#!/usr/bin/env bash
+
+set -e
+echo "" > coverage.txt
+
+for d in $(go list ./... | grep -v vendor); do
+ go test -race -coverprofile=profile.out -covermode=atomic "$d"
+ if [ -f profile.out ]; then
+ cat profile.out >> coverage.txt
+ rm profile.out
+ fi
+done
diff --git a/vendor/github.com/mattn/go-isatty/isatty_bsd.go b/vendor/github.com/mattn/go-isatty/isatty_bsd.go
new file mode 100644
index 0000000..d569c0c
--- /dev/null
+++ b/vendor/github.com/mattn/go-isatty/isatty_bsd.go
@@ -0,0 +1,19 @@
+//go:build (darwin || freebsd || openbsd || netbsd || dragonfly || hurd) && !appengine
+// +build darwin freebsd openbsd netbsd dragonfly hurd
+// +build !appengine
+
+package isatty
+
+import "golang.org/x/sys/unix"
+
+// IsTerminal return true if the file descriptor is terminal.
+func IsTerminal(fd uintptr) bool {
+ _, err := unix.IoctlGetTermios(int(fd), unix.TIOCGETA)
+ return err == nil
+}
+
+// IsCygwinTerminal return true if the file descriptor is a cygwin or msys2
+// terminal. This is also always false on this environment.
+func IsCygwinTerminal(fd uintptr) bool {
+ return false
+}
diff --git a/vendor/github.com/mattn/go-isatty/isatty_others.go b/vendor/github.com/mattn/go-isatty/isatty_others.go
new file mode 100644
index 0000000..3150322
--- /dev/null
+++ b/vendor/github.com/mattn/go-isatty/isatty_others.go
@@ -0,0 +1,16 @@
+//go:build appengine || js || nacl || wasm
+// +build appengine js nacl wasm
+
+package isatty
+
+// IsTerminal returns true if the file descriptor is terminal which
+// is always false on js and appengine classic which is a sandboxed PaaS.
+func IsTerminal(fd uintptr) bool {
+ return false
+}
+
+// IsCygwinTerminal() return true if the file descriptor is a cygwin or msys2
+// terminal. This is also always false on this environment.
+func IsCygwinTerminal(fd uintptr) bool {
+ return false
+}
diff --git a/vendor/github.com/mattn/go-isatty/isatty_plan9.go b/vendor/github.com/mattn/go-isatty/isatty_plan9.go
new file mode 100644
index 0000000..bae7f9b
--- /dev/null
+++ b/vendor/github.com/mattn/go-isatty/isatty_plan9.go
@@ -0,0 +1,23 @@
+//go:build plan9
+// +build plan9
+
+package isatty
+
+import (
+ "syscall"
+)
+
+// IsTerminal returns true if the given file descriptor is a terminal.
+func IsTerminal(fd uintptr) bool {
+ path, err := syscall.Fd2path(int(fd))
+ if err != nil {
+ return false
+ }
+ return path == "/dev/cons" || path == "/mnt/term/dev/cons"
+}
+
+// IsCygwinTerminal return true if the file descriptor is a cygwin or msys2
+// terminal. This is also always false on this environment.
+func IsCygwinTerminal(fd uintptr) bool {
+ return false
+}
diff --git a/vendor/github.com/mattn/go-isatty/isatty_solaris.go b/vendor/github.com/mattn/go-isatty/isatty_solaris.go
new file mode 100644
index 0000000..0c3acf2
--- /dev/null
+++ b/vendor/github.com/mattn/go-isatty/isatty_solaris.go
@@ -0,0 +1,21 @@
+//go:build solaris && !appengine
+// +build solaris,!appengine
+
+package isatty
+
+import (
+ "golang.org/x/sys/unix"
+)
+
+// IsTerminal returns true if the given file descriptor is a terminal.
+// see: https://src.illumos.org/source/xref/illumos-gate/usr/src/lib/libc/port/gen/isatty.c
+func IsTerminal(fd uintptr) bool {
+ _, err := unix.IoctlGetTermio(int(fd), unix.TCGETA)
+ return err == nil
+}
+
+// IsCygwinTerminal return true if the file descriptor is a cygwin or msys2
+// terminal. This is also always false on this environment.
+func IsCygwinTerminal(fd uintptr) bool {
+ return false
+}
diff --git a/vendor/github.com/mattn/go-isatty/isatty_tcgets.go b/vendor/github.com/mattn/go-isatty/isatty_tcgets.go
new file mode 100644
index 0000000..6778765
--- /dev/null
+++ b/vendor/github.com/mattn/go-isatty/isatty_tcgets.go
@@ -0,0 +1,19 @@
+//go:build (linux || aix || zos) && !appengine
+// +build linux aix zos
+// +build !appengine
+
+package isatty
+
+import "golang.org/x/sys/unix"
+
+// IsTerminal return true if the file descriptor is terminal.
+func IsTerminal(fd uintptr) bool {
+ _, err := unix.IoctlGetTermios(int(fd), unix.TCGETS)
+ return err == nil
+}
+
+// IsCygwinTerminal return true if the file descriptor is a cygwin or msys2
+// terminal. This is also always false on this environment.
+func IsCygwinTerminal(fd uintptr) bool {
+ return false
+}
diff --git a/vendor/github.com/mattn/go-isatty/isatty_windows.go b/vendor/github.com/mattn/go-isatty/isatty_windows.go
new file mode 100644
index 0000000..8e3c991
--- /dev/null
+++ b/vendor/github.com/mattn/go-isatty/isatty_windows.go
@@ -0,0 +1,125 @@
+//go:build windows && !appengine
+// +build windows,!appengine
+
+package isatty
+
+import (
+ "errors"
+ "strings"
+ "syscall"
+ "unicode/utf16"
+ "unsafe"
+)
+
+const (
+ objectNameInfo uintptr = 1
+ fileNameInfo = 2
+ fileTypePipe = 3
+)
+
+var (
+ kernel32 = syscall.NewLazyDLL("kernel32.dll")
+ ntdll = syscall.NewLazyDLL("ntdll.dll")
+ procGetConsoleMode = kernel32.NewProc("GetConsoleMode")
+ procGetFileInformationByHandleEx = kernel32.NewProc("GetFileInformationByHandleEx")
+ procGetFileType = kernel32.NewProc("GetFileType")
+ procNtQueryObject = ntdll.NewProc("NtQueryObject")
+)
+
+func init() {
+ // Check if GetFileInformationByHandleEx is available.
+ if procGetFileInformationByHandleEx.Find() != nil {
+ procGetFileInformationByHandleEx = nil
+ }
+}
+
+// IsTerminal return true if the file descriptor is terminal.
+func IsTerminal(fd uintptr) bool {
+ var st uint32
+ r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, fd, uintptr(unsafe.Pointer(&st)), 0)
+ return r != 0 && e == 0
+}
+
+// Check pipe name is used for cygwin/msys2 pty.
+// Cygwin/MSYS2 PTY has a name like:
+// \{cygwin,msys}-XXXXXXXXXXXXXXXX-ptyN-{from,to}-master
+func isCygwinPipeName(name string) bool {
+ token := strings.Split(name, "-")
+ if len(token) < 5 {
+ return false
+ }
+
+ if token[0] != `\msys` &&
+ token[0] != `\cygwin` &&
+ token[0] != `\Device\NamedPipe\msys` &&
+ token[0] != `\Device\NamedPipe\cygwin` {
+ return false
+ }
+
+ if token[1] == "" {
+ return false
+ }
+
+ if !strings.HasPrefix(token[2], "pty") {
+ return false
+ }
+
+ if token[3] != `from` && token[3] != `to` {
+ return false
+ }
+
+ if token[4] != "master" {
+ return false
+ }
+
+ return true
+}
+
+// getFileNameByHandle use the undocomented ntdll NtQueryObject to get file full name from file handler
+// since GetFileInformationByHandleEx is not available under windows Vista and still some old fashion
+// guys are using Windows XP, this is a workaround for those guys, it will also work on system from
+// Windows vista to 10
+// see https://stackoverflow.com/a/18792477 for details
+func getFileNameByHandle(fd uintptr) (string, error) {
+ if procNtQueryObject == nil {
+ return "", errors.New("ntdll.dll: NtQueryObject not supported")
+ }
+
+ var buf [4 + syscall.MAX_PATH]uint16
+ var result int
+ r, _, e := syscall.Syscall6(procNtQueryObject.Addr(), 5,
+ fd, objectNameInfo, uintptr(unsafe.Pointer(&buf)), uintptr(2*len(buf)), uintptr(unsafe.Pointer(&result)), 0)
+ if r != 0 {
+ return "", e
+ }
+ return string(utf16.Decode(buf[4 : 4+buf[0]/2])), nil
+}
+
+// IsCygwinTerminal() return true if the file descriptor is a cygwin or msys2
+// terminal.
+func IsCygwinTerminal(fd uintptr) bool {
+ if procGetFileInformationByHandleEx == nil {
+ name, err := getFileNameByHandle(fd)
+ if err != nil {
+ return false
+ }
+ return isCygwinPipeName(name)
+ }
+
+ // Cygwin/msys's pty is a pipe.
+ ft, _, e := syscall.Syscall(procGetFileType.Addr(), 1, fd, 0, 0)
+ if ft != fileTypePipe || e != 0 {
+ return false
+ }
+
+ var buf [2 + syscall.MAX_PATH]uint16
+ r, _, e := syscall.Syscall6(procGetFileInformationByHandleEx.Addr(),
+ 4, fd, fileNameInfo, uintptr(unsafe.Pointer(&buf)),
+ uintptr(len(buf)*2), 0, 0)
+ if r == 0 || e != 0 {
+ return false
+ }
+
+ l := *(*uint32)(unsafe.Pointer(&buf))
+ return isCygwinPipeName(string(utf16.Decode(buf[2 : 2+l/2])))
+}
diff --git a/vendor/github.com/nbd-wtf/go-nostr/.gitignore b/vendor/github.com/nbd-wtf/go-nostr/.gitignore
new file mode 100644
index 0000000..6c36ead
--- /dev/null
+++ b/vendor/github.com/nbd-wtf/go-nostr/.gitignore
@@ -0,0 +1 @@
+go-nostr
diff --git a/vendor/github.com/nbd-wtf/go-nostr/LICENSE.md b/vendor/github.com/nbd-wtf/go-nostr/LICENSE.md
new file mode 100644
index 0000000..ccd11e0
--- /dev/null
+++ b/vendor/github.com/nbd-wtf/go-nostr/LICENSE.md
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2022 nbd
+
+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/nbd-wtf/go-nostr/Makefile b/vendor/github.com/nbd-wtf/go-nostr/Makefile
new file mode 100644
index 0000000..d4f860b
--- /dev/null
+++ b/vendor/github.com/nbd-wtf/go-nostr/Makefile
@@ -0,0 +1,8 @@
+### Tools needed for development
+devtools:
+ @echo "Installing devtools"
+ go install mvdan.cc/gofumpt@latest
+
+### Formatting, linting, and vetting
+fmt:
+ gofumpt -l -w .
diff --git a/vendor/github.com/nbd-wtf/go-nostr/README.md b/vendor/github.com/nbd-wtf/go-nostr/README.md
new file mode 100644
index 0000000..8335220
--- /dev/null
+++ b/vendor/github.com/nbd-wtf/go-nostr/README.md
@@ -0,0 +1,137 @@
+[![Run Tests](https://github.com/nbd-wtf/go-nostr/actions/workflows/test.yml/badge.svg)](https://github.com/nbd-wtf/go-nostr/actions/workflows/test.yml)
+[![Go Reference](https://pkg.go.dev/badge/github.com/nbd-wtf/go-nostr.svg)](https://pkg.go.dev/github.com/nbd-wtf/go-nostr)
+[![Go Report Card](https://goreportcard.com/badge/github.com/nbd-wtf/go-nostr)](https://goreportcard.com/report/github.com/nbd-wtf/go-nostr)
+
+
+
+go-nostr
+========
+
+A set of useful things for [Nostr Protocol](https://github.com/nostr-protocol/nostr) implementations.
+
+```bash
+go get github.com/nbd-wtf/go-nostr
+```
+
+### Generating a key
+
+``` go
+package main
+
+import (
+ "fmt"
+
+ "github.com/nbd-wtf/go-nostr"
+ "github.com/nbd-wtf/go-nostr/nip19"
+)
+
+func main() {
+ sk := nostr.GeneratePrivateKey()
+ pk, _ := nostr.GetPublicKey(sk)
+ nsec, _ := nip19.EncodePrivateKey(sk)
+ npub, _ := nip19.EncodePublicKey(pk)
+
+ fmt.Println("sk:", sk)
+ fmt.Println("pk:", pk)
+ fmt.Println(nsec)
+ fmt.Println(npub)
+}
+```
+
+### Subscribing to a single relay
+
+``` go
+ctx := context.Background()
+relay, err := nostr.RelayConnect(ctx, "wss://relay.stoner.com")
+if err != nil {
+ panic(err)
+}
+
+npub := "npub1422a7ws4yul24p0pf7cacn7cghqkutdnm35z075vy68ggqpqjcyswn8ekc"
+
+var filters nostr.Filters
+if _, v, err := nip19.Decode(npub); err == nil {
+ pub := v.(string)
+ filters = []nostr.Filter{{
+ Kinds: []int{nostr.KindTextNote},
+ Authors: []string{pub},
+ Limit: 1,
+ }}
+} else {
+ panic(err)
+}
+
+ctx, cancel := context.WithTimeout(ctx, 3*time.Second)
+defer cancel()
+
+sub, err := relay.Subscribe(ctx, filters)
+if err != nil {
+ panic(err)
+}
+
+for ev := range sub.Events {
+ // handle returned event.
+ // channel will stay open until the ctx is cancelled (in this case, context timeout)
+ fmt.Println(ev.ID)
+}
+```
+
+### Publishing to two relays
+
+``` go
+sk := nostr.GeneratePrivateKey()
+pub, _ := nostr.GetPublicKey(sk)
+
+ev := nostr.Event{
+ PubKey: pub,
+ CreatedAt: nostr.Now(),
+ Kind: nostr.KindTextNote,
+ Tags: nil,
+ Content: "Hello World!",
+}
+
+// calling Sign sets the event ID field and the event Sig field
+ev.Sign(sk)
+
+// publish the event to two relays
+ctx := context.Background()
+for _, url := range []string{"wss://relay.stoner.com", "wss://nostr-pub.wellorder.net"} {
+ relay, err := nostr.RelayConnect(ctx, url)
+ if err != nil {
+ fmt.Println(err)
+ continue
+ }
+ if err := relay.Publish(ctx, ev); err != nil {
+ fmt.Println(err)
+ continue
+ }
+
+ fmt.Printf("published to %s\n", url)
+}
+```
+
+### Logging
+
+To get more logs from the interaction with relays printed to STDOUT you can compile or run your program with `-tags debug`.
+
+To remove the info logs completely, replace `nostr.InfoLogger` with something that prints nothing, like
+
+``` go
+nostr.InfoLogger = log.New(io.Discard, "", 0)
+```
+
+### Example script
+
+```
+go run example/example.go
+```
+
+## Warning: risk of goroutine bloat (if used incorrectly)
+
+Remember to cancel subscriptions, either by calling `.Unsub()` on them or ensuring their `context.Context` will be canceled at some point.
+If you don't do that they will keep creating a new goroutine for every new event that arrives and if you have stopped listening on the
+`sub.Events` channel that will cause chaos and doom in your program.
+
+## Contributing to this repository
+
+Use NIP-34 to send your patches to `naddr1qqyxwmeddehhxarjqy28wumn8ghj7un9d3shjtnyv9kh2uewd9hsz9nhwden5te0wfjkccte9ehx7um5wghxyctwvsq3vamnwvaz7tmjv4kxz7fwwpexjmtpdshxuet5qgsrhuxx8l9ex335q7he0f09aej04zpazpl0ne2cgukyawd24mayt8grqsqqqaueuwmljc`.
diff --git a/vendor/github.com/nbd-wtf/go-nostr/connection.go b/vendor/github.com/nbd-wtf/go-nostr/connection.go
new file mode 100644
index 0000000..da1161d
--- /dev/null
+++ b/vendor/github.com/nbd-wtf/go-nostr/connection.go
@@ -0,0 +1,181 @@
+package nostr
+
+import (
+ "bytes"
+ "compress/flate"
+ "context"
+ "crypto/tls"
+ "errors"
+ "fmt"
+ "io"
+ "net"
+ "net/http"
+
+ "github.com/gobwas/httphead"
+ "github.com/gobwas/ws"
+ "github.com/gobwas/ws/wsflate"
+ "github.com/gobwas/ws/wsutil"
+)
+
+type Connection struct {
+ conn net.Conn
+ enableCompression bool
+ controlHandler wsutil.FrameHandlerFunc
+ flateReader *wsflate.Reader
+ reader *wsutil.Reader
+ flateWriter *wsflate.Writer
+ writer *wsutil.Writer
+ msgStateR *wsflate.MessageState
+ msgStateW *wsflate.MessageState
+}
+
+func NewConnection(ctx context.Context, url string, requestHeader http.Header, tlsConfig *tls.Config) (*Connection, error) {
+ dialer := ws.Dialer{
+ Header: ws.HandshakeHeaderHTTP(requestHeader),
+ Extensions: []httphead.Option{
+ wsflate.DefaultParameters.Option(),
+ },
+ TLSConfig: tlsConfig,
+ }
+ conn, _, hs, err := dialer.Dial(ctx, url)
+ if err != nil {
+ return nil, fmt.Errorf("failed to dial: %w", err)
+ }
+
+ enableCompression := false
+ state := ws.StateClientSide
+ for _, extension := range hs.Extensions {
+ if string(extension.Name) == wsflate.ExtensionName {
+ enableCompression = true
+ state |= ws.StateExtended
+ break
+ }
+ }
+
+ // reader
+ var flateReader *wsflate.Reader
+ var msgStateR wsflate.MessageState
+ if enableCompression {
+ msgStateR.SetCompressed(true)
+
+ flateReader = wsflate.NewReader(nil, func(r io.Reader) wsflate.Decompressor {
+ return flate.NewReader(r)
+ })
+ }
+
+ controlHandler := wsutil.ControlFrameHandler(conn, ws.StateClientSide)
+ reader := &wsutil.Reader{
+ Source: conn,
+ State: state,
+ OnIntermediate: controlHandler,
+ CheckUTF8: false,
+ Extensions: []wsutil.RecvExtension{
+ &msgStateR,
+ },
+ }
+
+ // writer
+ var flateWriter *wsflate.Writer
+ var msgStateW wsflate.MessageState
+ if enableCompression {
+ msgStateW.SetCompressed(true)
+
+ flateWriter = wsflate.NewWriter(nil, func(w io.Writer) wsflate.Compressor {
+ fw, err := flate.NewWriter(w, 4)
+ if err != nil {
+ InfoLogger.Printf("Failed to create flate writer: %v", err)
+ }
+ return fw
+ })
+ }
+
+ writer := wsutil.NewWriter(conn, state, ws.OpText)
+ writer.SetExtensions(&msgStateW)
+
+ return &Connection{
+ conn: conn,
+ enableCompression: enableCompression,
+ controlHandler: controlHandler,
+ flateReader: flateReader,
+ reader: reader,
+ msgStateR: &msgStateR,
+ flateWriter: flateWriter,
+ writer: writer,
+ msgStateW: &msgStateW,
+ }, nil
+}
+
+func (c *Connection) WriteMessage(ctx context.Context, data []byte) error {
+ select {
+ case <-ctx.Done():
+ return errors.New("context canceled")
+ default:
+ }
+
+ if c.msgStateW.IsCompressed() && c.enableCompression {
+ c.flateWriter.Reset(c.writer)
+ if _, err := io.Copy(c.flateWriter, bytes.NewReader(data)); err != nil {
+ return fmt.Errorf("failed to write message: %w", err)
+ }
+
+ if err := c.flateWriter.Close(); err != nil {
+ return fmt.Errorf("failed to close flate writer: %w", err)
+ }
+ } else {
+ if _, err := io.Copy(c.writer, bytes.NewReader(data)); err != nil {
+ return fmt.Errorf("failed to write message: %w", err)
+ }
+ }
+
+ if err := c.writer.Flush(); err != nil {
+ return fmt.Errorf("failed to flush writer: %w", err)
+ }
+
+ return nil
+}
+
+func (c *Connection) ReadMessage(ctx context.Context, buf io.Writer) error {
+ for {
+ select {
+ case <-ctx.Done():
+ return errors.New("context canceled")
+ default:
+ }
+
+ h, err := c.reader.NextFrame()
+ if err != nil {
+ c.conn.Close()
+ return fmt.Errorf("failed to advance frame: %w", err)
+ }
+
+ if h.OpCode.IsControl() {
+ if err := c.controlHandler(h, c.reader); err != nil {
+ return fmt.Errorf("failed to handle control frame: %w", err)
+ }
+ } else if h.OpCode == ws.OpBinary ||
+ h.OpCode == ws.OpText {
+ break
+ }
+
+ if err := c.reader.Discard(); err != nil {
+ return fmt.Errorf("failed to discard: %w", err)
+ }
+ }
+
+ if c.msgStateR.IsCompressed() && c.enableCompression {
+ c.flateReader.Reset(c.reader)
+ if _, err := io.Copy(buf, c.flateReader); err != nil {
+ return fmt.Errorf("failed to read message: %w", err)
+ }
+ } else {
+ if _, err := io.Copy(buf, c.reader); err != nil {
+ return fmt.Errorf("failed to read message: %w", err)
+ }
+ }
+
+ return nil
+}
+
+func (c *Connection) Close() error {
+ return c.conn.Close()
+}
diff --git a/vendor/github.com/nbd-wtf/go-nostr/envelopes.go b/vendor/github.com/nbd-wtf/go-nostr/envelopes.go
new file mode 100644
index 0000000..8b2d442
--- /dev/null
+++ b/vendor/github.com/nbd-wtf/go-nostr/envelopes.go
@@ -0,0 +1,395 @@
+package nostr
+
+import (
+ "bytes"
+ "encoding/json"
+ "fmt"
+ "strconv"
+
+ "github.com/mailru/easyjson"
+ jwriter "github.com/mailru/easyjson/jwriter"
+ "github.com/tidwall/gjson"
+)
+
+func ParseMessage(message []byte) Envelope {
+ firstComma := bytes.Index(message, []byte{','})
+ if firstComma == -1 {
+ return nil
+ }
+ label := message[0:firstComma]
+
+ var v Envelope
+ switch {
+ case bytes.Contains(label, []byte("EVENT")):
+ v = &EventEnvelope{}
+ case bytes.Contains(label, []byte("REQ")):
+ v = &ReqEnvelope{}
+ case bytes.Contains(label, []byte("COUNT")):
+ v = &CountEnvelope{}
+ case bytes.Contains(label, []byte("NOTICE")):
+ x := NoticeEnvelope("")
+ v = &x
+ case bytes.Contains(label, []byte("EOSE")):
+ x := EOSEEnvelope("")
+ v = &x
+ case bytes.Contains(label, []byte("OK")):
+ v = &OKEnvelope{}
+ case bytes.Contains(label, []byte("AUTH")):
+ v = &AuthEnvelope{}
+ case bytes.Contains(label, []byte("CLOSED")):
+ v = &ClosedEnvelope{}
+ case bytes.Contains(label, []byte("CLOSE")):
+ x := CloseEnvelope("")
+ v = &x
+ default:
+ return nil
+ }
+
+ if err := v.UnmarshalJSON(message); err != nil {
+ return nil
+ }
+ return v
+}
+
+type Envelope interface {
+ Label() string
+ UnmarshalJSON([]byte) error
+ MarshalJSON() ([]byte, error)
+ String() string
+}
+
+var (
+ _ Envelope = (*EventEnvelope)(nil)
+ _ Envelope = (*ReqEnvelope)(nil)
+ _ Envelope = (*CountEnvelope)(nil)
+ _ Envelope = (*NoticeEnvelope)(nil)
+ _ Envelope = (*EOSEEnvelope)(nil)
+ _ Envelope = (*CloseEnvelope)(nil)
+ _ Envelope = (*OKEnvelope)(nil)
+ _ Envelope = (*AuthEnvelope)(nil)
+)
+
+type EventEnvelope struct {
+ SubscriptionID *string
+ Event
+}
+
+func (_ EventEnvelope) Label() string { return "EVENT" }
+
+func (v *EventEnvelope) UnmarshalJSON(data []byte) error {
+ r := gjson.ParseBytes(data)
+ arr := r.Array()
+ switch len(arr) {
+ case 2:
+ return easyjson.Unmarshal([]byte(arr[1].Raw), &v.Event)
+ case 3:
+ v.SubscriptionID = &arr[1].Str
+ return easyjson.Unmarshal([]byte(arr[2].Raw), &v.Event)
+ default:
+ return fmt.Errorf("failed to decode EVENT envelope")
+ }
+}
+
+func (v EventEnvelope) MarshalJSON() ([]byte, error) {
+ w := jwriter.Writer{}
+ w.RawString(`["EVENT",`)
+ if v.SubscriptionID != nil {
+ w.RawString(`"` + *v.SubscriptionID + `",`)
+ }
+ v.Event.MarshalEasyJSON(&w)
+ w.RawString(`]`)
+ return w.BuildBytes()
+}
+
+type ReqEnvelope struct {
+ SubscriptionID string
+ Filters
+}
+
+func (_ ReqEnvelope) Label() string { return "REQ" }
+
+func (v *ReqEnvelope) UnmarshalJSON(data []byte) error {
+ r := gjson.ParseBytes(data)
+ arr := r.Array()
+ if len(arr) < 3 {
+ return fmt.Errorf("failed to decode REQ envelope: missing filters")
+ }
+ v.SubscriptionID = arr[1].Str
+ v.Filters = make(Filters, len(arr)-2)
+ f := 0
+ for i := 2; i < len(arr); i++ {
+ if err := easyjson.Unmarshal([]byte(arr[i].Raw), &v.Filters[f]); err != nil {
+ return fmt.Errorf("%w -- on filter %d", err, f)
+ }
+ f++
+ }
+
+ return nil
+}
+
+func (v ReqEnvelope) MarshalJSON() ([]byte, error) {
+ w := jwriter.Writer{}
+ w.RawString(`["REQ",`)
+ w.RawString(`"` + v.SubscriptionID + `"`)
+ for _, filter := range v.Filters {
+ w.RawString(`,`)
+ filter.MarshalEasyJSON(&w)
+ }
+ w.RawString(`]`)
+ return w.BuildBytes()
+}
+
+type CountEnvelope struct {
+ SubscriptionID string
+ Filters
+ Count *int64
+}
+
+func (_ CountEnvelope) Label() string { return "COUNT" }
+func (c CountEnvelope) String() string {
+ v, _ := json.Marshal(c)
+ return string(v)
+}
+
+func (v *CountEnvelope) UnmarshalJSON(data []byte) error {
+ r := gjson.ParseBytes(data)
+ arr := r.Array()
+ if len(arr) < 3 {
+ return fmt.Errorf("failed to decode COUNT envelope: missing filters")
+ }
+ v.SubscriptionID = arr[1].Str
+
+ if len(arr) < 3 {
+ return fmt.Errorf("COUNT array must have at least 3 items")
+ }
+
+ var countResult struct {
+ Count *int64 `json:"count"`
+ }
+ if err := json.Unmarshal([]byte(arr[2].Raw), &countResult); err == nil && countResult.Count != nil {
+ v.Count = countResult.Count
+ return nil
+ }
+
+ v.Filters = make(Filters, len(arr)-2)
+ f := 0
+ for i := 2; i < len(arr); i++ {
+ item := []byte(arr[i].Raw)
+
+ if err := easyjson.Unmarshal(item, &v.Filters[f]); err != nil {
+ return fmt.Errorf("%w -- on filter %d", err, f)
+ }
+
+ f++
+ }
+
+ return nil
+}
+
+func (v CountEnvelope) MarshalJSON() ([]byte, error) {
+ w := jwriter.Writer{}
+ w.RawString(`["COUNT",`)
+ w.RawString(`"` + v.SubscriptionID + `"`)
+ if v.Count != nil {
+ w.RawString(`,{"count":`)
+ w.RawString(strconv.FormatInt(*v.Count, 10))
+ w.RawString(`}`)
+ } else {
+ for _, filter := range v.Filters {
+ w.RawString(`,`)
+ filter.MarshalEasyJSON(&w)
+ }
+ }
+ w.RawString(`]`)
+ return w.BuildBytes()
+}
+
+type NoticeEnvelope string
+
+func (_ NoticeEnvelope) Label() string { return "NOTICE" }
+func (n NoticeEnvelope) String() string {
+ v, _ := json.Marshal(n)
+ return string(v)
+}
+
+func (v *NoticeEnvelope) UnmarshalJSON(data []byte) error {
+ r := gjson.ParseBytes(data)
+ arr := r.Array()
+ if len(arr) < 2 {
+ return fmt.Errorf("failed to decode NOTICE envelope")
+ }
+ *v = NoticeEnvelope(arr[1].Str)
+ return nil
+}
+
+func (v NoticeEnvelope) MarshalJSON() ([]byte, error) {
+ w := jwriter.Writer{}
+ w.RawString(`["NOTICE",`)
+ w.Raw(json.Marshal(string(v)))
+ w.RawString(`]`)
+ return w.BuildBytes()
+}
+
+type EOSEEnvelope string
+
+func (_ EOSEEnvelope) Label() string { return "EOSE" }
+func (e EOSEEnvelope) String() string {
+ v, _ := json.Marshal(e)
+ return string(v)
+}
+
+func (v *EOSEEnvelope) UnmarshalJSON(data []byte) error {
+ r := gjson.ParseBytes(data)
+ arr := r.Array()
+ if len(arr) < 2 {
+ return fmt.Errorf("failed to decode EOSE envelope")
+ }
+ *v = EOSEEnvelope(arr[1].Str)
+ return nil
+}
+
+func (v EOSEEnvelope) MarshalJSON() ([]byte, error) {
+ w := jwriter.Writer{}
+ w.RawString(`["EOSE",`)
+ w.Raw(json.Marshal(string(v)))
+ w.RawString(`]`)
+ return w.BuildBytes()
+}
+
+type CloseEnvelope string
+
+func (_ CloseEnvelope) Label() string { return "CLOSE" }
+func (c CloseEnvelope) String() string {
+ v, _ := json.Marshal(c)
+ return string(v)
+}
+
+func (v *CloseEnvelope) UnmarshalJSON(data []byte) error {
+ r := gjson.ParseBytes(data)
+ arr := r.Array()
+ switch len(arr) {
+ case 2:
+ *v = CloseEnvelope(arr[1].Str)
+ return nil
+ default:
+ return fmt.Errorf("failed to decode CLOSE envelope")
+ }
+}
+
+func (v CloseEnvelope) MarshalJSON() ([]byte, error) {
+ w := jwriter.Writer{}
+ w.RawString(`["CLOSE",`)
+ w.Raw(json.Marshal(string(v)))
+ w.RawString(`]`)
+ return w.BuildBytes()
+}
+
+type ClosedEnvelope struct {
+ SubscriptionID string
+ Reason string
+}
+
+func (_ ClosedEnvelope) Label() string { return "CLOSED" }
+func (c ClosedEnvelope) String() string {
+ v, _ := json.Marshal(c)
+ return string(v)
+}
+
+func (v *ClosedEnvelope) UnmarshalJSON(data []byte) error {
+ r := gjson.ParseBytes(data)
+ arr := r.Array()
+ switch len(arr) {
+ case 3:
+ *v = ClosedEnvelope{arr[1].Str, arr[2].Str}
+ return nil
+ default:
+ return fmt.Errorf("failed to decode CLOSED envelope")
+ }
+}
+
+func (v ClosedEnvelope) MarshalJSON() ([]byte, error) {
+ w := jwriter.Writer{}
+ w.RawString(`["CLOSED",`)
+ w.Raw(json.Marshal(string(v.SubscriptionID)))
+ w.RawString(`,`)
+ w.Raw(json.Marshal(v.Reason))
+ w.RawString(`]`)
+ return w.BuildBytes()
+}
+
+type OKEnvelope struct {
+ EventID string
+ OK bool
+ Reason string
+}
+
+func (_ OKEnvelope) Label() string { return "OK" }
+func (o OKEnvelope) String() string {
+ v, _ := json.Marshal(o)
+ return string(v)
+}
+
+func (v *OKEnvelope) UnmarshalJSON(data []byte) error {
+ r := gjson.ParseBytes(data)
+ arr := r.Array()
+ if len(arr) < 4 {
+ return fmt.Errorf("failed to decode OK envelope: missing fields")
+ }
+ v.EventID = arr[1].Str
+ v.OK = arr[2].Raw == "true"
+ v.Reason = arr[3].Str
+
+ return nil
+}
+
+func (v OKEnvelope) MarshalJSON() ([]byte, error) {
+ w := jwriter.Writer{}
+ w.RawString(`["OK",`)
+ w.RawString(`"` + v.EventID + `",`)
+ ok := "false"
+ if v.OK {
+ ok = "true"
+ }
+ w.RawString(ok)
+ w.RawString(`,`)
+ w.Raw(json.Marshal(v.Reason))
+ w.RawString(`]`)
+ return w.BuildBytes()
+}
+
+type AuthEnvelope struct {
+ Challenge *string
+ Event Event
+}
+
+func (_ AuthEnvelope) Label() string { return "AUTH" }
+func (a AuthEnvelope) String() string {
+ v, _ := json.Marshal(a)
+ return string(v)
+}
+
+func (v *AuthEnvelope) UnmarshalJSON(data []byte) error {
+ r := gjson.ParseBytes(data)
+ arr := r.Array()
+ if len(arr) < 2 {
+ return fmt.Errorf("failed to decode Auth envelope: missing fields")
+ }
+ if arr[1].IsObject() {
+ return easyjson.Unmarshal([]byte(arr[1].Raw), &v.Event)
+ } else {
+ v.Challenge = &arr[1].Str
+ }
+ return nil
+}
+
+func (v AuthEnvelope) MarshalJSON() ([]byte, error) {
+ w := jwriter.Writer{}
+ w.RawString(`["AUTH",`)
+ if v.Challenge != nil {
+ w.Raw(json.Marshal(*v.Challenge))
+ } else {
+ v.Event.MarshalEasyJSON(&w)
+ }
+ w.RawString(`]`)
+ return w.BuildBytes()
+}
diff --git a/vendor/github.com/nbd-wtf/go-nostr/event.go b/vendor/github.com/nbd-wtf/go-nostr/event.go
new file mode 100644
index 0000000..37bc20d
--- /dev/null
+++ b/vendor/github.com/nbd-wtf/go-nostr/event.go
@@ -0,0 +1,143 @@
+package nostr
+
+import (
+ "crypto/sha256"
+ "encoding/hex"
+ "fmt"
+
+ "github.com/btcsuite/btcd/btcec/v2"
+ "github.com/btcsuite/btcd/btcec/v2/schnorr"
+ "github.com/mailru/easyjson"
+)
+
+type Event struct {
+ ID string
+ PubKey string
+ CreatedAt Timestamp
+ Kind int
+ Tags Tags
+ Content string
+ Sig string
+
+ // anything here will be mashed together with the main event object when serializing
+ extra map[string]any
+}
+
+// Event Stringer interface, just returns the raw JSON as a string.
+func (evt Event) String() string {
+ j, _ := easyjson.Marshal(evt)
+ return string(j)
+}
+
+// GetID serializes and returns the event ID as a string.
+func (evt *Event) GetID() string {
+ h := sha256.Sum256(evt.Serialize())
+ return hex.EncodeToString(h[:])
+}
+
+// CheckID checks if the implied ID matches the given ID
+func (evt *Event) CheckID() bool {
+ ser := evt.Serialize()
+ h := sha256.Sum256(ser)
+
+ const hextable = "0123456789abcdef"
+
+ for i := 0; i < 32; i++ {
+ b := hextable[h[i]>>4]
+ if b != evt.ID[i*2] {
+ return false
+ }
+
+ b = hextable[h[i]&0x0f]
+ if b != evt.ID[i*2+1] {
+ return false
+ }
+ }
+
+ return true
+}
+
+// Serialize outputs a byte array that can be hashed/signed to identify/authenticate.
+// JSON encoding as defined in RFC4627.
+func (evt *Event) Serialize() []byte {
+ // the serialization process is just putting everything into a JSON array
+ // so the order is kept. See NIP-01
+ dst := make([]byte, 0)
+
+ // the header portion is easy to serialize
+ // [0,"pubkey",created_at,kind,[
+ dst = append(dst, []byte(
+ fmt.Sprintf(
+ "[0,\"%s\",%d,%d,",
+ evt.PubKey,
+ evt.CreatedAt,
+ evt.Kind,
+ ))...)
+
+ // tags
+ dst = evt.Tags.marshalTo(dst)
+ dst = append(dst, ',')
+
+ // content needs to be escaped in general as it is user generated.
+ dst = escapeString(dst, evt.Content)
+ dst = append(dst, ']')
+
+ return dst
+}
+
+// CheckSignature checks if the signature is valid for the id
+// (which is a hash of the serialized event content).
+// returns an error if the signature itself is invalid.
+func (evt Event) CheckSignature() (bool, error) {
+ // read and check pubkey
+ pk, err := hex.DecodeString(evt.PubKey)
+ if err != nil {
+ return false, fmt.Errorf("event pubkey '%s' is invalid hex: %w", evt.PubKey, err)
+ }
+
+ pubkey, err := schnorr.ParsePubKey(pk)
+ if err != nil {
+ return false, fmt.Errorf("event has invalid pubkey '%s': %w", evt.PubKey, err)
+ }
+
+ // read signature
+ s, err := hex.DecodeString(evt.Sig)
+ if err != nil {
+ return false, fmt.Errorf("signature '%s' is invalid hex: %w", evt.Sig, err)
+ }
+ sig, err := schnorr.ParseSignature(s)
+ if err != nil {
+ return false, fmt.Errorf("failed to parse signature: %w", err)
+ }
+
+ // check signature
+ hash := sha256.Sum256(evt.Serialize())
+ return sig.Verify(hash[:], pubkey), nil
+}
+
+// Sign signs an event with a given privateKey.
+func (evt *Event) Sign(privateKey string, signOpts ...schnorr.SignOption) error {
+ s, err := hex.DecodeString(privateKey)
+ if err != nil {
+ return fmt.Errorf("Sign called with invalid private key '%s': %w", privateKey, err)
+ }
+
+ if evt.Tags == nil {
+ evt.Tags = make(Tags, 0)
+ }
+
+ sk, pk := btcec.PrivKeyFromBytes(s)
+ pkBytes := pk.SerializeCompressed()
+ evt.PubKey = hex.EncodeToString(pkBytes[1:])
+
+ h := sha256.Sum256(evt.Serialize())
+ sig, err := schnorr.Sign(sk, h[:], signOpts...)
+ if err != nil {
+ return err
+ }
+
+ evt.ID = hex.EncodeToString(h[:])
+ evt.Sig = hex.EncodeToString(sig.Serialize())
+
+ return nil
+}
diff --git a/vendor/github.com/nbd-wtf/go-nostr/event_easyjson.go b/vendor/github.com/nbd-wtf/go-nostr/event_easyjson.go
new file mode 100644
index 0000000..01959f7
--- /dev/null
+++ b/vendor/github.com/nbd-wtf/go-nostr/event_easyjson.go
@@ -0,0 +1,192 @@
+package nostr
+
+import (
+ json "encoding/json"
+
+ easyjson "github.com/mailru/easyjson"
+ jlexer "github.com/mailru/easyjson/jlexer"
+ jwriter "github.com/mailru/easyjson/jwriter"
+)
+
+// suppress unused package warning
+var (
+ _ *json.RawMessage
+ _ *jlexer.Lexer
+ _ *jwriter.Writer
+ _ easyjson.Marshaler
+)
+
+func easyjsonF642ad3eDecodeGithubComNbdWtfGoNostr(in *jlexer.Lexer, out *Event) {
+ isTopLevel := in.IsStart()
+ if in.IsNull() {
+ if isTopLevel {
+ in.Consumed()
+ }
+ in.Skip()
+ return
+ }
+ out.extra = make(map[string]any)
+ in.Delim('{')
+ for !in.IsDelim('}') {
+ key := in.UnsafeFieldName(true)
+ in.WantColon()
+ if in.IsNull() {
+ in.Skip()
+ in.WantComma()
+ continue
+ }
+ switch key {
+ case "id":
+ out.ID = in.String()
+ case "pubkey":
+ out.PubKey = in.String()
+ case "created_at":
+ out.CreatedAt = Timestamp(in.Int64())
+ case "kind":
+ out.Kind = in.Int()
+ case "tags":
+ if in.IsNull() {
+ in.Skip()
+ out.Tags = nil
+ } else {
+ in.Delim('[')
+ if out.Tags == nil {
+ if !in.IsDelim(']') {
+ out.Tags = make(Tags, 0, 7)
+ } else {
+ out.Tags = Tags{}
+ }
+ } else {
+ out.Tags = (out.Tags)[:0]
+ }
+ for !in.IsDelim(']') {
+ var v1 Tag
+ if in.IsNull() {
+ in.Skip()
+ v1 = nil
+ } else {
+ in.Delim('[')
+ if !in.IsDelim(']') {
+ v1 = make(Tag, 0, 5)
+ } else {
+ v1 = Tag{}
+ }
+ for !in.IsDelim(']') {
+ var v2 string
+ v2 = string(in.String())
+ v1 = append(v1, v2)
+ in.WantComma()
+ }
+ in.Delim(']')
+ }
+ out.Tags = append(out.Tags, v1)
+ in.WantComma()
+ }
+ in.Delim(']')
+ }
+ case "content":
+ out.Content = in.String()
+ case "sig":
+ out.Sig = in.String()
+ default:
+ out.extra[key] = in.Interface()
+ }
+ in.WantComma()
+ }
+ in.Delim('}')
+ if isTopLevel {
+ in.Consumed()
+ }
+}
+
+func easyjsonF642ad3eEncodeGithubComNbdWtfGoNostr(out *jwriter.Writer, in Event) {
+ out.RawByte('{')
+ first := true
+ _ = first
+ {
+ const prefix string = "\"kind\":"
+ out.RawString(prefix)
+ out.Int(in.Kind)
+ }
+ {
+ if in.ID != "" {
+ const prefix string = ",\"id\":"
+ out.RawString(prefix)
+ out.String(in.ID)
+ }
+ }
+ {
+ if in.PubKey != "" {
+ const prefix string = ",\"pubkey\":"
+ out.RawString(prefix)
+ out.String(in.PubKey)
+ }
+ }
+ {
+ const prefix string = ",\"created_at\":"
+ out.RawString(prefix)
+ out.Int64(int64(in.CreatedAt))
+ }
+ {
+ const prefix string = ",\"tags\":"
+ out.RawString(prefix)
+ out.RawByte('[')
+ for v3, v4 := range in.Tags {
+ if v3 > 0 {
+ out.RawByte(',')
+ }
+ out.RawByte('[')
+ for v5, v6 := range v4 {
+ if v5 > 0 {
+ out.RawByte(',')
+ }
+ out.String(string(v6))
+ }
+ out.RawByte(']')
+ }
+ out.RawByte(']')
+ }
+ {
+ const prefix string = ",\"content\":"
+ out.RawString(prefix)
+ out.String(in.Content)
+ }
+ {
+ if in.Sig != "" {
+ const prefix string = ",\"sig\":"
+ out.RawString(prefix)
+ out.String(in.Sig)
+ }
+ }
+ {
+ for key, value := range in.extra {
+ out.RawString(",\"" + key + "\":")
+ out.Raw(json.Marshal(value))
+ }
+ }
+ out.RawByte('}')
+}
+
+// MarshalJSON supports json.Marshaler interface
+func (v Event) MarshalJSON() ([]byte, error) {
+ w := jwriter.Writer{}
+ easyjsonF642ad3eEncodeGithubComNbdWtfGoNostr(&w, v)
+ return w.Buffer.BuildBytes(), w.Error
+}
+
+// MarshalEasyJSON supports easyjson.Marshaler interface
+func (v Event) MarshalEasyJSON(w *jwriter.Writer) {
+ easyjsonF642ad3eEncodeGithubComNbdWtfGoNostr(w, v)
+}
+
+// UnmarshalJSON supports json.Unmarshaler interface
+func (v *Event) UnmarshalJSON(data []byte) error {
+ r := jlexer.Lexer{Data: data}
+ easyjsonF642ad3eDecodeGithubComNbdWtfGoNostr(&r, v)
+ return r.Error()
+}
+
+// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
+func (v *Event) UnmarshalEasyJSON(l *jlexer.Lexer) {
+ easyjsonF642ad3eDecodeGithubComNbdWtfGoNostr(l, v)
+}
diff --git a/vendor/github.com/nbd-wtf/go-nostr/event_extra.go b/vendor/github.com/nbd-wtf/go-nostr/event_extra.go
new file mode 100644
index 0000000..ad2838f
--- /dev/null
+++ b/vendor/github.com/nbd-wtf/go-nostr/event_extra.go
@@ -0,0 +1,72 @@
+package nostr
+
+// SetExtra sets an out-of-the-spec value under the given key into the event object.
+func (evt *Event) SetExtra(key string, value any) {
+ if evt.extra == nil {
+ evt.extra = make(map[string]any)
+ }
+ evt.extra[key] = value
+}
+
+// RemoveExtra removes an out-of-the-spec value under the given key from the event object.
+func (evt *Event) RemoveExtra(key string) {
+ if evt.extra == nil {
+ return
+ }
+ delete(evt.extra, key)
+}
+
+// GetExtra tries to get a value under the given key that may be present in the event object
+// but is hidden in the basic type since it is out of the spec.
+func (evt Event) GetExtra(key string) any {
+ ival, _ := evt.extra[key]
+ return ival
+}
+
+// GetExtraString is like [Event.GetExtra], but only works if the value is a string,
+// otherwise returns the zero-value.
+func (evt Event) GetExtraString(key string) string {
+ ival, ok := evt.extra[key]
+ if !ok {
+ return ""
+ }
+ val, ok := ival.(string)
+ if !ok {
+ return ""
+ }
+ return val
+}
+
+// GetExtraNumber is like [Event.GetExtra], but only works if the value is a float64,
+// otherwise returns the zero-value.
+func (evt Event) GetExtraNumber(key string) float64 {
+ ival, ok := evt.extra[key]
+ if !ok {
+ return 0
+ }
+
+ switch val := ival.(type) {
+ case float64:
+ return val
+ case int:
+ return float64(val)
+ case int64:
+ return float64(val)
+ }
+
+ return 0
+}
+
+// GetExtraBoolean is like [Event.GetExtra], but only works if the value is a boolean,
+// otherwise returns the zero-value.
+func (evt Event) GetExtraBoolean(key string) bool {
+ ival, ok := evt.extra[key]
+ if !ok {
+ return false
+ }
+ val, ok := ival.(bool)
+ if !ok {
+ return false
+ }
+ return val
+}
diff --git a/vendor/github.com/nbd-wtf/go-nostr/filter.go b/vendor/github.com/nbd-wtf/go-nostr/filter.go
new file mode 100644
index 0000000..e28ad5a
--- /dev/null
+++ b/vendor/github.com/nbd-wtf/go-nostr/filter.go
@@ -0,0 +1,172 @@
+package nostr
+
+import (
+ "encoding/json"
+ "slices"
+
+ "github.com/mailru/easyjson"
+)
+
+type Filters []Filter
+
+type Filter struct {
+ IDs []string
+ Kinds []int
+ Authors []string
+ Tags TagMap
+ Since *Timestamp
+ Until *Timestamp
+ Limit int
+ Search string
+
+ // LimitZero is or must be set when there is a "limit":0 in the filter, and not when "limit" is just omitted
+ LimitZero bool `json:"-"`
+}
+
+type TagMap map[string][]string
+
+func (eff Filters) String() string {
+ j, _ := json.Marshal(eff)
+ return string(j)
+}
+
+func (eff Filters) Match(event *Event) bool {
+ for _, filter := range eff {
+ if filter.Matches(event) {
+ return true
+ }
+ }
+ return false
+}
+
+func (eff Filters) MatchIgnoringTimestampConstraints(event *Event) bool {
+ for _, filter := range eff {
+ if filter.MatchesIgnoringTimestampConstraints(event) {
+ return true
+ }
+ }
+ return false
+}
+
+func (ef Filter) String() string {
+ j, _ := easyjson.Marshal(ef)
+ return string(j)
+}
+
+func (ef Filter) Matches(event *Event) bool {
+ if !ef.MatchesIgnoringTimestampConstraints(event) {
+ return false
+ }
+
+ if ef.Since != nil && event.CreatedAt < *ef.Since {
+ return false
+ }
+
+ if ef.Until != nil && event.CreatedAt > *ef.Until {
+ return false
+ }
+
+ return true
+}
+
+func (ef Filter) MatchesIgnoringTimestampConstraints(event *Event) bool {
+ if event == nil {
+ return false
+ }
+
+ if ef.IDs != nil && !slices.Contains(ef.IDs, event.ID) {
+ return false
+ }
+
+ if ef.Kinds != nil && !slices.Contains(ef.Kinds, event.Kind) {
+ return false
+ }
+
+ if ef.Authors != nil && !slices.Contains(ef.Authors, event.PubKey) {
+ return false
+ }
+
+ for f, v := range ef.Tags {
+ if v != nil && !event.Tags.ContainsAny(f, v) {
+ return false
+ }
+ }
+
+ return true
+}
+
+func FilterEqual(a Filter, b Filter) bool {
+ if !similar(a.Kinds, b.Kinds) {
+ return false
+ }
+
+ if !similar(a.IDs, b.IDs) {
+ return false
+ }
+
+ if !similar(a.Authors, b.Authors) {
+ return false
+ }
+
+ if len(a.Tags) != len(b.Tags) {
+ return false
+ }
+
+ for f, av := range a.Tags {
+ if bv, ok := b.Tags[f]; !ok {
+ return false
+ } else {
+ if !similar(av, bv) {
+ return false
+ }
+ }
+ }
+
+ if !arePointerValuesEqual(a.Since, b.Since) {
+ return false
+ }
+
+ if !arePointerValuesEqual(a.Until, b.Until) {
+ return false
+ }
+
+ if a.Search != b.Search {
+ return false
+ }
+
+ if a.LimitZero != b.LimitZero {
+ return false
+ }
+
+ return true
+}
+
+func (ef Filter) Clone() Filter {
+ clone := Filter{
+ IDs: slices.Clone(ef.IDs),
+ Authors: slices.Clone(ef.Authors),
+ Kinds: slices.Clone(ef.Kinds),
+ Limit: ef.Limit,
+ Search: ef.Search,
+ LimitZero: ef.LimitZero,
+ }
+
+ if ef.Tags != nil {
+ clone.Tags = make(TagMap, len(ef.Tags))
+ for k, v := range ef.Tags {
+ clone.Tags[k] = slices.Clone(v)
+ }
+ }
+
+ if ef.Since != nil {
+ since := *ef.Since
+ clone.Since = &since
+ }
+
+ if ef.Until != nil {
+ until := *ef.Until
+ clone.Until = &until
+ }
+
+ return clone
+}
diff --git a/vendor/github.com/nbd-wtf/go-nostr/filter_easyjson.go b/vendor/github.com/nbd-wtf/go-nostr/filter_easyjson.go
new file mode 100644
index 0000000..4880d8a
--- /dev/null
+++ b/vendor/github.com/nbd-wtf/go-nostr/filter_easyjson.go
@@ -0,0 +1,311 @@
+package nostr
+
+import (
+ json "encoding/json"
+
+ easyjson "github.com/mailru/easyjson"
+ jlexer "github.com/mailru/easyjson/jlexer"
+ jwriter "github.com/mailru/easyjson/jwriter"
+)
+
+// suppress unused package warning
+var (
+ _ *json.RawMessage
+ _ *jlexer.Lexer
+ _ *jwriter.Writer
+ _ easyjson.Marshaler
+)
+
+func easyjson4d398eaaDecodeGithubComNbdWtfGoNostr(in *jlexer.Lexer, out *Filter) {
+ isTopLevel := in.IsStart()
+ if in.IsNull() {
+ if isTopLevel {
+ in.Consumed()
+ }
+ in.Skip()
+ return
+ }
+ out.Tags = make(TagMap)
+ in.Delim('{')
+ for !in.IsDelim('}') {
+ key := in.UnsafeFieldName(false)
+ in.WantColon()
+ if in.IsNull() {
+ in.Skip()
+ in.WantComma()
+ continue
+ }
+ switch key {
+ case "ids":
+ if in.IsNull() {
+ in.Skip()
+ out.IDs = nil
+ } else {
+ in.Delim('[')
+ if out.IDs == nil {
+ if !in.IsDelim(']') {
+ out.IDs = make([]string, 0, 20)
+ } else {
+ out.IDs = []string{}
+ }
+ } else {
+ out.IDs = (out.IDs)[:0]
+ }
+ for !in.IsDelim(']') {
+ var v1 string
+ v1 = string(in.String())
+ out.IDs = append(out.IDs, v1)
+ in.WantComma()
+ }
+ in.Delim(']')
+ }
+ case "kinds":
+ if in.IsNull() {
+ in.Skip()
+ out.Kinds = nil
+ } else {
+ in.Delim('[')
+ if out.Kinds == nil {
+ if !in.IsDelim(']') {
+ out.Kinds = make([]int, 0, 8)
+ } else {
+ out.Kinds = []int{}
+ }
+ } else {
+ out.Kinds = (out.Kinds)[:0]
+ }
+ for !in.IsDelim(']') {
+ var v2 int
+ v2 = int(in.Int())
+ out.Kinds = append(out.Kinds, v2)
+ in.WantComma()
+ }
+ in.Delim(']')
+ }
+ case "authors":
+ if in.IsNull() {
+ in.Skip()
+ out.Authors = nil
+ } else {
+ in.Delim('[')
+ if out.Authors == nil {
+ if !in.IsDelim(']') {
+ out.Authors = make([]string, 0, 40)
+ } else {
+ out.Authors = []string{}
+ }
+ } else {
+ out.Authors = (out.Authors)[:0]
+ }
+ for !in.IsDelim(']') {
+ var v3 string
+ v3 = string(in.String())
+ out.Authors = append(out.Authors, v3)
+ in.WantComma()
+ }
+ in.Delim(']')
+ }
+ case "since":
+ if in.IsNull() {
+ in.Skip()
+ out.Since = nil
+ } else {
+ if out.Since == nil {
+ out.Since = new(Timestamp)
+ }
+ *out.Since = Timestamp(in.Int64())
+ }
+ case "until":
+ if in.IsNull() {
+ in.Skip()
+ out.Until = nil
+ } else {
+ if out.Until == nil {
+ out.Until = new(Timestamp)
+ }
+ *out.Until = Timestamp(in.Int64())
+ }
+ case "limit":
+ out.Limit = int(in.Int())
+ if out.Limit == 0 {
+ out.LimitZero = true
+ }
+ case "search":
+ out.Search = string(in.String())
+ default:
+ if len(key) > 1 && key[0] == '#' {
+ tagValues := make([]string, 0, 40)
+ if !in.IsNull() {
+ in.Delim('[')
+ if out.Authors == nil {
+ if !in.IsDelim(']') {
+ tagValues = make([]string, 0, 4)
+ } else {
+ tagValues = []string{}
+ }
+ } else {
+ tagValues = (tagValues)[:0]
+ }
+ for !in.IsDelim(']') {
+ var v3 string
+ v3 = string(in.String())
+ tagValues = append(tagValues, v3)
+ in.WantComma()
+ }
+ in.Delim(']')
+ }
+ out.Tags[key[1:]] = tagValues
+ } else {
+ in.SkipRecursive()
+ }
+ }
+ in.WantComma()
+ }
+ in.Delim('}')
+ if isTopLevel {
+ in.Consumed()
+ }
+}
+
+func easyjson4d398eaaEncodeGithubComNbdWtfGoNostr(out *jwriter.Writer, in Filter) {
+ out.RawByte('{')
+ first := true
+ _ = first
+ if len(in.IDs) != 0 {
+ const prefix string = ",\"ids\":"
+ first = false
+ out.RawString(prefix[1:])
+ {
+ out.RawByte('[')
+ for v4, v5 := range in.IDs {
+ if v4 > 0 {
+ out.RawByte(',')
+ }
+ out.String(string(v5))
+ }
+ out.RawByte(']')
+ }
+ }
+ if len(in.Kinds) != 0 {
+ const prefix string = ",\"kinds\":"
+ if first {
+ first = false
+ out.RawString(prefix[1:])
+ } else {
+ out.RawString(prefix)
+ }
+ {
+ out.RawByte('[')
+ for v6, v7 := range in.Kinds {
+ if v6 > 0 {
+ out.RawByte(',')
+ }
+ out.Int(int(v7))
+ }
+ out.RawByte(']')
+ }
+ }
+ if len(in.Authors) != 0 {
+ const prefix string = ",\"authors\":"
+ if first {
+ first = false
+ out.RawString(prefix[1:])
+ } else {
+ out.RawString(prefix)
+ }
+ {
+ out.RawByte('[')
+ for v8, v9 := range in.Authors {
+ if v8 > 0 {
+ out.RawByte(',')
+ }
+ out.String(string(v9))
+ }
+ out.RawByte(']')
+ }
+ }
+ if in.Since != nil {
+ const prefix string = ",\"since\":"
+ if first {
+ first = false
+ out.RawString(prefix[1:])
+ } else {
+ out.RawString(prefix)
+ }
+ out.Int64(int64(*in.Since))
+ }
+ if in.Until != nil {
+ const prefix string = ",\"until\":"
+ if first {
+ first = false
+ out.RawString(prefix[1:])
+ } else {
+ out.RawString(prefix)
+ }
+ out.Int64(int64(*in.Until))
+ }
+ if in.Limit != 0 || in.LimitZero {
+ const prefix string = ",\"limit\":"
+ if first {
+ first = false
+ out.RawString(prefix[1:])
+ } else {
+ out.RawString(prefix)
+ }
+ out.Int(int(in.Limit))
+ }
+ if in.Search != "" {
+ const prefix string = ",\"search\":"
+ if first {
+ first = false
+ out.RawString(prefix[1:])
+ } else {
+ out.RawString(prefix)
+ }
+ out.String(string(in.Search))
+ }
+ for tag, values := range in.Tags {
+ const prefix string = ",\"authors\":"
+ if first {
+ first = false
+ out.RawString("\"#" + tag + "\":")
+ } else {
+ out.RawString(",\"#" + tag + "\":")
+ }
+ {
+ out.RawByte('[')
+ for i, v := range values {
+ if i > 0 {
+ out.RawByte(',')
+ }
+ out.String(string(v))
+ }
+ out.RawByte(']')
+ }
+ }
+ out.RawByte('}')
+}
+
+// MarshalJSON supports json.Marshaler interface
+func (v Filter) MarshalJSON() ([]byte, error) {
+ w := jwriter.Writer{}
+ easyjson4d398eaaEncodeGithubComNbdWtfGoNostr(&w, v)
+ return w.Buffer.BuildBytes(), w.Error
+}
+
+// MarshalEasyJSON supports easyjson.Marshaler interface
+func (v Filter) MarshalEasyJSON(w *jwriter.Writer) {
+ easyjson4d398eaaEncodeGithubComNbdWtfGoNostr(w, v)
+}
+
+// UnmarshalJSON supports json.Unmarshaler interface
+func (v *Filter) UnmarshalJSON(data []byte) error {
+ r := jlexer.Lexer{Data: data}
+ easyjson4d398eaaDecodeGithubComNbdWtfGoNostr(&r, v)
+ return r.Error()
+}
+
+// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
+func (v *Filter) UnmarshalEasyJSON(l *jlexer.Lexer) {
+ easyjson4d398eaaDecodeGithubComNbdWtfGoNostr(l, v)
+}
diff --git a/vendor/github.com/nbd-wtf/go-nostr/helpers.go b/vendor/github.com/nbd-wtf/go-nostr/helpers.go
new file mode 100644
index 0000000..5504673
--- /dev/null
+++ b/vendor/github.com/nbd-wtf/go-nostr/helpers.go
@@ -0,0 +1,94 @@
+package nostr
+
+import (
+ "sync"
+ "unsafe"
+
+ "golang.org/x/exp/constraints"
+)
+
+const MAX_LOCKS = 50
+
+var namedMutexPool = make([]sync.Mutex, MAX_LOCKS)
+
+//go:noescape
+//go:linkname memhash runtime.memhash
+func memhash(p unsafe.Pointer, h, s uintptr) uintptr
+
+func namedLock(name string) (unlock func()) {
+ sptr := unsafe.StringData(name)
+ idx := uint64(memhash(unsafe.Pointer(sptr), 0, uintptr(len(name)))) % MAX_LOCKS
+ namedMutexPool[idx].Lock()
+ return namedMutexPool[idx].Unlock
+}
+
+func similar[E constraints.Ordered](as, bs []E) bool {
+ if len(as) != len(bs) {
+ return false
+ }
+
+ for _, a := range as {
+ for _, b := range bs {
+ if b == a {
+ goto next
+ }
+ }
+ // didn't find a B that corresponded to the current A
+ return false
+
+ next:
+ continue
+ }
+
+ return true
+}
+
+// Escaping strings for JSON encoding according to RFC8259.
+// Also encloses result in quotation marks "".
+func escapeString(dst []byte, s string) []byte {
+ dst = append(dst, '"')
+ for i := 0; i < len(s); i++ {
+ c := s[i]
+ switch {
+ case c == '"':
+ // quotation mark
+ dst = append(dst, []byte{'\\', '"'}...)
+ case c == '\\':
+ // reverse solidus
+ dst = append(dst, []byte{'\\', '\\'}...)
+ case c >= 0x20:
+ // default, rest below are control chars
+ dst = append(dst, c)
+ case c == 0x08:
+ dst = append(dst, []byte{'\\', 'b'}...)
+ case c < 0x09:
+ dst = append(dst, []byte{'\\', 'u', '0', '0', '0', '0' + c}...)
+ case c == 0x09:
+ dst = append(dst, []byte{'\\', 't'}...)
+ case c == 0x0a:
+ dst = append(dst, []byte{'\\', 'n'}...)
+ case c == 0x0c:
+ dst = append(dst, []byte{'\\', 'f'}...)
+ case c == 0x0d:
+ dst = append(dst, []byte{'\\', 'r'}...)
+ case c < 0x10:
+ dst = append(dst, []byte{'\\', 'u', '0', '0', '0', 0x57 + c}...)
+ case c < 0x1a:
+ dst = append(dst, []byte{'\\', 'u', '0', '0', '1', 0x20 + c}...)
+ case c < 0x20:
+ dst = append(dst, []byte{'\\', 'u', '0', '0', '1', 0x47 + c}...)
+ }
+ }
+ dst = append(dst, '"')
+ return dst
+}
+
+func arePointerValuesEqual[V comparable](a *V, b *V) bool {
+ if a == nil && b == nil {
+ return true
+ }
+ if a != nil && b != nil {
+ return *a == *b
+ }
+ return false
+}
diff --git a/vendor/github.com/nbd-wtf/go-nostr/interface.go b/vendor/github.com/nbd-wtf/go-nostr/interface.go
new file mode 100644
index 0000000..7149d2b
--- /dev/null
+++ b/vendor/github.com/nbd-wtf/go-nostr/interface.go
@@ -0,0 +1,72 @@
+package nostr
+
+import (
+ "context"
+ "errors"
+ "slices"
+)
+
+type RelayStore interface {
+ Publish(context.Context, Event) error
+ QueryEvents(context.Context, Filter) (chan *Event, error)
+ QuerySync(context.Context, Filter) ([]*Event, error)
+}
+
+var (
+ _ RelayStore = (*Relay)(nil)
+ _ RelayStore = (*MultiStore)(nil)
+)
+
+type MultiStore []RelayStore
+
+func (multi MultiStore) Publish(ctx context.Context, event Event) error {
+ errs := make([]error, len(multi))
+ for i, s := range multi {
+ errs[i] = s.Publish(ctx, event)
+ }
+ return errors.Join(errs...)
+}
+
+func (multi MultiStore) QueryEvents(ctx context.Context, filter Filter) (chan *Event, error) {
+ multich := make(chan *Event)
+
+ errs := make([]error, len(multi))
+ var good bool
+ for i, s := range multi {
+ ch, err := s.QueryEvents(ctx, filter)
+ errs[i] = err
+ if err == nil {
+ good = true
+ go func(ch chan *Event) {
+ for evt := range ch {
+ multich <- evt
+ }
+ }(ch)
+ }
+ }
+
+ if good {
+ return multich, nil
+ } else {
+ return nil, errors.Join(errs...)
+ }
+}
+
+func (multi MultiStore) QuerySync(ctx context.Context, filter Filter) ([]*Event, error) {
+ errs := make([]error, len(multi))
+ events := make([]*Event, 0, max(filter.Limit, 250))
+ for i, s := range multi {
+ res, err := s.QuerySync(ctx, filter)
+ errs[i] = err
+ events = append(events, res...)
+ }
+ slices.SortFunc(events, func(a, b *Event) int {
+ if b.CreatedAt > a.CreatedAt {
+ return 1
+ } else if b.CreatedAt < a.CreatedAt {
+ return -1
+ }
+ return 0
+ })
+ return events, errors.Join(errs...)
+}
diff --git a/vendor/github.com/nbd-wtf/go-nostr/keys.go b/vendor/github.com/nbd-wtf/go-nostr/keys.go
new file mode 100644
index 0000000..baa1841
--- /dev/null
+++ b/vendor/github.com/nbd-wtf/go-nostr/keys.go
@@ -0,0 +1,55 @@
+package nostr
+
+import (
+ "crypto/rand"
+ "encoding/hex"
+ "fmt"
+ "io"
+ "math/big"
+ "strings"
+
+ "github.com/btcsuite/btcd/btcec/v2"
+ "github.com/btcsuite/btcd/btcec/v2/schnorr"
+)
+
+func GeneratePrivateKey() string {
+ params := btcec.S256().Params()
+ one := new(big.Int).SetInt64(1)
+
+ b := make([]byte, params.BitSize/8+8)
+ if _, err := io.ReadFull(rand.Reader, b); err != nil {
+ return ""
+ }
+
+ k := new(big.Int).SetBytes(b)
+ n := new(big.Int).Sub(params.N, one)
+ k.Mod(k, n)
+ k.Add(k, one)
+
+ return fmt.Sprintf("%064x", k.Bytes())
+}
+
+func GetPublicKey(sk string) (string, error) {
+ b, err := hex.DecodeString(sk)
+ if err != nil {
+ return "", err
+ }
+
+ _, pk := btcec.PrivKeyFromBytes(b)
+ return hex.EncodeToString(schnorr.SerializePubKey(pk)), nil
+}
+
+// Deprecated: use IsValid32ByteHex instead -- functionality unchanged.
+func IsValidPublicKeyHex(pk string) bool {
+ if strings.ToLower(pk) != pk {
+ return false
+ }
+ dec, _ := hex.DecodeString(pk)
+ return len(dec) == 32
+}
+
+func IsValidPublicKey(pk string) bool {
+ v, _ := hex.DecodeString(pk)
+ _, err := schnorr.ParsePubKey(v)
+ return err == nil
+}
diff --git a/vendor/github.com/nbd-wtf/go-nostr/kinds.go b/vendor/github.com/nbd-wtf/go-nostr/kinds.go
new file mode 100644
index 0000000..ef40e9d
--- /dev/null
+++ b/vendor/github.com/nbd-wtf/go-nostr/kinds.go
@@ -0,0 +1,56 @@
+package nostr
+
+const (
+ KindProfileMetadata int = 0
+ KindTextNote int = 1
+ KindRecommendServer int = 2
+ KindContactList int = 3
+ KindEncryptedDirectMessage int = 4
+ KindDeletion int = 5
+ KindRepost int = 6
+ KindReaction int = 7
+ KindSimpleGroupChatMessage int = 9
+ KindSimpleGroupThread int = 11
+ KindSimpleGroupReply int = 12
+ KindChannelCreation int = 40
+ KindChannelMetadata int = 41
+ KindChannelMessage int = 42
+ KindChannelHideMessage int = 43
+ KindChannelMuteUser int = 44
+ KindPatch int = 1617
+ KindFileMetadata int = 1063
+ KindSimpleGroupAddUser int = 9000
+ KindSimpleGroupRemoveUser int = 9001
+ KindSimpleGroupEditMetadata int = 9002
+ KindSimpleGroupAddPermission int = 9003
+ KindSimpleGroupRemovePermission int = 9004
+ KindSimpleGroupDeleteEvent int = 9005
+ KindSimpleGroupEditGroupStatus int = 9006
+ KindSimpleGroupCreateGroup int = 9007
+ KindSimpleGroupDeleteGroup int = 9008
+ KindSimpleGroupJoinRequest int = 9021
+ KindSimpleGroupLeaveRequest int = 9022
+ KindZapRequest int = 9734
+ KindZap int = 9735
+ KindMuteList int = 10000
+ KindPinList int = 10001
+ KindRelayListMetadata int = 10002
+ KindNWCWalletInfo int = 13194
+ KindClientAuthentication int = 22242
+ KindNWCWalletRequest int = 23194
+ KindNWCWalletResponse int = 23195
+ KindNostrConnect int = 24133
+ KindCategorizedPeopleList int = 30000
+ KindCategorizedBookmarksList int = 30001
+ KindProfileBadges int = 30008
+ KindBadgeDefinition int = 30009
+ KindStallDefinition int = 30017
+ KindProductDefinition int = 30018
+ KindArticle int = 30023
+ KindApplicationSpecificData int = 30078
+ KindRepositoryAnnouncement int = 30617
+ KindRepositoryState int = 30618
+ KindSimpleGroupMetadata int = 39000
+ KindSimpleGroupAdmins int = 39001
+ KindSimpleGroupMembers int = 39002
+)
diff --git a/vendor/github.com/nbd-wtf/go-nostr/log.go b/vendor/github.com/nbd-wtf/go-nostr/log.go
new file mode 100644
index 0000000..52e2a44
--- /dev/null
+++ b/vendor/github.com/nbd-wtf/go-nostr/log.go
@@ -0,0 +1,14 @@
+package nostr
+
+import (
+ "log"
+ "os"
+)
+
+var (
+ // call SetOutput on InfoLogger to enable info logging
+ InfoLogger = log.New(os.Stderr, "[go-nostr][info] ", log.LstdFlags)
+
+ // call SetOutput on DebugLogger to enable debug logging
+ DebugLogger = log.New(os.Stderr, "[go-nostr][debug] ", log.LstdFlags)
+)
diff --git a/vendor/github.com/nbd-wtf/go-nostr/log_debug.go b/vendor/github.com/nbd-wtf/go-nostr/log_debug.go
new file mode 100644
index 0000000..3fb34c8
--- /dev/null
+++ b/vendor/github.com/nbd-wtf/go-nostr/log_debug.go
@@ -0,0 +1,40 @@
+//go:build debug
+
+package nostr
+
+import (
+ "encoding/json"
+ "fmt"
+)
+
+func debugLogf(str string, args ...any) {
+ // this is such that we don't modify the actual args that may be used outside of this function
+ printableArgs := make([]any, len(args))
+
+ for i, v := range args {
+ printableArgs[i] = stringify(v)
+ }
+
+ DebugLogger.Printf(str, printableArgs...)
+}
+
+func stringify(anything any) any {
+ switch v := anything.(type) {
+ case []any:
+ // this is such that we don't modify the actual values that may be used outside of this function
+ printableValues := make([]any, len(v))
+ for i, subv := range v {
+ printableValues[i] = stringify(subv)
+ }
+ return printableValues
+ case []json.RawMessage:
+ j, _ := json.Marshal(v)
+ return string(j)
+ case []byte:
+ return string(v)
+ case fmt.Stringer:
+ return v.String()
+ default:
+ return v
+ }
+}
diff --git a/vendor/github.com/nbd-wtf/go-nostr/log_normal.go b/vendor/github.com/nbd-wtf/go-nostr/log_normal.go
new file mode 100644
index 0000000..af79930
--- /dev/null
+++ b/vendor/github.com/nbd-wtf/go-nostr/log_normal.go
@@ -0,0 +1,6 @@
+//go:build !debug
+
+package nostr
+
+func debugLogf(str string, args ...any) {
+}
diff --git a/vendor/github.com/nbd-wtf/go-nostr/nip11/fetch.go b/vendor/github.com/nbd-wtf/go-nostr/nip11/fetch.go
new file mode 100644
index 0000000..b230a98
--- /dev/null
+++ b/vendor/github.com/nbd-wtf/go-nostr/nip11/fetch.go
@@ -0,0 +1,51 @@
+package nip11
+
+import (
+ "context"
+ "encoding/json"
+ "fmt"
+ "net/http"
+ "time"
+
+ "github.com/nbd-wtf/go-nostr"
+)
+
+// Fetch fetches the NIP-11 metadata for a relay.
+//
+// It will always return `info` with at least `URL` filled -- even if we can't connect to the
+// relay or if it doesn't have a NIP-11 handler -- although in that case it will also return
+// an error.
+func Fetch(ctx context.Context, u string) (info RelayInformationDocument, err error) {
+ if _, ok := ctx.Deadline(); !ok {
+ // if no timeout is set, force it to 7 seconds
+ var cancel context.CancelFunc
+ ctx, cancel = context.WithTimeout(ctx, 7*time.Second)
+ defer cancel()
+ }
+
+ // normalize URL to start with http://, https:// or without protocol
+ u = nostr.NormalizeURL(u)
+
+ info = RelayInformationDocument{
+ URL: u,
+ }
+
+ // make request
+ req, err := http.NewRequestWithContext(ctx, "GET", "http"+u[2:], nil)
+
+ // add the NIP-11 header
+ req.Header.Add("Accept", "application/nostr+json")
+
+ // send the request
+ resp, err := http.DefaultClient.Do(req)
+ if err != nil {
+ return info, fmt.Errorf("request failed: %w", err)
+ }
+ defer resp.Body.Close()
+
+ if err := json.NewDecoder(resp.Body).Decode(&info); err != nil {
+ return info, fmt.Errorf("invalid json: %w", err)
+ }
+
+ return info, nil
+}
diff --git a/vendor/github.com/nbd-wtf/go-nostr/nip11/types.go b/vendor/github.com/nbd-wtf/go-nostr/nip11/types.go
new file mode 100644
index 0000000..7fa3873
--- /dev/null
+++ b/vendor/github.com/nbd-wtf/go-nostr/nip11/types.go
@@ -0,0 +1,66 @@
+package nip11
+
+import "slices"
+
+type RelayInformationDocument struct {
+ URL string `json:"-"`
+
+ Name string `json:"name"`
+ Description string `json:"description"`
+ PubKey string `json:"pubkey"`
+ Contact string `json:"contact"`
+ SupportedNIPs []int `json:"supported_nips"`
+ Software string `json:"software"`
+ Version string `json:"version"`
+
+ Limitation *RelayLimitationDocument `json:"limitation,omitempty"`
+ RelayCountries []string `json:"relay_countries,omitempty"`
+ LanguageTags []string `json:"language_tags,omitempty"`
+ Tags []string `json:"tags,omitempty"`
+ PostingPolicy string `json:"posting_policy,omitempty"`
+ PaymentsURL string `json:"payments_url,omitempty"`
+ Fees *RelayFeesDocument `json:"fees,omitempty"`
+ Icon string `json:"icon"`
+}
+
+func (info *RelayInformationDocument) AddSupportedNIP(number int) {
+ idx, exists := slices.BinarySearch(info.SupportedNIPs, number)
+ if exists {
+ return
+ }
+
+ info.SupportedNIPs = append(info.SupportedNIPs, -1)
+ copy(info.SupportedNIPs[idx+1:], info.SupportedNIPs[idx:])
+ info.SupportedNIPs[idx] = number
+}
+
+type RelayLimitationDocument struct {
+ MaxMessageLength int `json:"max_message_length,omitempty"`
+ MaxSubscriptions int `json:"max_subscriptions,omitempty"`
+ MaxFilters int `json:"max_filters,omitempty"`
+ MaxLimit int `json:"max_limit,omitempty"`
+ MaxSubidLength int `json:"max_subid_length,omitempty"`
+ MaxEventTags int `json:"max_event_tags,omitempty"`
+ MaxContentLength int `json:"max_content_length,omitempty"`
+ MinPowDifficulty int `json:"min_pow_difficulty,omitempty"`
+ AuthRequired bool `json:"auth_required"`
+ PaymentRequired bool `json:"payment_required"`
+ RestrictedWrites bool `json:"restricted_writes"`
+}
+
+type RelayFeesDocument struct {
+ Admission []struct {
+ Amount int `json:"amount"`
+ Unit string `json:"unit"`
+ } `json:"admission,omitempty"`
+ Subscription []struct {
+ Amount int `json:"amount"`
+ Unit string `json:"unit"`
+ Period int `json:"period"`
+ } `json:"subscription,omitempty"`
+ Publication []struct {
+ Kinds []int `json:"kinds"`
+ Amount int `json:"amount"`
+ Unit string `json:"unit"`
+ } `json:"publication,omitempty"`
+}
diff --git a/vendor/github.com/nbd-wtf/go-nostr/nip42/nip42.go b/vendor/github.com/nbd-wtf/go-nostr/nip42/nip42.go
new file mode 100644
index 0000000..2c05dbc
--- /dev/null
+++ b/vendor/github.com/nbd-wtf/go-nostr/nip42/nip42.go
@@ -0,0 +1,74 @@
+package nip42
+
+import (
+ "net/url"
+ "strings"
+ "time"
+
+ "github.com/nbd-wtf/go-nostr"
+)
+
+// CreateUnsignedAuthEvent creates an event which should be sent via an "AUTH" command.
+// If the authentication succeeds, the user will be authenticated as pubkey.
+func CreateUnsignedAuthEvent(challenge, pubkey, relayURL string) nostr.Event {
+ return nostr.Event{
+ PubKey: pubkey,
+ CreatedAt: nostr.Now(),
+ Kind: nostr.KindClientAuthentication,
+ Tags: nostr.Tags{
+ nostr.Tag{"relay", relayURL},
+ nostr.Tag{"challenge", challenge},
+ },
+ Content: "",
+ }
+}
+
+// helper function for ValidateAuthEvent.
+func parseURL(input string) (*url.URL, error) {
+ return url.Parse(
+ strings.ToLower(
+ strings.TrimSuffix(input, "/"),
+ ),
+ )
+}
+
+// ValidateAuthEvent checks whether event is a valid NIP-42 event for given challenge and relayURL.
+// The result of the validation is encoded in the ok bool.
+func ValidateAuthEvent(event *nostr.Event, challenge string, relayURL string) (pubkey string, ok bool) {
+ if event.Kind != nostr.KindClientAuthentication {
+ return "", false
+ }
+
+ if event.Tags.GetFirst([]string{"challenge", challenge}) == nil {
+ return "", false
+ }
+
+ expected, err := parseURL(relayURL)
+ if err != nil {
+ return "", false
+ }
+
+ found, err := parseURL(event.Tags.GetFirst([]string{"relay", ""}).Value())
+ if err != nil {
+ return "", false
+ }
+
+ if expected.Scheme != found.Scheme ||
+ expected.Host != found.Host ||
+ expected.Path != found.Path {
+ return "", false
+ }
+
+ now := time.Now()
+ if event.CreatedAt.Time().After(now.Add(10*time.Minute)) || event.CreatedAt.Time().Before(now.Add(-10*time.Minute)) {
+ return "", false
+ }
+
+ // save for last, as it is most expensive operation
+ // no need to check returned error, since ok == true implies err == nil.
+ if ok, _ := event.CheckSignature(); !ok {
+ return "", false
+ }
+
+ return event.PubKey, true
+}
diff --git a/vendor/github.com/nbd-wtf/go-nostr/nip86/methods.go b/vendor/github.com/nbd-wtf/go-nostr/nip86/methods.go
new file mode 100644
index 0000000..0797f17
--- /dev/null
+++ b/vendor/github.com/nbd-wtf/go-nostr/nip86/methods.go
@@ -0,0 +1,271 @@
+package nip86
+
+import (
+ "fmt"
+ "math"
+ "net"
+
+ "github.com/nbd-wtf/go-nostr"
+)
+
+func DecodeRequest(req Request) (MethodParams, error) {
+ switch req.Method {
+ case "supportedmethods":
+ return SupportedMethods{}, nil
+ case "banpubkey":
+ if len(req.Params) == 0 {
+ return nil, fmt.Errorf("invalid number of params for '%s'", req.Method)
+ }
+ pk, ok := req.Params[0].(string)
+ if !ok || !nostr.IsValidPublicKey(pk) {
+ return nil, fmt.Errorf("invalid pubkey param for '%s'", req.Method)
+ }
+ var reason string
+ if len(req.Params) >= 2 {
+ reason, _ = req.Params[1].(string)
+ }
+ return BanPubKey{pk, reason}, nil
+ case "listbannedpubkeys":
+ return ListBannedPubKeys{}, nil
+ case "allowpubkey":
+ if len(req.Params) == 0 {
+ return nil, fmt.Errorf("invalid number of params for '%s'", req.Method)
+ }
+ pk, ok := req.Params[0].(string)
+ if !ok || !nostr.IsValidPublicKey(pk) {
+ return nil, fmt.Errorf("invalid pubkey param for '%s'", req.Method)
+ }
+ var reason string
+ if len(req.Params) >= 2 {
+ reason, _ = req.Params[1].(string)
+ }
+ return AllowPubKey{pk, reason}, nil
+ case "listallowedpubkeys":
+ return ListAllowedPubKeys{}, nil
+ case "listeventsneedingmoderation":
+ return ListEventsNeedingModeration{}, nil
+ case "allowevent":
+ if len(req.Params) == 0 {
+ return nil, fmt.Errorf("invalid number of params for '%s'", req.Method)
+ }
+ id, ok := req.Params[0].(string)
+ if !ok || !nostr.IsValid32ByteHex(id) {
+ return nil, fmt.Errorf("invalid id param for '%s'", req.Method)
+ }
+ var reason string
+ if len(req.Params) >= 2 {
+ reason, _ = req.Params[1].(string)
+ }
+ return AllowEvent{id, reason}, nil
+ case "banevent":
+ if len(req.Params) == 0 {
+ return nil, fmt.Errorf("invalid number of params for '%s'", req.Method)
+ }
+ id, ok := req.Params[0].(string)
+ if !ok || !nostr.IsValid32ByteHex(id) {
+ return nil, fmt.Errorf("invalid id param for '%s'", req.Method)
+ }
+ var reason string
+ if len(req.Params) >= 2 {
+ reason, _ = req.Params[1].(string)
+ }
+ return BanEvent{id, reason}, nil
+ case "listbannedevents":
+ return ListBannedEvents{}, nil
+ case "changerelayname":
+ if len(req.Params) == 0 {
+ return nil, fmt.Errorf("invalid number of params for '%s'", req.Method)
+ }
+ name, _ := req.Params[0].(string)
+ return ChangeRelayName{name}, nil
+ case "changerelaydescription":
+ if len(req.Params) == 0 {
+ return nil, fmt.Errorf("invalid number of params for '%s'", req.Method)
+ }
+ desc, _ := req.Params[0].(string)
+ return ChangeRelayDescription{desc}, nil
+ case "changerelayicon":
+ if len(req.Params) == 0 {
+ return nil, fmt.Errorf("invalid number of params for '%s'", req.Method)
+ }
+ url, _ := req.Params[0].(string)
+ return ChangeRelayIcon{url}, nil
+ case "allowkind":
+ if len(req.Params) == 0 {
+ return nil, fmt.Errorf("invalid number of params for '%s'", req.Method)
+ }
+ kind, ok := req.Params[0].(float64)
+ if !ok || math.Trunc(kind) != kind {
+ return nil, fmt.Errorf("invalid kind '%v' for '%s'", req.Params[0], req.Method)
+ }
+ return AllowKind{int(kind)}, nil
+ case "disallowkind":
+ if len(req.Params) == 0 {
+ return nil, fmt.Errorf("invalid number of params for '%s'", req.Method)
+ }
+ kind, ok := req.Params[0].(float64)
+ if !ok || math.Trunc(kind) != kind {
+ return nil, fmt.Errorf("invalid kind '%v' for '%s'", req.Params[0], req.Method)
+ }
+ return DisallowKind{int(kind)}, nil
+ case "listallowedkinds":
+ return ListAllowedKinds{}, nil
+ case "blockip":
+ if len(req.Params) == 0 {
+ return nil, fmt.Errorf("invalid number of params for '%s'", req.Method)
+ }
+ ipstr, _ := req.Params[0].(string)
+ ip := net.ParseIP(ipstr)
+ if ip == nil {
+ return nil, fmt.Errorf("invalid ip param for '%s'", req.Method)
+ }
+ var reason string
+ if len(req.Params) >= 2 {
+ reason, _ = req.Params[1].(string)
+ }
+ return BlockIP{ip, reason}, nil
+ case "unblockip":
+ if len(req.Params) == 0 {
+ return nil, fmt.Errorf("invalid number of params for '%s'", req.Method)
+ }
+ ipstr, _ := req.Params[0].(string)
+ ip := net.ParseIP(ipstr)
+ if ip == nil {
+ return nil, fmt.Errorf("invalid ip param for '%s'", req.Method)
+ }
+ var reason string
+ if len(req.Params) >= 2 {
+ reason, _ = req.Params[1].(string)
+ }
+ return UnblockIP{ip, reason}, nil
+ case "listblockedips":
+ return ListBlockedIPs{}, nil
+ default:
+ return nil, fmt.Errorf("unknown method '%s'", req.Method)
+ }
+}
+
+type MethodParams interface {
+ MethodName() string
+}
+
+var (
+ _ MethodParams = (*SupportedMethods)(nil)
+ _ MethodParams = (*BanPubKey)(nil)
+ _ MethodParams = (*ListBannedPubKeys)(nil)
+ _ MethodParams = (*AllowPubKey)(nil)
+ _ MethodParams = (*ListAllowedPubKeys)(nil)
+ _ MethodParams = (*ListEventsNeedingModeration)(nil)
+ _ MethodParams = (*AllowEvent)(nil)
+ _ MethodParams = (*BanEvent)(nil)
+ _ MethodParams = (*ListBannedEvents)(nil)
+ _ MethodParams = (*ChangeRelayName)(nil)
+ _ MethodParams = (*ChangeRelayDescription)(nil)
+ _ MethodParams = (*ChangeRelayIcon)(nil)
+ _ MethodParams = (*AllowKind)(nil)
+ _ MethodParams = (*DisallowKind)(nil)
+ _ MethodParams = (*ListAllowedKinds)(nil)
+ _ MethodParams = (*BlockIP)(nil)
+ _ MethodParams = (*UnblockIP)(nil)
+ _ MethodParams = (*ListBlockedIPs)(nil)
+)
+
+type SupportedMethods struct{}
+
+func (_ SupportedMethods) MethodName() string { return "supportedmethods" }
+
+type BanPubKey struct {
+ PubKey string
+ Reason string
+}
+
+func (_ BanPubKey) MethodName() string { return "banpubkey" }
+
+type ListBannedPubKeys struct{}
+
+func (_ ListBannedPubKeys) MethodName() string { return "listbannedpubkeys" }
+
+type AllowPubKey struct {
+ PubKey string
+ Reason string
+}
+
+func (_ AllowPubKey) MethodName() string { return "allowpubkey" }
+
+type ListAllowedPubKeys struct{}
+
+func (_ ListAllowedPubKeys) MethodName() string { return "listallowedpubkeys" }
+
+type ListEventsNeedingModeration struct{}
+
+func (_ ListEventsNeedingModeration) MethodName() string { return "listeventsneedingmoderation" }
+
+type AllowEvent struct {
+ ID string
+ Reason string
+}
+
+func (_ AllowEvent) MethodName() string { return "allowevent" }
+
+type BanEvent struct {
+ ID string
+ Reason string
+}
+
+func (_ BanEvent) MethodName() string { return "banevent" }
+
+type ListBannedEvents struct{}
+
+func (_ ListBannedEvents) MethodName() string { return "listbannedevents" }
+
+type ChangeRelayName struct {
+ Name string
+}
+
+func (_ ChangeRelayName) MethodName() string { return "changerelayname" }
+
+type ChangeRelayDescription struct {
+ Description string
+}
+
+func (_ ChangeRelayDescription) MethodName() string { return "changerelaydescription" }
+
+type ChangeRelayIcon struct {
+ IconURL string
+}
+
+func (_ ChangeRelayIcon) MethodName() string { return "changerelayicon" }
+
+type AllowKind struct {
+ Kind int
+}
+
+func (_ AllowKind) MethodName() string { return "allowkind" }
+
+type DisallowKind struct {
+ Kind int
+}
+
+func (_ DisallowKind) MethodName() string { return "disallowkind" }
+
+type ListAllowedKinds struct{}
+
+func (_ ListAllowedKinds) MethodName() string { return "listallowedkinds" }
+
+type BlockIP struct {
+ IP net.IP
+ Reason string
+}
+
+func (_ BlockIP) MethodName() string { return "blockip" }
+
+type UnblockIP struct {
+ IP net.IP
+ Reason string
+}
+
+func (_ UnblockIP) MethodName() string { return "unblockip" }
+
+type ListBlockedIPs struct{}
+
+func (_ ListBlockedIPs) MethodName() string { return "listblockedips" }
diff --git a/vendor/github.com/nbd-wtf/go-nostr/nip86/responses.go b/vendor/github.com/nbd-wtf/go-nostr/nip86/responses.go
new file mode 100644
index 0000000..126b674
--- /dev/null
+++ b/vendor/github.com/nbd-wtf/go-nostr/nip86/responses.go
@@ -0,0 +1,16 @@
+package nip86
+
+type IDReason struct {
+ ID string `json:"id"`
+ Reason string `json:"reason"`
+}
+
+type PubKeyReason struct {
+ PubKey string `json:"pubkey"`
+ Reason string `json:"reason"`
+}
+
+type IPReason struct {
+ IP string `json:"ip"`
+ Reason string `json:"reason"`
+}
diff --git a/vendor/github.com/nbd-wtf/go-nostr/nip86/types.go b/vendor/github.com/nbd-wtf/go-nostr/nip86/types.go
new file mode 100644
index 0000000..c1ace3c
--- /dev/null
+++ b/vendor/github.com/nbd-wtf/go-nostr/nip86/types.go
@@ -0,0 +1,11 @@
+package nip86
+
+type Request struct {
+ Method string `json:"method"`
+ Params []any `json:"params"`
+}
+
+type Response struct {
+ Result any `json:"result,omitempty"`
+ Error string `json:"error,omitempty"`
+}
diff --git a/vendor/github.com/nbd-wtf/go-nostr/normalize.go b/vendor/github.com/nbd-wtf/go-nostr/normalize.go
new file mode 100644
index 0000000..6d5ce07
--- /dev/null
+++ b/vendor/github.com/nbd-wtf/go-nostr/normalize.go
@@ -0,0 +1,47 @@
+package nostr
+
+import (
+ "net/url"
+ "strings"
+)
+
+// NormalizeURL normalizes the url and replaces http://, https:// schemes with ws://, wss://
+// and normalizes the path.
+func NormalizeURL(u string) string {
+ if u == "" {
+ return ""
+ }
+
+ u = strings.TrimSpace(u)
+ u = strings.ToLower(u)
+
+ if fqn := strings.Split(u, ":")[0]; fqn == "localhost" || fqn == "127.0.0.1" {
+ u = "ws://" + u
+ } else if !strings.HasPrefix(u, "http") && !strings.HasPrefix(u, "ws") {
+ u = "wss://" + u
+ }
+
+ p, err := url.Parse(u)
+ if err != nil {
+ return ""
+ }
+
+ if p.Scheme == "http" {
+ p.Scheme = "ws"
+ } else if p.Scheme == "https" {
+ p.Scheme = "wss"
+ }
+
+ p.Path = strings.TrimRight(p.Path, "/")
+
+ return p.String()
+}
+
+// NormalizeOKMessage takes a string message that is to be sent in an `OK` or `CLOSED` command
+// and prefixes it with ": " if it doesn't already have an acceptable prefix.
+func NormalizeOKMessage(reason string, prefix string) string {
+ if idx := strings.Index(reason, ": "); idx == -1 || strings.IndexByte(reason[0:idx], ' ') != -1 {
+ return prefix + ": " + reason
+ }
+ return reason
+}
diff --git a/vendor/github.com/nbd-wtf/go-nostr/pointers.go b/vendor/github.com/nbd-wtf/go-nostr/pointers.go
new file mode 100644
index 0000000..9f4da04
--- /dev/null
+++ b/vendor/github.com/nbd-wtf/go-nostr/pointers.go
@@ -0,0 +1,20 @@
+package nostr
+
+type ProfilePointer struct {
+ PublicKey string `json:"pubkey"`
+ Relays []string `json:"relays,omitempty"`
+}
+
+type EventPointer struct {
+ ID string `json:"id"`
+ Relays []string `json:"relays,omitempty"`
+ Author string `json:"author,omitempty"`
+ Kind int `json:"kind,omitempty"`
+}
+
+type EntityPointer struct {
+ PublicKey string `json:"pubkey"`
+ Kind int `json:"kind,omitempty"`
+ Identifier string `json:"identifier,omitempty"`
+ Relays []string `json:"relays,omitempty"`
+}
diff --git a/vendor/github.com/nbd-wtf/go-nostr/pool.go b/vendor/github.com/nbd-wtf/go-nostr/pool.go
new file mode 100644
index 0000000..846d176
--- /dev/null
+++ b/vendor/github.com/nbd-wtf/go-nostr/pool.go
@@ -0,0 +1,437 @@
+package nostr
+
+import (
+ "context"
+ "fmt"
+ "log"
+ "math"
+ "slices"
+ "strings"
+ "sync"
+ "time"
+
+ "github.com/puzpuzpuz/xsync/v3"
+)
+
+const (
+ seenAlreadyDropTick = time.Minute
+)
+
+type SimplePool struct {
+ Relays *xsync.MapOf[string, *Relay]
+ Context context.Context
+
+ authHandler func(*Event) error
+ cancel context.CancelFunc
+
+ eventMiddleware []func(IncomingEvent)
+
+ // custom things not often used
+ signatureChecker func(Event) bool
+ penaltyBoxMu sync.Mutex
+ penaltyBox map[string][2]float64
+}
+
+type DirectedFilters struct {
+ Filters
+ Relay string
+}
+
+type IncomingEvent struct {
+ *Event
+ Relay *Relay
+}
+
+func (ie IncomingEvent) String() string {
+ return fmt.Sprintf("[%s] >> %s", ie.Relay.URL, ie.Event)
+}
+
+type PoolOption interface {
+ ApplyPoolOption(*SimplePool)
+}
+
+func NewSimplePool(ctx context.Context, opts ...PoolOption) *SimplePool {
+ ctx, cancel := context.WithCancel(ctx)
+
+ pool := &SimplePool{
+ Relays: xsync.NewMapOf[string, *Relay](),
+
+ Context: ctx,
+ cancel: cancel,
+ }
+
+ for _, opt := range opts {
+ opt.ApplyPoolOption(pool)
+ }
+
+ return pool
+}
+
+// WithAuthHandler must be a function that signs the auth event when called.
+// it will be called whenever any relay in the pool returns a `CLOSED` message
+// with the "auth-required:" prefix, only once for each relay
+type WithAuthHandler func(authEvent *Event) error
+
+func (h WithAuthHandler) ApplyPoolOption(pool *SimplePool) {
+ pool.authHandler = h
+}
+
+// WithPenaltyBox just sets the penalty box mechanism so relays that fail to connect
+// or that disconnect will be ignored for a while and we won't attempt to connect again.
+func WithPenaltyBox() withPenaltyBoxOpt { return withPenaltyBoxOpt{} }
+
+type withPenaltyBoxOpt struct{}
+
+func (h withPenaltyBoxOpt) ApplyPoolOption(pool *SimplePool) {
+ pool.penaltyBox = make(map[string][2]float64)
+ go func() {
+ sleep := 30.0
+ for {
+ time.Sleep(time.Duration(sleep) * time.Second)
+
+ pool.penaltyBoxMu.Lock()
+ nextSleep := 300.0
+ for url, v := range pool.penaltyBox {
+ remainingSeconds := v[1]
+ remainingSeconds -= sleep
+ if remainingSeconds <= 0 {
+ pool.penaltyBox[url] = [2]float64{v[0], 0}
+ continue
+ } else {
+ pool.penaltyBox[url] = [2]float64{v[0], remainingSeconds}
+ }
+
+ if remainingSeconds < nextSleep {
+ nextSleep = remainingSeconds
+ }
+ }
+
+ sleep = nextSleep
+ pool.penaltyBoxMu.Unlock()
+ }
+ }()
+}
+
+// WithEventMiddleware is a function that will be called with all events received.
+// more than one can be passed at a time.
+type WithEventMiddleware func(IncomingEvent)
+
+func (h WithEventMiddleware) ApplyPoolOption(pool *SimplePool) {
+ pool.eventMiddleware = append(pool.eventMiddleware, h)
+}
+
+var (
+ _ PoolOption = (WithAuthHandler)(nil)
+ _ PoolOption = (WithEventMiddleware)(nil)
+ _ PoolOption = WithPenaltyBox()
+)
+
+func (pool *SimplePool) EnsureRelay(url string) (*Relay, error) {
+ nm := NormalizeURL(url)
+ defer namedLock(nm)()
+
+ relay, ok := pool.Relays.Load(nm)
+ if ok && relay == nil {
+ if pool.penaltyBox != nil {
+ pool.penaltyBoxMu.Lock()
+ defer pool.penaltyBoxMu.Unlock()
+ v, _ := pool.penaltyBox[nm]
+ if v[1] > 0 {
+ return nil, fmt.Errorf("in penalty box, %fs remaining", v[1])
+ }
+ }
+ } else if ok && relay.IsConnected() {
+ // already connected, unlock and return
+ return relay, nil
+ }
+
+ // try to connect
+ var err error
+ // we use this ctx here so when the pool dies everything dies
+ ctx, cancel := context.WithTimeout(pool.Context, time.Second*15)
+ defer cancel()
+
+ opts := make([]RelayOption, 0, 1+len(pool.eventMiddleware))
+ if pool.signatureChecker != nil {
+ opts = append(opts, WithSignatureChecker(pool.signatureChecker))
+ }
+
+ if relay, err = RelayConnect(ctx, nm, opts...); err != nil {
+ if pool.penaltyBox != nil {
+ // putting relay in penalty box
+ pool.penaltyBoxMu.Lock()
+ defer pool.penaltyBoxMu.Unlock()
+ v, _ := pool.penaltyBox[nm]
+ pool.penaltyBox[nm] = [2]float64{v[0] + 1, 30.0 + math.Pow(2, v[0]+1)}
+ }
+ return nil, fmt.Errorf("failed to connect: %w", err)
+ }
+
+ pool.Relays.Store(nm, relay)
+ return relay, nil
+}
+
+// SubMany opens a subscription with the given filters to multiple relays
+// the subscriptions only end when the context is canceled
+func (pool *SimplePool) SubMany(ctx context.Context, urls []string, filters Filters) chan IncomingEvent {
+ return pool.subMany(ctx, urls, filters, true)
+}
+
+// SubManyNonUnique is like SubMany, but returns duplicate events if they come from different relays
+func (pool *SimplePool) SubManyNonUnique(ctx context.Context, urls []string, filters Filters) chan IncomingEvent {
+ return pool.subMany(ctx, urls, filters, false)
+}
+
+func (pool *SimplePool) subMany(ctx context.Context, urls []string, filters Filters, unique bool) chan IncomingEvent {
+ ctx, cancel := context.WithCancel(ctx)
+ _ = cancel // do this so `go vet` will stop complaining
+ events := make(chan IncomingEvent)
+ seenAlready := xsync.NewMapOf[string, Timestamp]()
+ ticker := time.NewTicker(seenAlreadyDropTick)
+
+ eose := false
+
+ pending := xsync.NewCounter()
+ pending.Add(int64(len(urls)))
+ for i, url := range urls {
+ url = NormalizeURL(url)
+ urls[i] = url
+ if idx := slices.Index(urls, url); idx != i {
+ // skip duplicate relays in the list
+ continue
+ }
+
+ go func(nm string) {
+ defer func() {
+ pending.Dec()
+ if pending.Value() == 0 {
+ close(events)
+ }
+ cancel()
+ }()
+
+ hasAuthed := false
+ interval := 3 * time.Second
+ for {
+ select {
+ case <-ctx.Done():
+ return
+ default:
+ }
+
+ var sub *Subscription
+
+ relay, err := pool.EnsureRelay(nm)
+ if err != nil {
+ goto reconnect
+ }
+ hasAuthed = false
+
+ subscribe:
+ sub, err = relay.Subscribe(ctx, filters)
+ if err != nil {
+ goto reconnect
+ }
+
+ go func() {
+ <-sub.EndOfStoredEvents
+ eose = true
+ }()
+
+ // reset interval when we get a good subscription
+ interval = 3 * time.Second
+
+ for {
+ select {
+ case evt, more := <-sub.Events:
+ if !more {
+ // this means the connection was closed for weird reasons, like the server shut down
+ // so we will update the filters here to include only events seem from now on
+ // and try to reconnect until we succeed
+ now := Now()
+ for i := range filters {
+ filters[i].Since = &now
+ }
+ goto reconnect
+ }
+
+ ie := IncomingEvent{Event: evt, Relay: relay}
+ for _, mh := range pool.eventMiddleware {
+ mh(ie)
+ }
+
+ if unique {
+ if _, seen := seenAlready.LoadOrStore(evt.ID, evt.CreatedAt); seen {
+ continue
+ }
+ }
+
+ select {
+ case events <- ie:
+ case <-ctx.Done():
+ return
+ }
+ case <-ticker.C:
+ if eose {
+ old := Timestamp(time.Now().Add(-seenAlreadyDropTick).Unix())
+ seenAlready.Range(func(id string, value Timestamp) bool {
+ if value < old {
+ seenAlready.Delete(id)
+ }
+ return true
+ })
+ }
+ case reason := <-sub.ClosedReason:
+ if strings.HasPrefix(reason, "auth-required:") && pool.authHandler != nil && !hasAuthed {
+ // relay is requesting auth. if we can we will perform auth and try again
+ if err := relay.Auth(ctx, pool.authHandler); err == nil {
+ hasAuthed = true // so we don't keep doing AUTH again and again
+ goto subscribe
+ }
+ } else {
+ log.Printf("CLOSED from %s: '%s'\n", nm, reason)
+ }
+ return
+ case <-ctx.Done():
+ return
+ }
+ }
+
+ reconnect:
+ // we will go back to the beginning of the loop and try to connect again and again
+ // until the context is canceled
+ time.Sleep(interval)
+ interval = interval * 17 / 10 // the next time we try we will wait longer
+ }
+ }(url)
+ }
+
+ return events
+}
+
+// SubManyEose is like SubMany, but it stops subscriptions and closes the channel when gets a EOSE
+func (pool *SimplePool) SubManyEose(ctx context.Context, urls []string, filters Filters) chan IncomingEvent {
+ return pool.subManyEose(ctx, urls, filters, true)
+}
+
+// SubManyEoseNonUnique is like SubManyEose, but returns duplicate events if they come from different relays
+func (pool *SimplePool) SubManyEoseNonUnique(ctx context.Context, urls []string, filters Filters) chan IncomingEvent {
+ return pool.subManyEose(ctx, urls, filters, false)
+}
+
+func (pool *SimplePool) subManyEose(ctx context.Context, urls []string, filters Filters, unique bool) chan IncomingEvent {
+ ctx, cancel := context.WithCancel(ctx)
+
+ events := make(chan IncomingEvent)
+ seenAlready := xsync.NewMapOf[string, bool]()
+ wg := sync.WaitGroup{}
+ wg.Add(len(urls))
+
+ go func() {
+ // this will happen when all subscriptions get an eose (or when they die)
+ wg.Wait()
+ cancel()
+ close(events)
+ }()
+
+ for _, url := range urls {
+ go func(nm string) {
+ defer wg.Done()
+
+ relay, err := pool.EnsureRelay(nm)
+ if err != nil {
+ return
+ }
+
+ hasAuthed := false
+
+ subscribe:
+ sub, err := relay.Subscribe(ctx, filters)
+ if sub == nil {
+ debugLogf("error subscribing to %s with %v: %s", relay, filters, err)
+ return
+ }
+
+ for {
+ select {
+ case <-ctx.Done():
+ return
+ case <-sub.EndOfStoredEvents:
+ return
+ case reason := <-sub.ClosedReason:
+ if strings.HasPrefix(reason, "auth-required:") && pool.authHandler != nil && !hasAuthed {
+ // relay is requesting auth. if we can we will perform auth and try again
+ err := relay.Auth(ctx, pool.authHandler)
+ if err == nil {
+ hasAuthed = true // so we don't keep doing AUTH again and again
+ goto subscribe
+ }
+ }
+ log.Printf("CLOSED from %s: '%s'\n", nm, reason)
+ return
+ case evt, more := <-sub.Events:
+ if !more {
+ return
+ }
+
+ ie := IncomingEvent{Event: evt, Relay: relay}
+ for _, mh := range pool.eventMiddleware {
+ mh(ie)
+ }
+
+ if unique {
+ if _, seen := seenAlready.LoadOrStore(evt.ID, true); seen {
+ continue
+ }
+ }
+
+ select {
+ case events <- ie:
+ case <-ctx.Done():
+ return
+ }
+ }
+ }
+ }(NormalizeURL(url))
+ }
+
+ return events
+}
+
+// QuerySingle returns the first event returned by the first relay, cancels everything else.
+func (pool *SimplePool) QuerySingle(ctx context.Context, urls []string, filter Filter) *IncomingEvent {
+ ctx, cancel := context.WithCancel(ctx)
+ defer cancel()
+ for ievt := range pool.SubManyEose(ctx, urls, Filters{filter}) {
+ return &ievt
+ }
+ return nil
+}
+
+func (pool *SimplePool) batchedSubMany(
+ ctx context.Context,
+ dfs []DirectedFilters,
+ subFn func(context.Context, []string, Filters, bool) chan IncomingEvent,
+) chan IncomingEvent {
+ res := make(chan IncomingEvent)
+
+ for _, df := range dfs {
+ go func(df DirectedFilters) {
+ for ie := range subFn(ctx, []string{df.Relay}, df.Filters, true) {
+ res <- ie
+ }
+ }(df)
+ }
+
+ return res
+}
+
+// BatchedSubMany fires subscriptions only to specific relays, but batches them when they are the same.
+func (pool *SimplePool) BatchedSubMany(ctx context.Context, dfs []DirectedFilters) chan IncomingEvent {
+ return pool.batchedSubMany(ctx, dfs, pool.subMany)
+}
+
+// BatchedSubManyEose is like BatchedSubMany, but ends upon receiving EOSE from all relays.
+func (pool *SimplePool) BatchedSubManyEose(ctx context.Context, dfs []DirectedFilters) chan IncomingEvent {
+ return pool.batchedSubMany(ctx, dfs, pool.subManyEose)
+}
diff --git a/vendor/github.com/nbd-wtf/go-nostr/relay.go b/vendor/github.com/nbd-wtf/go-nostr/relay.go
new file mode 100644
index 0000000..ce44268
--- /dev/null
+++ b/vendor/github.com/nbd-wtf/go-nostr/relay.go
@@ -0,0 +1,522 @@
+package nostr
+
+import (
+ "bytes"
+ "context"
+ "crypto/tls"
+ "fmt"
+ "log"
+ "net/http"
+ "sync"
+ "sync/atomic"
+ "time"
+
+ "github.com/gobwas/ws"
+ "github.com/gobwas/ws/wsutil"
+ "github.com/puzpuzpuz/xsync/v3"
+)
+
+type Status int
+
+var subscriptionIDCounter atomic.Int32
+
+type Relay struct {
+ closeMutex sync.Mutex
+
+ URL string
+ RequestHeader http.Header // e.g. for origin header
+
+ Connection *Connection
+ Subscriptions *xsync.MapOf[string, *Subscription]
+
+ ConnectionError error
+ connectionContext context.Context // will be canceled when the connection closes
+ connectionContextCancel context.CancelFunc
+
+ challenge string // NIP-42 challenge, we only keep the last
+ noticeHandler func(string) // NIP-01 NOTICEs
+ customHandler func([]byte) // nonstandard unparseable messages
+ okCallbacks *xsync.MapOf[string, func(bool, string)]
+ writeQueue chan writeRequest
+ subscriptionChannelCloseQueue chan *Subscription
+ signatureChecker func(Event) bool
+
+ // custom things that aren't often used
+ //
+ AssumeValid bool // this will skip verifying signatures for events received from this relay
+}
+
+type writeRequest struct {
+ msg []byte
+ answer chan error
+}
+
+// NewRelay returns a new relay. The relay connection will be closed when the context is canceled.
+func NewRelay(ctx context.Context, url string, opts ...RelayOption) *Relay {
+ ctx, cancel := context.WithCancel(ctx)
+ r := &Relay{
+ URL: NormalizeURL(url),
+ connectionContext: ctx,
+ connectionContextCancel: cancel,
+ Subscriptions: xsync.NewMapOf[string, *Subscription](),
+ okCallbacks: xsync.NewMapOf[string, func(bool, string)](),
+ writeQueue: make(chan writeRequest),
+ subscriptionChannelCloseQueue: make(chan *Subscription),
+ signatureChecker: func(e Event) bool {
+ ok, _ := e.CheckSignature()
+ return ok
+ },
+ }
+
+ for _, opt := range opts {
+ opt.ApplyRelayOption(r)
+ }
+
+ return r
+}
+
+// RelayConnect returns a relay object connected to url.
+// Once successfully connected, cancelling ctx has no effect.
+// To close the connection, call r.Close().
+func RelayConnect(ctx context.Context, url string, opts ...RelayOption) (*Relay, error) {
+ r := NewRelay(context.Background(), url, opts...)
+ err := r.Connect(ctx)
+ return r, err
+}
+
+// When instantiating relay connections, some options may be passed.
+// RelayOption is the type of the argument passed for that.
+type RelayOption interface {
+ ApplyRelayOption(*Relay)
+}
+
+var (
+ _ RelayOption = (WithNoticeHandler)(nil)
+ _ RelayOption = (WithSignatureChecker)(nil)
+ _ RelayOption = (WithCustomHandler)(nil)
+)
+
+// WithNoticeHandler just takes notices and is expected to do something with them.
+// when not given, defaults to logging the notices.
+type WithNoticeHandler func(notice string)
+
+func (nh WithNoticeHandler) ApplyRelayOption(r *Relay) {
+ r.noticeHandler = nh
+}
+
+// WithSignatureChecker must be a function that checks the signature of an
+// event and returns true or false.
+type WithSignatureChecker func(Event) bool
+
+func (sc WithSignatureChecker) ApplyRelayOption(r *Relay) {
+ r.signatureChecker = sc
+}
+
+// WithCustomHandler must be a function that handles any relay message that couldn't be
+// parsed as a standard envelope.
+type WithCustomHandler func(data []byte)
+
+func (ch WithCustomHandler) ApplyRelayOption(r *Relay) {
+ r.customHandler = ch
+}
+
+// String just returns the relay URL.
+func (r *Relay) String() string {
+ return r.URL
+}
+
+// Context retrieves the context that is associated with this relay connection.
+func (r *Relay) Context() context.Context { return r.connectionContext }
+
+// IsConnected returns true if the connection to this relay seems to be active.
+func (r *Relay) IsConnected() bool { return r.connectionContext.Err() == nil }
+
+// Connect tries to establish a websocket connection to r.URL.
+// If the context expires before the connection is complete, an error is returned.
+// Once successfully connected, context expiration has no effect: call r.Close
+// to close the connection.
+//
+// The underlying relay connection will use a background context. If you want to
+// pass a custom context to the underlying relay connection, use NewRelay() and
+// then Relay.Connect().
+func (r *Relay) Connect(ctx context.Context) error {
+ return r.ConnectWithTLS(ctx, nil)
+}
+
+// ConnectWithTLS tries to establish a secured websocket connection to r.URL using customized tls.Config (CA's, etc).
+func (r *Relay) ConnectWithTLS(ctx context.Context, tlsConfig *tls.Config) error {
+ if r.connectionContext == nil || r.Subscriptions == nil {
+ return fmt.Errorf("relay must be initialized with a call to NewRelay()")
+ }
+
+ if r.URL == "" {
+ return fmt.Errorf("invalid relay URL '%s'", r.URL)
+ }
+
+ if _, ok := ctx.Deadline(); !ok {
+ // if no timeout is set, force it to 7 seconds
+ var cancel context.CancelFunc
+ ctx, cancel = context.WithTimeout(ctx, 7*time.Second)
+ defer cancel()
+ }
+
+ conn, err := NewConnection(ctx, r.URL, r.RequestHeader, tlsConfig)
+ if err != nil {
+ return fmt.Errorf("error opening websocket to '%s': %w", r.URL, err)
+ }
+ r.Connection = conn
+
+ // ping every 29 seconds
+ ticker := time.NewTicker(29 * time.Second)
+
+ // to be used when the connection is closed
+ go func() {
+ <-r.connectionContext.Done()
+
+ // stop the ticker
+ ticker.Stop()
+ // close all subscriptions
+ r.Subscriptions.Range(func(_ string, sub *Subscription) bool {
+ go sub.Unsub()
+ return true
+ })
+ }()
+
+ // queue all write operations here so we don't do mutex spaghetti
+ go func() {
+ for {
+ select {
+ case <-ticker.C:
+ err := wsutil.WriteClientMessage(r.Connection.conn, ws.OpPing, nil)
+ if err != nil {
+ InfoLogger.Printf("{%s} error writing ping: %v; closing websocket", r.URL, err)
+ r.Close() // this should trigger a context cancelation
+ return
+ }
+ case writeRequest := <-r.writeQueue:
+ // all write requests will go through this to prevent races
+ debugLogf("{%s} sending %v\n", r.URL, string(writeRequest.msg))
+ if err := r.Connection.WriteMessage(r.connectionContext, writeRequest.msg); err != nil {
+ writeRequest.answer <- err
+ }
+ close(writeRequest.answer)
+ case <-r.connectionContext.Done():
+ // stop here
+ return
+ }
+ }
+ }()
+
+ // general message reader loop
+ go func() {
+ buf := new(bytes.Buffer)
+
+ for {
+ buf.Reset()
+ if err := conn.ReadMessage(r.connectionContext, buf); err != nil {
+ r.ConnectionError = err
+ r.Close()
+ break
+ }
+
+ message := buf.Bytes()
+ debugLogf("{%s} %v\n", r.URL, message)
+ envelope := ParseMessage(message)
+ if envelope == nil {
+ if r.customHandler != nil {
+ r.customHandler(message)
+ }
+ continue
+ }
+
+ switch env := envelope.(type) {
+ case *NoticeEnvelope:
+ // see WithNoticeHandler
+ if r.noticeHandler != nil {
+ r.noticeHandler(string(*env))
+ } else {
+ log.Printf("NOTICE from %s: '%s'\n", r.URL, string(*env))
+ }
+ case *AuthEnvelope:
+ if env.Challenge == nil {
+ continue
+ }
+ r.challenge = *env.Challenge
+ case *EventEnvelope:
+ if env.SubscriptionID == nil {
+ continue
+ }
+ if subscription, ok := r.Subscriptions.Load(*env.SubscriptionID); !ok {
+ // InfoLogger.Printf("{%s} no subscription with id '%s'\n", r.URL, *env.SubscriptionID)
+ continue
+ } else {
+ // check if the event matches the desired filter, ignore otherwise
+ if !subscription.match(&env.Event) {
+ InfoLogger.Printf("{%s} filter does not match: %v ~ %v\n", r.URL, subscription.Filters, env.Event)
+ continue
+ }
+
+ // check signature, ignore invalid, except from trusted (AssumeValid) relays
+ if !r.AssumeValid {
+ if ok := r.signatureChecker(env.Event); !ok {
+ InfoLogger.Printf("{%s} bad signature on %s\n", r.URL, env.Event.ID)
+ continue
+ }
+ }
+
+ // dispatch this to the internal .events channel of the subscription
+ subscription.dispatchEvent(&env.Event)
+ }
+ case *EOSEEnvelope:
+ if subscription, ok := r.Subscriptions.Load(string(*env)); ok {
+ subscription.dispatchEose()
+ }
+ case *ClosedEnvelope:
+ if subscription, ok := r.Subscriptions.Load(string(env.SubscriptionID)); ok {
+ subscription.dispatchClosed(env.Reason)
+ }
+ case *CountEnvelope:
+ if subscription, ok := r.Subscriptions.Load(string(env.SubscriptionID)); ok && env.Count != nil && subscription.countResult != nil {
+ subscription.countResult <- *env.Count
+ }
+ case *OKEnvelope:
+ if okCallback, exist := r.okCallbacks.Load(env.EventID); exist {
+ okCallback(env.OK, env.Reason)
+ } else {
+ InfoLogger.Printf("{%s} got an unexpected OK message for event %s", r.URL, env.EventID)
+ }
+ }
+ }
+ }()
+
+ return nil
+}
+
+// Write queues a message to be sent to the relay.
+func (r *Relay) Write(msg []byte) <-chan error {
+ ch := make(chan error)
+ select {
+ case r.writeQueue <- writeRequest{msg: msg, answer: ch}:
+ case <-r.connectionContext.Done():
+ go func() { ch <- fmt.Errorf("connection closed") }()
+ }
+ return ch
+}
+
+// Publish sends an "EVENT" command to the relay r as in NIP-01 and waits for an OK response.
+func (r *Relay) Publish(ctx context.Context, event Event) error {
+ return r.publish(ctx, event.ID, &EventEnvelope{Event: event})
+}
+
+// Auth sends an "AUTH" command client->relay as in NIP-42 and waits for an OK response.
+func (r *Relay) Auth(ctx context.Context, sign func(event *Event) error) error {
+ authEvent := Event{
+ CreatedAt: Now(),
+ Kind: KindClientAuthentication,
+ Tags: Tags{
+ Tag{"relay", r.URL},
+ Tag{"challenge", r.challenge},
+ },
+ Content: "",
+ }
+ if err := sign(&authEvent); err != nil {
+ return fmt.Errorf("error signing auth event: %w", err)
+ }
+
+ return r.publish(ctx, authEvent.ID, &AuthEnvelope{Event: authEvent})
+}
+
+// publish can be used both for EVENT and for AUTH
+func (r *Relay) publish(ctx context.Context, id string, env Envelope) error {
+ var err error
+ var cancel context.CancelFunc
+
+ if _, ok := ctx.Deadline(); !ok {
+ // if no timeout is set, force it to 7 seconds
+ ctx, cancel = context.WithTimeoutCause(ctx, 7*time.Second, fmt.Errorf("given up waiting for an OK"))
+ defer cancel()
+ } else {
+ // otherwise make the context cancellable so we can stop everything upon receiving an "OK"
+ ctx, cancel = context.WithCancel(ctx)
+ defer cancel()
+ }
+
+ // listen for an OK callback
+ gotOk := false
+ r.okCallbacks.Store(id, func(ok bool, reason string) {
+ gotOk = true
+ if !ok {
+ err = fmt.Errorf("msg: %s", reason)
+ }
+ cancel()
+ })
+ defer r.okCallbacks.Delete(id)
+
+ // publish event
+ envb, _ := env.MarshalJSON()
+ if err := <-r.Write(envb); err != nil {
+ return err
+ }
+
+ for {
+ select {
+ case <-ctx.Done():
+ // this will be called when we get an OK or when the context has been canceled
+ if gotOk {
+ return err
+ }
+ return ctx.Err()
+ case <-r.connectionContext.Done():
+ // this is caused when we lose connectivity
+ return err
+ }
+ }
+}
+
+// Subscribe sends a "REQ" command to the relay r as in NIP-01.
+// Events are returned through the channel sub.Events.
+// The subscription is closed when context ctx is cancelled ("CLOSE" in NIP-01).
+//
+// Remember to cancel subscriptions, either by calling `.Unsub()` on them or ensuring their `context.Context` will be canceled at some point.
+// Failure to do that will result in a huge number of halted goroutines being created.
+func (r *Relay) Subscribe(ctx context.Context, filters Filters, opts ...SubscriptionOption) (*Subscription, error) {
+ sub := r.PrepareSubscription(ctx, filters, opts...)
+
+ if r.Connection == nil {
+ return nil, fmt.Errorf("not connected to %s", r.URL)
+ }
+
+ if err := sub.Fire(); err != nil {
+ return nil, fmt.Errorf("couldn't subscribe to %v at %s: %w", filters, r.URL, err)
+ }
+
+ return sub, nil
+}
+
+// PrepareSubscription creates a subscription, but doesn't fire it.
+//
+// Remember to cancel subscriptions, either by calling `.Unsub()` on them or ensuring their `context.Context` will be canceled at some point.
+// Failure to do that will result in a huge number of halted goroutines being created.
+func (r *Relay) PrepareSubscription(ctx context.Context, filters Filters, opts ...SubscriptionOption) *Subscription {
+ current := subscriptionIDCounter.Add(1)
+ ctx, cancel := context.WithCancel(ctx)
+
+ sub := &Subscription{
+ Relay: r,
+ Context: ctx,
+ cancel: cancel,
+ counter: int(current),
+ Events: make(chan *Event),
+ EndOfStoredEvents: make(chan struct{}, 1),
+ ClosedReason: make(chan string, 1),
+ Filters: filters,
+ match: filters.Match,
+ }
+
+ for _, opt := range opts {
+ switch o := opt.(type) {
+ case WithLabel:
+ sub.label = string(o)
+ }
+ }
+
+ id := sub.GetID()
+ r.Subscriptions.Store(id, sub)
+
+ // start handling events, eose, unsub etc:
+ go sub.start()
+
+ return sub
+}
+
+func (r *Relay) QueryEvents(ctx context.Context, filter Filter) (chan *Event, error) {
+ sub, err := r.Subscribe(ctx, Filters{filter})
+ if err != nil {
+ return nil, err
+ }
+
+ go func() {
+ for {
+ select {
+ case <-sub.ClosedReason:
+ case <-sub.EndOfStoredEvents:
+ case <-ctx.Done():
+ case <-r.Context().Done():
+ }
+ sub.Unsub()
+ }
+ }()
+
+ return sub.Events, nil
+}
+
+func (r *Relay) QuerySync(ctx context.Context, filter Filter) ([]*Event, error) {
+ if _, ok := ctx.Deadline(); !ok {
+ // if no timeout is set, force it to 7 seconds
+ var cancel context.CancelFunc
+ ctx, cancel = context.WithTimeout(ctx, 7*time.Second)
+ defer cancel()
+ }
+
+ events := make([]*Event, 0, max(filter.Limit, 250))
+ ch, err := r.QueryEvents(ctx, filter)
+ if err != nil {
+ return nil, err
+ }
+
+ for evt := range ch {
+ events = append(events, evt)
+ }
+
+ return events, nil
+}
+
+func (r *Relay) Count(ctx context.Context, filters Filters, opts ...SubscriptionOption) (int64, error) {
+ sub := r.PrepareSubscription(ctx, filters, opts...)
+ sub.countResult = make(chan int64)
+
+ if err := sub.Fire(); err != nil {
+ return 0, err
+ }
+
+ defer sub.Unsub()
+
+ if _, ok := ctx.Deadline(); !ok {
+ // if no timeout is set, force it to 7 seconds
+ var cancel context.CancelFunc
+ ctx, cancel = context.WithTimeout(ctx, 7*time.Second)
+ defer cancel()
+ }
+
+ for {
+ select {
+ case count := <-sub.countResult:
+ return count, nil
+ case <-ctx.Done():
+ return 0, ctx.Err()
+ }
+ }
+}
+
+func (r *Relay) Close() error {
+ r.closeMutex.Lock()
+ defer r.closeMutex.Unlock()
+
+ if r.connectionContextCancel == nil {
+ return fmt.Errorf("relay already closed")
+ }
+ r.connectionContextCancel()
+ r.connectionContextCancel = nil
+
+ if r.Connection == nil {
+ return fmt.Errorf("relay not connected")
+ }
+
+ err := r.Connection.Close()
+ r.Connection = nil
+ if err != nil {
+ return err
+ }
+
+ return nil
+}
diff --git a/vendor/github.com/nbd-wtf/go-nostr/subscription.go b/vendor/github.com/nbd-wtf/go-nostr/subscription.go
new file mode 100644
index 0000000..e1acc42
--- /dev/null
+++ b/vendor/github.com/nbd-wtf/go-nostr/subscription.go
@@ -0,0 +1,176 @@
+package nostr
+
+import (
+ "context"
+ "fmt"
+ "strconv"
+ "sync"
+ "sync/atomic"
+)
+
+type Subscription struct {
+ label string
+ counter int
+
+ Relay *Relay
+ Filters Filters
+
+ // for this to be treated as a COUNT and not a REQ this must be set
+ countResult chan int64
+
+ // the Events channel emits all EVENTs that come in a Subscription
+ // will be closed when the subscription ends
+ Events chan *Event
+ mu sync.Mutex
+
+ // the EndOfStoredEvents channel gets closed when an EOSE comes for that subscription
+ EndOfStoredEvents chan struct{}
+
+ // the ClosedReason channel emits the reason when a CLOSED message is received
+ ClosedReason chan string
+
+ // Context will be .Done() when the subscription ends
+ Context context.Context
+
+ match func(*Event) bool // this will be either Filters.Match or Filters.MatchIgnoringTimestampConstraints
+ live atomic.Bool
+ eosed atomic.Bool
+ closed atomic.Bool
+ cancel context.CancelFunc
+
+ // this keeps track of the events we've received before the EOSE that we must dispatch before
+ // closing the EndOfStoredEvents channel
+ storedwg sync.WaitGroup
+}
+
+type EventMessage struct {
+ Event Event
+ Relay string
+}
+
+// When instantiating relay connections, some options may be passed.
+// SubscriptionOption is the type of the argument passed for that.
+// Some examples are WithLabel.
+type SubscriptionOption interface {
+ IsSubscriptionOption()
+}
+
+// WithLabel puts a label on the subscription (it is prepended to the automatic id) that is sent to relays.
+type WithLabel string
+
+func (_ WithLabel) IsSubscriptionOption() {}
+
+var _ SubscriptionOption = (WithLabel)("")
+
+// GetID return the Nostr subscription ID as given to the Relay
+// it is a concatenation of the label and a serial number.
+func (sub *Subscription) GetID() string {
+ return sub.label + ":" + strconv.Itoa(sub.counter)
+}
+
+func (sub *Subscription) start() {
+ <-sub.Context.Done()
+ // the subscription ends once the context is canceled (if not already)
+ sub.Unsub() // this will set sub.live to false
+
+ // do this so we don't have the possibility of closing the Events channel and then trying to send to it
+ sub.mu.Lock()
+ close(sub.Events)
+ sub.mu.Unlock()
+}
+
+func (sub *Subscription) dispatchEvent(evt *Event) {
+ added := false
+ if !sub.eosed.Load() {
+ sub.storedwg.Add(1)
+ added = true
+ }
+
+ go func() {
+ sub.mu.Lock()
+ defer sub.mu.Unlock()
+
+ if sub.live.Load() {
+ select {
+ case sub.Events <- evt:
+ case <-sub.Context.Done():
+ }
+ }
+
+ if added {
+ sub.storedwg.Done()
+ }
+ }()
+}
+
+func (sub *Subscription) dispatchEose() {
+ if sub.eosed.CompareAndSwap(false, true) {
+ sub.match = sub.Filters.MatchIgnoringTimestampConstraints
+ go func() {
+ sub.storedwg.Wait()
+ sub.EndOfStoredEvents <- struct{}{}
+ }()
+ }
+}
+
+func (sub *Subscription) dispatchClosed(reason string) {
+ if sub.closed.CompareAndSwap(false, true) {
+ go func() {
+ sub.ClosedReason <- reason
+ }()
+ }
+}
+
+// Unsub closes the subscription, sending "CLOSE" to relay as in NIP-01.
+// Unsub() also closes the channel sub.Events and makes a new one.
+func (sub *Subscription) Unsub() {
+ // cancel the context (if it's not canceled already)
+ sub.cancel()
+
+ // mark subscription as closed and send a CLOSE to the relay (naïve sync.Once implementation)
+ if sub.live.CompareAndSwap(true, false) {
+ sub.Close()
+ }
+
+ // remove subscription from our map
+ sub.Relay.Subscriptions.Delete(sub.GetID())
+}
+
+// Close just sends a CLOSE message. You probably want Unsub() instead.
+func (sub *Subscription) Close() {
+ if sub.Relay.IsConnected() {
+ id := sub.GetID()
+ closeMsg := CloseEnvelope(id)
+ closeb, _ := (&closeMsg).MarshalJSON()
+ debugLogf("{%s} sending %v", sub.Relay.URL, closeb)
+ <-sub.Relay.Write(closeb)
+ }
+}
+
+// Sub sets sub.Filters and then calls sub.Fire(ctx).
+// The subscription will be closed if the context expires.
+func (sub *Subscription) Sub(_ context.Context, filters Filters) {
+ sub.Filters = filters
+ sub.Fire()
+}
+
+// Fire sends the "REQ" command to the relay.
+func (sub *Subscription) Fire() error {
+ id := sub.GetID()
+
+ var reqb []byte
+ if sub.countResult == nil {
+ reqb, _ = ReqEnvelope{id, sub.Filters}.MarshalJSON()
+ } else {
+ reqb, _ = CountEnvelope{id, sub.Filters, nil}.MarshalJSON()
+ }
+ debugLogf("{%s} sending %v", sub.Relay.URL, reqb)
+
+ sub.live.Store(true)
+ if err := <-sub.Relay.Write(reqb); err != nil {
+ sub.cancel()
+ return fmt.Errorf("failed to write: %w", err)
+ }
+
+ return nil
+}
diff --git a/vendor/github.com/nbd-wtf/go-nostr/tags.go b/vendor/github.com/nbd-wtf/go-nostr/tags.go
new file mode 100644
index 0000000..c02a95e
--- /dev/null
+++ b/vendor/github.com/nbd-wtf/go-nostr/tags.go
@@ -0,0 +1,190 @@
+package nostr
+
+import (
+ "encoding/json"
+ "errors"
+ "strings"
+
+ "slices"
+)
+
+type Tag []string
+
+// StartsWith checks if a tag contains a prefix.
+// for example,
+//
+// ["p", "abcdef...", "wss://relay.com"]
+//
+// would match against
+//
+// ["p", "abcdef..."]
+//
+// or even
+//
+// ["p", "abcdef...", "wss://"]
+func (tag Tag) StartsWith(prefix []string) bool {
+ prefixLen := len(prefix)
+
+ if prefixLen > len(tag) {
+ return false
+ }
+ // check initial elements for equality
+ for i := 0; i < prefixLen-1; i++ {
+ if prefix[i] != tag[i] {
+ return false
+ }
+ }
+ // check last element just for a prefix
+ return strings.HasPrefix(tag[prefixLen-1], prefix[prefixLen-1])
+}
+
+func (tag Tag) Key() string {
+ if len(tag) > 0 {
+ return tag[0]
+ }
+ return ""
+}
+
+func (tag Tag) Value() string {
+ if len(tag) > 1 {
+ return tag[1]
+ }
+ return ""
+}
+
+func (tag Tag) Relay() string {
+ if (tag[0] == "e" || tag[0] == "p") && len(tag) > 2 {
+ return NormalizeURL(tag[2])
+ }
+ return ""
+}
+
+type Tags []Tag
+
+// GetD gets the first "d" tag (for parameterized replaceable events) value or ""
+func (tags Tags) GetD() string {
+ for _, v := range tags {
+ if v.StartsWith([]string{"d", ""}) {
+ return v[1]
+ }
+ }
+ return ""
+}
+
+// GetFirst gets the first tag in tags that matches the prefix, see [Tag.StartsWith]
+func (tags Tags) GetFirst(tagPrefix []string) *Tag {
+ for _, v := range tags {
+ if v.StartsWith(tagPrefix) {
+ return &v
+ }
+ }
+ return nil
+}
+
+// GetLast gets the last tag in tags that matches the prefix, see [Tag.StartsWith]
+func (tags Tags) GetLast(tagPrefix []string) *Tag {
+ for i := len(tags) - 1; i >= 0; i-- {
+ v := tags[i]
+ if v.StartsWith(tagPrefix) {
+ return &v
+ }
+ }
+ return nil
+}
+
+// GetAll gets all the tags that match the prefix, see [Tag.StartsWith]
+func (tags Tags) GetAll(tagPrefix []string) Tags {
+ result := make(Tags, 0, len(tags))
+ for _, v := range tags {
+ if v.StartsWith(tagPrefix) {
+ result = append(result, v)
+ }
+ }
+ return result
+}
+
+// FilterOut removes all tags that match the prefix, see [Tag.StartsWith]
+func (tags Tags) FilterOut(tagPrefix []string) Tags {
+ filtered := make(Tags, 0, len(tags))
+ for _, v := range tags {
+ if !v.StartsWith(tagPrefix) {
+ filtered = append(filtered, v)
+ }
+ }
+ return filtered
+}
+
+// AppendUnique appends a tag if it doesn't exist yet, otherwise does nothing.
+// the uniqueness comparison is done based only on the first 2 elements of the tag.
+func (tags Tags) AppendUnique(tag Tag) Tags {
+ n := len(tag)
+ if n > 2 {
+ n = 2
+ }
+
+ if tags.GetFirst(tag[:n]) == nil {
+ return append(tags, tag)
+ }
+ return tags
+}
+
+func (t *Tags) Scan(src any) error {
+ var jtags []byte
+
+ switch v := src.(type) {
+ case []byte:
+ jtags = v
+ case string:
+ jtags = []byte(v)
+ default:
+ return errors.New("couldn't scan tags, it's not a json string")
+ }
+
+ json.Unmarshal(jtags, &t)
+ return nil
+}
+
+func (tags Tags) ContainsAny(tagName string, values []string) bool {
+ for _, tag := range tags {
+ if len(tag) < 2 {
+ continue
+ }
+
+ if tag[0] != tagName {
+ continue
+ }
+
+ if slices.Contains(values, tag[1]) {
+ return true
+ }
+ }
+
+ return false
+}
+
+// Marshal Tag. Used for Serialization so string escaping should be as in RFC8259.
+func (tag Tag) marshalTo(dst []byte) []byte {
+ dst = append(dst, '[')
+ for i, s := range tag {
+ if i > 0 {
+ dst = append(dst, ',')
+ }
+ dst = escapeString(dst, s)
+ }
+ dst = append(dst, ']')
+ return dst
+}
+
+// MarshalTo appends the JSON encoded byte of Tags as [][]string to dst.
+// String escaping is as described in RFC8259.
+func (tags Tags) marshalTo(dst []byte) []byte {
+ dst = append(dst, '[')
+ for i, tag := range tags {
+ if i > 0 {
+ dst = append(dst, ',')
+ }
+ dst = tag.marshalTo(dst)
+ }
+ dst = append(dst, ']')
+ return dst
+}
diff --git a/vendor/github.com/nbd-wtf/go-nostr/timestamp.go b/vendor/github.com/nbd-wtf/go-nostr/timestamp.go
new file mode 100644
index 0000000..43ecb98
--- /dev/null
+++ b/vendor/github.com/nbd-wtf/go-nostr/timestamp.go
@@ -0,0 +1,13 @@
+package nostr
+
+import "time"
+
+type Timestamp int64
+
+func Now() Timestamp {
+ return Timestamp(time.Now().Unix())
+}
+
+func (t Timestamp) Time() time.Time {
+ return time.Unix(int64(t), 0)
+}
diff --git a/vendor/github.com/nbd-wtf/go-nostr/utils.go b/vendor/github.com/nbd-wtf/go-nostr/utils.go
new file mode 100644
index 0000000..984204b
--- /dev/null
+++ b/vendor/github.com/nbd-wtf/go-nostr/utils.go
@@ -0,0 +1,37 @@
+package nostr
+
+import (
+ "cmp"
+ "encoding/hex"
+ "net/url"
+ "strings"
+)
+
+func IsValidRelayURL(u string) bool {
+ parsed, err := url.Parse(u)
+ if err != nil {
+ return false
+ }
+ if parsed.Scheme != "wss" && parsed.Scheme != "ws" {
+ return false
+ }
+ return true
+}
+
+func IsValid32ByteHex(thing string) bool {
+ if strings.ToLower(thing) != thing {
+ return false
+ }
+ if len(thing) != 64 {
+ return false
+ }
+ _, err := hex.DecodeString(thing)
+ return err == nil
+}
+
+func CompareEvent(a, b Event) int {
+ if a.CreatedAt == b.CreatedAt {
+ return strings.Compare(a.ID, b.ID)
+ }
+ return cmp.Compare(a.CreatedAt, b.CreatedAt)
+}
diff --git a/vendor/github.com/puzpuzpuz/xsync/v3/.gitignore b/vendor/github.com/puzpuzpuz/xsync/v3/.gitignore
new file mode 100644
index 0000000..66fd13c
--- /dev/null
+++ b/vendor/github.com/puzpuzpuz/xsync/v3/.gitignore
@@ -0,0 +1,15 @@
+# Binaries for programs and plugins
+*.exe
+*.exe~
+*.dll
+*.so
+*.dylib
+
+# Test binary, built with `go test -c`
+*.test
+
+# Output of the go coverage tool, specifically when used with LiteIDE
+*.out
+
+# Dependency directories (remove the comment below to include it)
+# vendor/
diff --git a/vendor/github.com/puzpuzpuz/xsync/v3/BENCHMARKS.md b/vendor/github.com/puzpuzpuz/xsync/v3/BENCHMARKS.md
new file mode 100644
index 0000000..aaa72fa
--- /dev/null
+++ b/vendor/github.com/puzpuzpuz/xsync/v3/BENCHMARKS.md
@@ -0,0 +1,133 @@
+# xsync benchmarks
+
+If you're interested in `MapOf` comparison with some of the popular concurrent hash maps written in Go, check [this](https://github.com/cornelk/hashmap/pull/70) and [this](https://github.com/alphadose/haxmap/pull/22) PRs.
+
+The below results were obtained for xsync v2.3.1 on a c6g.metal EC2 instance (64 CPU, 128GB RAM) running Linux and Go 1.19.3. I'd like to thank [@felixge](https://github.com/felixge) who kindly ran the benchmarks.
+
+The following commands were used to run the benchmarks:
+```bash
+$ go test -run='^$' -cpu=1,2,4,8,16,32,64 -bench . -count=30 -timeout=0 | tee bench.txt
+$ benchstat bench.txt | tee benchstat.txt
+```
+
+The below sections contain some of the results. Refer to [this gist](https://gist.github.com/puzpuzpuz/e62e38e06feadecfdc823c0f941ece0b) for the complete output.
+
+Please note that `MapOf` got a number of optimizations since v2.3.1, so the current result is likely to be different.
+
+### Counter vs. atomic int64
+
+```
+name time/op
+Counter 27.3ns ± 1%
+Counter-2 27.2ns ±11%
+Counter-4 15.3ns ± 8%
+Counter-8 7.43ns ± 7%
+Counter-16 3.70ns ±10%
+Counter-32 1.77ns ± 3%
+Counter-64 0.96ns ±10%
+AtomicInt64 7.60ns ± 0%
+AtomicInt64-2 12.6ns ±13%
+AtomicInt64-4 13.5ns ±14%
+AtomicInt64-8 12.7ns ± 9%
+AtomicInt64-16 12.8ns ± 8%
+AtomicInt64-32 13.0ns ± 6%
+AtomicInt64-64 12.9ns ± 7%
+```
+
+Here `time/op` stands for average time spent on operation. If you divide `10^9` by the result in nanoseconds per operation, you'd get the throughput in operations per second. Thus, the ideal theoretical scalability of a concurrent data structure implies that the reported `time/op` decreases proportionally with the increased number of CPU cores. On the contrary, if the measured time per operation increases when run on more cores, it means performance degradation.
+
+### MapOf vs. sync.Map
+
+1,000 `[int, int]` entries with a warm-up, 100% Loads:
+```
+IntegerMapOf_WarmUp/reads=100% 24.0ns ± 0%
+IntegerMapOf_WarmUp/reads=100%-2 12.0ns ± 0%
+IntegerMapOf_WarmUp/reads=100%-4 6.02ns ± 0%
+IntegerMapOf_WarmUp/reads=100%-8 3.01ns ± 0%
+IntegerMapOf_WarmUp/reads=100%-16 1.50ns ± 0%
+IntegerMapOf_WarmUp/reads=100%-32 0.75ns ± 0%
+IntegerMapOf_WarmUp/reads=100%-64 0.38ns ± 0%
+IntegerMapStandard_WarmUp/reads=100% 55.3ns ± 0%
+IntegerMapStandard_WarmUp/reads=100%-2 27.6ns ± 0%
+IntegerMapStandard_WarmUp/reads=100%-4 16.1ns ± 3%
+IntegerMapStandard_WarmUp/reads=100%-8 8.35ns ± 7%
+IntegerMapStandard_WarmUp/reads=100%-16 4.24ns ± 7%
+IntegerMapStandard_WarmUp/reads=100%-32 2.18ns ± 6%
+IntegerMapStandard_WarmUp/reads=100%-64 1.11ns ± 3%
+```
+
+1,000 `[int, int]` entries with a warm-up, 99% Loads, 0.5% Stores, 0.5% Deletes:
+```
+IntegerMapOf_WarmUp/reads=99% 31.0ns ± 0%
+IntegerMapOf_WarmUp/reads=99%-2 16.4ns ± 1%
+IntegerMapOf_WarmUp/reads=99%-4 8.42ns ± 0%
+IntegerMapOf_WarmUp/reads=99%-8 4.41ns ± 0%
+IntegerMapOf_WarmUp/reads=99%-16 2.38ns ± 2%
+IntegerMapOf_WarmUp/reads=99%-32 1.37ns ± 4%
+IntegerMapOf_WarmUp/reads=99%-64 0.85ns ± 2%
+IntegerMapStandard_WarmUp/reads=99% 121ns ± 1%
+IntegerMapStandard_WarmUp/reads=99%-2 109ns ± 3%
+IntegerMapStandard_WarmUp/reads=99%-4 115ns ± 4%
+IntegerMapStandard_WarmUp/reads=99%-8 114ns ± 2%
+IntegerMapStandard_WarmUp/reads=99%-16 105ns ± 2%
+IntegerMapStandard_WarmUp/reads=99%-32 97.0ns ± 3%
+IntegerMapStandard_WarmUp/reads=99%-64 98.0ns ± 2%
+```
+
+1,000 `[int, int]` entries with a warm-up, 75% Loads, 12.5% Stores, 12.5% Deletes:
+```
+IntegerMapOf_WarmUp/reads=75%-reads 46.2ns ± 1%
+IntegerMapOf_WarmUp/reads=75%-reads-2 36.7ns ± 2%
+IntegerMapOf_WarmUp/reads=75%-reads-4 22.0ns ± 1%
+IntegerMapOf_WarmUp/reads=75%-reads-8 12.8ns ± 2%
+IntegerMapOf_WarmUp/reads=75%-reads-16 7.69ns ± 1%
+IntegerMapOf_WarmUp/reads=75%-reads-32 5.16ns ± 1%
+IntegerMapOf_WarmUp/reads=75%-reads-64 4.91ns ± 1%
+IntegerMapStandard_WarmUp/reads=75%-reads 156ns ± 0%
+IntegerMapStandard_WarmUp/reads=75%-reads-2 177ns ± 1%
+IntegerMapStandard_WarmUp/reads=75%-reads-4 197ns ± 1%
+IntegerMapStandard_WarmUp/reads=75%-reads-8 221ns ± 2%
+IntegerMapStandard_WarmUp/reads=75%-reads-16 242ns ± 1%
+IntegerMapStandard_WarmUp/reads=75%-reads-32 258ns ± 1%
+IntegerMapStandard_WarmUp/reads=75%-reads-64 264ns ± 1%
+```
+
+### MPMCQueue vs. Go channels
+
+Concurrent producers and consumers (1:1), queue/channel size 1,000, some work done by both producers and consumers:
+```
+QueueProdConsWork100 252ns ± 0%
+QueueProdConsWork100-2 206ns ± 5%
+QueueProdConsWork100-4 136ns ±12%
+QueueProdConsWork100-8 110ns ± 6%
+QueueProdConsWork100-16 108ns ± 2%
+QueueProdConsWork100-32 102ns ± 2%
+QueueProdConsWork100-64 101ns ± 0%
+ChanProdConsWork100 283ns ± 0%
+ChanProdConsWork100-2 406ns ±21%
+ChanProdConsWork100-4 549ns ± 7%
+ChanProdConsWork100-8 754ns ± 7%
+ChanProdConsWork100-16 828ns ± 7%
+ChanProdConsWork100-32 810ns ± 8%
+ChanProdConsWork100-64 832ns ± 4%
+```
+
+### RBMutex vs. sync.RWMutex
+
+The writer locks on each 100,000 iteration with some work in the critical section for both readers and the writer:
+```
+RBMutexWorkWrite100000 146ns ± 0%
+RBMutexWorkWrite100000-2 73.3ns ± 0%
+RBMutexWorkWrite100000-4 36.7ns ± 0%
+RBMutexWorkWrite100000-8 18.6ns ± 0%
+RBMutexWorkWrite100000-16 9.83ns ± 3%
+RBMutexWorkWrite100000-32 5.53ns ± 0%
+RBMutexWorkWrite100000-64 4.04ns ± 3%
+RWMutexWorkWrite100000 121ns ± 0%
+RWMutexWorkWrite100000-2 128ns ± 1%
+RWMutexWorkWrite100000-4 124ns ± 2%
+RWMutexWorkWrite100000-8 101ns ± 1%
+RWMutexWorkWrite100000-16 92.9ns ± 1%
+RWMutexWorkWrite100000-32 89.9ns ± 1%
+RWMutexWorkWrite100000-64 88.4ns ± 1%
+```
diff --git a/vendor/github.com/puzpuzpuz/xsync/v3/LICENSE b/vendor/github.com/puzpuzpuz/xsync/v3/LICENSE
new file mode 100644
index 0000000..261eeb9
--- /dev/null
+++ b/vendor/github.com/puzpuzpuz/xsync/v3/LICENSE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/vendor/github.com/puzpuzpuz/xsync/v3/README.md b/vendor/github.com/puzpuzpuz/xsync/v3/README.md
new file mode 100644
index 0000000..6fe0497
--- /dev/null
+++ b/vendor/github.com/puzpuzpuz/xsync/v3/README.md
@@ -0,0 +1,166 @@
+[![GoDoc reference](https://img.shields.io/badge/godoc-reference-blue.svg)](https://pkg.go.dev/github.com/puzpuzpuz/xsync/v3)
+[![GoReport](https://goreportcard.com/badge/github.com/puzpuzpuz/xsync/v3)](https://goreportcard.com/report/github.com/puzpuzpuz/xsync/v3)
+[![codecov](https://codecov.io/gh/puzpuzpuz/xsync/branch/main/graph/badge.svg)](https://codecov.io/gh/puzpuzpuz/xsync)
+
+# xsync
+
+Concurrent data structures for Go. Aims to provide more scalable alternatives for some of the data structures from the standard `sync` package, but not only.
+
+Covered with tests following the approach described [here](https://puzpuzpuz.dev/testing-concurrent-code-for-fun-and-profit).
+
+## Benchmarks
+
+Benchmark results may be found [here](BENCHMARKS.md). I'd like to thank [@felixge](https://github.com/felixge) who kindly ran the benchmarks on a beefy multicore machine.
+
+Also, a non-scientific, unfair benchmark comparing Java's [j.u.c.ConcurrentHashMap](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/concurrent/ConcurrentHashMap.html) and `xsync.MapOf` is available [here](https://puzpuzpuz.dev/concurrent-map-in-go-vs-java-yet-another-meaningless-benchmark).
+
+## Usage
+
+The latest xsync major version is v3, so `/v3` suffix should be used when importing the library:
+
+```go
+import (
+ "github.com/puzpuzpuz/xsync/v3"
+)
+```
+
+*Note for pre-v3 users*: v1 and v2 support is discontinued, so please upgrade to v3. While the API has some breaking changes, the migration should be trivial.
+
+### Counter
+
+A `Counter` is a striped `int64` counter inspired by the `j.u.c.a.LongAdder` class from the Java standard library.
+
+```go
+c := xsync.NewCounter()
+// increment and decrement the counter
+c.Inc()
+c.Dec()
+// read the current value
+v := c.Value()
+```
+
+Works better in comparison with a single atomically updated `int64` counter in high contention scenarios.
+
+### Map
+
+A `Map` is like a concurrent hash table-based map. It follows the interface of `sync.Map` with a number of valuable extensions like `Compute` or `Size`.
+
+```go
+m := xsync.NewMap()
+m.Store("foo", "bar")
+v, ok := m.Load("foo")
+s := m.Size()
+```
+
+`Map` uses a modified version of Cache-Line Hash Table (CLHT) data structure: https://github.com/LPD-EPFL/CLHT
+
+CLHT is built around the idea of organizing the hash table in cache-line-sized buckets, so that on all modern CPUs update operations complete with minimal cache-line transfer. Also, `Get` operations are obstruction-free and involve no writes to shared memory, hence no mutexes or any other sort of locks. Due to this design, in all considered scenarios `Map` outperforms `sync.Map`.
+
+One important difference with `sync.Map` is that only string keys are supported. That's because Golang standard library does not expose the built-in hash functions for `interface{}` values.
+
+`MapOf[K, V]` is an implementation with parametrized key and value types. While it's still a CLHT-inspired hash map, `MapOf`'s design is quite different from `Map`. As a result, less GC pressure and fewer atomic operations on reads.
+
+```go
+m := xsync.NewMapOf[string, string]()
+m.Store("foo", "bar")
+v, ok := m.Load("foo")
+```
+
+Apart from CLHT, `MapOf` borrows ideas from Java's `j.u.c.ConcurrentHashMap` (immutable K/V pair structs instead of atomic snapshots) and C++'s `absl::flat_hash_map` (meta memory and SWAR-based lookups). It also has more dense memory layout when compared with `Map`. Long story short, `MapOf` should be preferred over `Map` when possible.
+
+An important difference with `Map` is that `MapOf` supports arbitrary `comparable` key types:
+
+```go
+type Point struct {
+ x int32
+ y int32
+}
+m := NewMapOf[Point, int]()
+m.Store(Point{42, 42}, 42)
+v, ok := m.Load(point{42, 42})
+```
+
+Both maps use the built-in Golang's hash function which has DDOS protection. This means that each map instance gets its own seed number and the hash function uses that seed for hash code calculation. However, for smaller keys this hash function has some overhead. So, if you don't need DDOS protection, you may provide a custom hash function when creating a `MapOf`. For instance, Murmur3 finalizer does a decent job when it comes to integers:
+
+```go
+m := NewMapOfWithHasher[int, int](func(i int, _ uint64) uint64 {
+ h := uint64(i)
+ h = (h ^ (h >> 33)) * 0xff51afd7ed558ccd
+ h = (h ^ (h >> 33)) * 0xc4ceb9fe1a85ec53
+ return h ^ (h >> 33)
+})
+```
+
+When benchmarking concurrent maps, make sure to configure all of the competitors with the same hash function or, at least, take hash function performance into the consideration.
+
+### MPMCQueue
+
+A `MPMCQueue` is a bounded multi-producer multi-consumer concurrent queue.
+
+```go
+q := xsync.NewMPMCQueue(1024)
+// producer inserts an item into the queue
+q.Enqueue("foo")
+// optimistic insertion attempt; doesn't block
+inserted := q.TryEnqueue("bar")
+// consumer obtains an item from the queue
+item := q.Dequeue() // interface{} pointing to a string
+// optimistic obtain attempt; doesn't block
+item, ok := q.TryDequeue()
+```
+
+`MPMCQueueOf[I]` is an implementation with parametrized item type. It is available for Go 1.19 or later.
+
+```go
+q := xsync.NewMPMCQueueOf[string](1024)
+q.Enqueue("foo")
+item := q.Dequeue() // string
+```
+
+The queue is based on the algorithm from the [MPMCQueue](https://github.com/rigtorp/MPMCQueue) C++ library which in its turn references D.Vyukov's [MPMC queue](https://www.1024cores.net/home/lock-free-algorithms/queues/bounded-mpmc-queue). According to the following [classification](https://www.1024cores.net/home/lock-free-algorithms/queues), the queue is array-based, fails on overflow, provides causal FIFO, has blocking producers and consumers.
+
+The idea of the algorithm is to allow parallelism for concurrent producers and consumers by introducing the notion of tickets, i.e. values of two counters, one per producers/consumers. An atomic increment of one of those counters is the only noticeable contention point in queue operations. The rest of the operation avoids contention on writes thanks to the turn-based read/write access for each of the queue items.
+
+In essence, `MPMCQueue` is a specialized queue for scenarios where there are multiple concurrent producers and consumers of a single queue running on a large multicore machine.
+
+To get the optimal performance, you may want to set the queue size to be large enough, say, an order of magnitude greater than the number of producers/consumers, to allow producers and consumers to progress with their queue operations in parallel most of the time.
+
+### RBMutex
+
+A `RBMutex` is a reader-biased reader/writer mutual exclusion lock. The lock can be held by many readers or a single writer.
+
+```go
+mu := xsync.NewRBMutex()
+// reader lock calls return a token
+t := mu.RLock()
+// the token must be later used to unlock the mutex
+mu.RUnlock(t)
+// writer locks are the same as in sync.RWMutex
+mu.Lock()
+mu.Unlock()
+```
+
+`RBMutex` is based on a modified version of BRAVO (Biased Locking for Reader-Writer Locks) algorithm: https://arxiv.org/pdf/1810.01553.pdf
+
+The idea of the algorithm is to build on top of an existing reader-writer mutex and introduce a fast path for readers. On the fast path, reader lock attempts are sharded over an internal array based on the reader identity (a token in the case of Golang). This means that readers do not contend over a single atomic counter like it's done in, say, `sync.RWMutex` allowing for better scalability in terms of cores.
+
+Hence, by the design `RBMutex` is a specialized mutex for scenarios, such as caches, where the vast majority of locks are acquired by readers and write lock acquire attempts are infrequent. In such scenarios, `RBMutex` should perform better than the `sync.RWMutex` on large multicore machines.
+
+`RBMutex` extends `sync.RWMutex` internally and uses it as the "reader bias disabled" fallback, so the same semantics apply. The only noticeable difference is in the reader tokens returned from the `RLock`/`RUnlock` methods.
+
+Apart from blocking methods, `RBMutex` also has methods for optimistic locking:
+```go
+mu := xsync.NewRBMutex()
+if locked, t := mu.TryRLock(); locked {
+ // critical reader section...
+ mu.RUnlock(t)
+}
+if mu.TryLock() {
+ // critical writer section...
+ mu.Unlock()
+}
+```
+
+## License
+
+Licensed under MIT.
diff --git a/vendor/github.com/puzpuzpuz/xsync/v3/counter.go b/vendor/github.com/puzpuzpuz/xsync/v3/counter.go
new file mode 100644
index 0000000..4d4dc87
--- /dev/null
+++ b/vendor/github.com/puzpuzpuz/xsync/v3/counter.go
@@ -0,0 +1,99 @@
+package xsync
+
+import (
+ "sync"
+ "sync/atomic"
+)
+
+// pool for P tokens
+var ptokenPool sync.Pool
+
+// a P token is used to point at the current OS thread (P)
+// on which the goroutine is run; exact identity of the thread,
+// as well as P migration tolerance, is not important since
+// it's used to as a best effort mechanism for assigning
+// concurrent operations (goroutines) to different stripes of
+// the counter
+type ptoken struct {
+ idx uint32
+ //lint:ignore U1000 prevents false sharing
+ pad [cacheLineSize - 4]byte
+}
+
+// A Counter is a striped int64 counter.
+//
+// Should be preferred over a single atomically updated int64
+// counter in high contention scenarios.
+//
+// A Counter must not be copied after first use.
+type Counter struct {
+ stripes []cstripe
+ mask uint32
+}
+
+type cstripe struct {
+ c int64
+ //lint:ignore U1000 prevents false sharing
+ pad [cacheLineSize - 8]byte
+}
+
+// NewCounter creates a new Counter instance.
+func NewCounter() *Counter {
+ nstripes := nextPowOf2(parallelism())
+ c := Counter{
+ stripes: make([]cstripe, nstripes),
+ mask: nstripes - 1,
+ }
+ return &c
+}
+
+// Inc increments the counter by 1.
+func (c *Counter) Inc() {
+ c.Add(1)
+}
+
+// Dec decrements the counter by 1.
+func (c *Counter) Dec() {
+ c.Add(-1)
+}
+
+// Add adds the delta to the counter.
+func (c *Counter) Add(delta int64) {
+ t, ok := ptokenPool.Get().(*ptoken)
+ if !ok {
+ t = new(ptoken)
+ t.idx = runtime_fastrand()
+ }
+ for {
+ stripe := &c.stripes[t.idx&c.mask]
+ cnt := atomic.LoadInt64(&stripe.c)
+ if atomic.CompareAndSwapInt64(&stripe.c, cnt, cnt+delta) {
+ break
+ }
+ // Give a try with another randomly selected stripe.
+ t.idx = runtime_fastrand()
+ }
+ ptokenPool.Put(t)
+}
+
+// Value returns the current counter value.
+// The returned value may not include all of the latest operations in
+// presence of concurrent modifications of the counter.
+func (c *Counter) Value() int64 {
+ v := int64(0)
+ for i := 0; i < len(c.stripes); i++ {
+ stripe := &c.stripes[i]
+ v += atomic.LoadInt64(&stripe.c)
+ }
+ return v
+}
+
+// Reset resets the counter to zero.
+// This method should only be used when it is known that there are
+// no concurrent modifications of the counter.
+func (c *Counter) Reset() {
+ for i := 0; i < len(c.stripes); i++ {
+ stripe := &c.stripes[i]
+ atomic.StoreInt64(&stripe.c, 0)
+ }
+}
diff --git a/vendor/github.com/puzpuzpuz/xsync/v3/map.go b/vendor/github.com/puzpuzpuz/xsync/v3/map.go
new file mode 100644
index 0000000..6c5b6eb
--- /dev/null
+++ b/vendor/github.com/puzpuzpuz/xsync/v3/map.go
@@ -0,0 +1,873 @@
+package xsync
+
+import (
+ "fmt"
+ "math"
+ "runtime"
+ "strings"
+ "sync"
+ "sync/atomic"
+ "unsafe"
+)
+
+type mapResizeHint int
+
+const (
+ mapGrowHint mapResizeHint = 0
+ mapShrinkHint mapResizeHint = 1
+ mapClearHint mapResizeHint = 2
+)
+
+const (
+ // number of Map entries per bucket; 3 entries lead to size of 64B
+ // (one cache line) on 64-bit machines
+ entriesPerMapBucket = 3
+ // threshold fraction of table occupation to start a table shrinking
+ // when deleting the last entry in a bucket chain
+ mapShrinkFraction = 128
+ // map load factor to trigger a table resize during insertion;
+ // a map holds up to mapLoadFactor*entriesPerMapBucket*mapTableLen
+ // key-value pairs (this is a soft limit)
+ mapLoadFactor = 0.75
+ // minimal table size, i.e. number of buckets; thus, minimal map
+ // capacity can be calculated as entriesPerMapBucket*defaultMinMapTableLen
+ defaultMinMapTableLen = 32
+ // minimum counter stripes to use
+ minMapCounterLen = 8
+ // maximum counter stripes to use; stands for around 4KB of memory
+ maxMapCounterLen = 32
+)
+
+var (
+ topHashMask = uint64((1<<20)-1) << 44
+ topHashEntryMasks = [3]uint64{
+ topHashMask,
+ topHashMask >> 20,
+ topHashMask >> 40,
+ }
+)
+
+// Map is like a Go map[string]interface{} but is safe for concurrent
+// use by multiple goroutines without additional locking or
+// coordination. It follows the interface of sync.Map with
+// a number of valuable extensions like Compute or Size.
+//
+// A Map must not be copied after first use.
+//
+// Map uses a modified version of Cache-Line Hash Table (CLHT)
+// data structure: https://github.com/LPD-EPFL/CLHT
+//
+// CLHT is built around idea to organize the hash table in
+// cache-line-sized buckets, so that on all modern CPUs update
+// operations complete with at most one cache-line transfer.
+// Also, Get operations involve no write to memory, as well as no
+// mutexes or any other sort of locks. Due to this design, in all
+// considered scenarios Map outperforms sync.Map.
+//
+// One important difference with sync.Map is that only string keys
+// are supported. That's because Golang standard library does not
+// expose the built-in hash functions for interface{} values.
+type Map struct {
+ totalGrowths int64
+ totalShrinks int64
+ resizing int64 // resize in progress flag; updated atomically
+ resizeMu sync.Mutex // only used along with resizeCond
+ resizeCond sync.Cond // used to wake up resize waiters (concurrent modifications)
+ table unsafe.Pointer // *mapTable
+ minTableLen int
+ growOnly bool
+}
+
+type mapTable struct {
+ buckets []bucketPadded
+ // striped counter for number of table entries;
+ // used to determine if a table shrinking is needed
+ // occupies min(buckets_memory/1024, 64KB) of memory
+ size []counterStripe
+ seed uint64
+}
+
+type counterStripe struct {
+ c int64
+ //lint:ignore U1000 prevents false sharing
+ pad [cacheLineSize - 8]byte
+}
+
+type bucketPadded struct {
+ //lint:ignore U1000 ensure each bucket takes two cache lines on both 32 and 64-bit archs
+ pad [cacheLineSize - unsafe.Sizeof(bucket{})]byte
+ bucket
+}
+
+type bucket struct {
+ next unsafe.Pointer // *bucketPadded
+ keys [entriesPerMapBucket]unsafe.Pointer
+ values [entriesPerMapBucket]unsafe.Pointer
+ // topHashMutex is a 2-in-1 value.
+ //
+ // It contains packed top 20 bits (20 MSBs) of hash codes for keys
+ // stored in the bucket:
+ // | key 0's top hash | key 1's top hash | key 2's top hash | bitmap for keys | mutex |
+ // | 20 bits | 20 bits | 20 bits | 3 bits | 1 bit |
+ //
+ // The least significant bit is used for the mutex (TTAS spinlock).
+ topHashMutex uint64
+}
+
+type rangeEntry struct {
+ key unsafe.Pointer
+ value unsafe.Pointer
+}
+
+// MapConfig defines configurable Map/MapOf options.
+type MapConfig struct {
+ sizeHint int
+ growOnly bool
+}
+
+// WithPresize configures new Map/MapOf instance with capacity enough
+// to hold sizeHint entries. The capacity is treated as the minimal
+// capacity meaning that the underlying hash table will never shrink
+// to a smaller capacity. If sizeHint is zero or negative, the value
+// is ignored.
+func WithPresize(sizeHint int) func(*MapConfig) {
+ return func(c *MapConfig) {
+ c.sizeHint = sizeHint
+ }
+}
+
+// WithGrowOnly configures new Map/MapOf instance to be grow-only.
+// This means that the underlying hash table grows in capacity when
+// new keys are added, but does not shrink when keys are deleted.
+// The only exception to this rule is the Clear method which
+// shrinks the hash table back to the initial capacity.
+func WithGrowOnly() func(*MapConfig) {
+ return func(c *MapConfig) {
+ c.growOnly = true
+ }
+}
+
+// NewMap creates a new Map instance configured with the given
+// options.
+func NewMap(options ...func(*MapConfig)) *Map {
+ c := &MapConfig{
+ sizeHint: defaultMinMapTableLen * entriesPerMapBucket,
+ }
+ for _, o := range options {
+ o(c)
+ }
+
+ m := &Map{}
+ m.resizeCond = *sync.NewCond(&m.resizeMu)
+ var table *mapTable
+ if c.sizeHint <= defaultMinMapTableLen*entriesPerMapBucket {
+ table = newMapTable(defaultMinMapTableLen)
+ } else {
+ tableLen := nextPowOf2(uint32((float64(c.sizeHint) / entriesPerMapBucket) / mapLoadFactor))
+ table = newMapTable(int(tableLen))
+ }
+ m.minTableLen = len(table.buckets)
+ m.growOnly = c.growOnly
+ atomic.StorePointer(&m.table, unsafe.Pointer(table))
+ return m
+}
+
+// NewMapPresized creates a new Map instance with capacity enough to hold
+// sizeHint entries. The capacity is treated as the minimal capacity
+// meaning that the underlying hash table will never shrink to
+// a smaller capacity. If sizeHint is zero or negative, the value
+// is ignored.
+//
+// Deprecated: use NewMap in combination with WithPresize.
+func NewMapPresized(sizeHint int) *Map {
+ return NewMap(WithPresize(sizeHint))
+}
+
+func newMapTable(minTableLen int) *mapTable {
+ buckets := make([]bucketPadded, minTableLen)
+ counterLen := minTableLen >> 10
+ if counterLen < minMapCounterLen {
+ counterLen = minMapCounterLen
+ } else if counterLen > maxMapCounterLen {
+ counterLen = maxMapCounterLen
+ }
+ counter := make([]counterStripe, counterLen)
+ t := &mapTable{
+ buckets: buckets,
+ size: counter,
+ seed: makeSeed(),
+ }
+ return t
+}
+
+// Load returns the value stored in the map for a key, or nil if no
+// value is present.
+// The ok result indicates whether value was found in the map.
+func (m *Map) Load(key string) (value interface{}, ok bool) {
+ table := (*mapTable)(atomic.LoadPointer(&m.table))
+ hash := hashString(key, table.seed)
+ bidx := uint64(len(table.buckets)-1) & hash
+ b := &table.buckets[bidx]
+ for {
+ topHashes := atomic.LoadUint64(&b.topHashMutex)
+ for i := 0; i < entriesPerMapBucket; i++ {
+ if !topHashMatch(hash, topHashes, i) {
+ continue
+ }
+ atomic_snapshot:
+ // Start atomic snapshot.
+ vp := atomic.LoadPointer(&b.values[i])
+ kp := atomic.LoadPointer(&b.keys[i])
+ if kp != nil && vp != nil {
+ if key == derefKey(kp) {
+ if uintptr(vp) == uintptr(atomic.LoadPointer(&b.values[i])) {
+ // Atomic snapshot succeeded.
+ return derefValue(vp), true
+ }
+ // Concurrent update/remove. Go for another spin.
+ goto atomic_snapshot
+ }
+ }
+ }
+ bptr := atomic.LoadPointer(&b.next)
+ if bptr == nil {
+ return
+ }
+ b = (*bucketPadded)(bptr)
+ }
+}
+
+// Store sets the value for a key.
+func (m *Map) Store(key string, value interface{}) {
+ m.doCompute(
+ key,
+ func(interface{}, bool) (interface{}, bool) {
+ return value, false
+ },
+ false,
+ false,
+ )
+}
+
+// LoadOrStore returns the existing value for the key if present.
+// Otherwise, it stores and returns the given value.
+// The loaded result is true if the value was loaded, false if stored.
+func (m *Map) LoadOrStore(key string, value interface{}) (actual interface{}, loaded bool) {
+ return m.doCompute(
+ key,
+ func(interface{}, bool) (interface{}, bool) {
+ return value, false
+ },
+ true,
+ false,
+ )
+}
+
+// LoadAndStore returns the existing value for the key if present,
+// while setting the new value for the key.
+// It stores the new value and returns the existing one, if present.
+// The loaded result is true if the existing value was loaded,
+// false otherwise.
+func (m *Map) LoadAndStore(key string, value interface{}) (actual interface{}, loaded bool) {
+ return m.doCompute(
+ key,
+ func(interface{}, bool) (interface{}, bool) {
+ return value, false
+ },
+ false,
+ false,
+ )
+}
+
+// LoadOrCompute returns the existing value for the key if present.
+// Otherwise, it computes the value using the provided function and
+// returns the computed value. The loaded result is true if the value
+// was loaded, false if stored.
+//
+// This call locks a hash table bucket while the compute function
+// is executed. It means that modifications on other entries in
+// the bucket will be blocked until the valueFn executes. Consider
+// this when the function includes long-running operations.
+func (m *Map) LoadOrCompute(key string, valueFn func() interface{}) (actual interface{}, loaded bool) {
+ return m.doCompute(
+ key,
+ func(interface{}, bool) (interface{}, bool) {
+ return valueFn(), false
+ },
+ true,
+ false,
+ )
+}
+
+// Compute either sets the computed new value for the key or deletes
+// the value for the key. When the delete result of the valueFn function
+// is set to true, the value will be deleted, if it exists. When delete
+// is set to false, the value is updated to the newValue.
+// The ok result indicates whether value was computed and stored, thus, is
+// present in the map. The actual result contains the new value in cases where
+// the value was computed and stored. See the example for a few use cases.
+//
+// This call locks a hash table bucket while the compute function
+// is executed. It means that modifications on other entries in
+// the bucket will be blocked until the valueFn executes. Consider
+// this when the function includes long-running operations.
+func (m *Map) Compute(
+ key string,
+ valueFn func(oldValue interface{}, loaded bool) (newValue interface{}, delete bool),
+) (actual interface{}, ok bool) {
+ return m.doCompute(key, valueFn, false, true)
+}
+
+// LoadAndDelete deletes the value for a key, returning the previous
+// value if any. The loaded result reports whether the key was
+// present.
+func (m *Map) LoadAndDelete(key string) (value interface{}, loaded bool) {
+ return m.doCompute(
+ key,
+ func(value interface{}, loaded bool) (interface{}, bool) {
+ return value, true
+ },
+ false,
+ false,
+ )
+}
+
+// Delete deletes the value for a key.
+func (m *Map) Delete(key string) {
+ m.doCompute(
+ key,
+ func(value interface{}, loaded bool) (interface{}, bool) {
+ return value, true
+ },
+ false,
+ false,
+ )
+}
+
+func (m *Map) doCompute(
+ key string,
+ valueFn func(oldValue interface{}, loaded bool) (interface{}, bool),
+ loadIfExists, computeOnly bool,
+) (interface{}, bool) {
+ // Read-only path.
+ if loadIfExists {
+ if v, ok := m.Load(key); ok {
+ return v, !computeOnly
+ }
+ }
+ // Write path.
+ for {
+ compute_attempt:
+ var (
+ emptyb *bucketPadded
+ emptyidx int
+ hintNonEmpty int
+ )
+ table := (*mapTable)(atomic.LoadPointer(&m.table))
+ tableLen := len(table.buckets)
+ hash := hashString(key, table.seed)
+ bidx := uint64(len(table.buckets)-1) & hash
+ rootb := &table.buckets[bidx]
+ lockBucket(&rootb.topHashMutex)
+ // The following two checks must go in reverse to what's
+ // in the resize method.
+ if m.resizeInProgress() {
+ // Resize is in progress. Wait, then go for another attempt.
+ unlockBucket(&rootb.topHashMutex)
+ m.waitForResize()
+ goto compute_attempt
+ }
+ if m.newerTableExists(table) {
+ // Someone resized the table. Go for another attempt.
+ unlockBucket(&rootb.topHashMutex)
+ goto compute_attempt
+ }
+ b := rootb
+ for {
+ topHashes := atomic.LoadUint64(&b.topHashMutex)
+ for i := 0; i < entriesPerMapBucket; i++ {
+ if b.keys[i] == nil {
+ if emptyb == nil {
+ emptyb = b
+ emptyidx = i
+ }
+ continue
+ }
+ if !topHashMatch(hash, topHashes, i) {
+ hintNonEmpty++
+ continue
+ }
+ if key == derefKey(b.keys[i]) {
+ vp := b.values[i]
+ if loadIfExists {
+ unlockBucket(&rootb.topHashMutex)
+ return derefValue(vp), !computeOnly
+ }
+ // In-place update/delete.
+ // We get a copy of the value via an interface{} on each call,
+ // thus the live value pointers are unique. Otherwise atomic
+ // snapshot won't be correct in case of multiple Store calls
+ // using the same value.
+ oldValue := derefValue(vp)
+ newValue, del := valueFn(oldValue, true)
+ if del {
+ // Deletion.
+ // First we update the value, then the key.
+ // This is important for atomic snapshot states.
+ atomic.StoreUint64(&b.topHashMutex, eraseTopHash(topHashes, i))
+ atomic.StorePointer(&b.values[i], nil)
+ atomic.StorePointer(&b.keys[i], nil)
+ leftEmpty := false
+ if hintNonEmpty == 0 {
+ leftEmpty = isEmptyBucket(b)
+ }
+ unlockBucket(&rootb.topHashMutex)
+ table.addSize(bidx, -1)
+ // Might need to shrink the table.
+ if leftEmpty {
+ m.resize(table, mapShrinkHint)
+ }
+ return oldValue, !computeOnly
+ }
+ nvp := unsafe.Pointer(&newValue)
+ if assertionsEnabled && vp == nvp {
+ panic("non-unique value pointer")
+ }
+ atomic.StorePointer(&b.values[i], nvp)
+ unlockBucket(&rootb.topHashMutex)
+ if computeOnly {
+ // Compute expects the new value to be returned.
+ return newValue, true
+ }
+ // LoadAndStore expects the old value to be returned.
+ return oldValue, true
+ }
+ hintNonEmpty++
+ }
+ if b.next == nil {
+ if emptyb != nil {
+ // Insertion into an existing bucket.
+ var zeroedV interface{}
+ newValue, del := valueFn(zeroedV, false)
+ if del {
+ unlockBucket(&rootb.topHashMutex)
+ return zeroedV, false
+ }
+ // First we update the value, then the key.
+ // This is important for atomic snapshot states.
+ topHashes = atomic.LoadUint64(&emptyb.topHashMutex)
+ atomic.StoreUint64(&emptyb.topHashMutex, storeTopHash(hash, topHashes, emptyidx))
+ atomic.StorePointer(&emptyb.values[emptyidx], unsafe.Pointer(&newValue))
+ atomic.StorePointer(&emptyb.keys[emptyidx], unsafe.Pointer(&key))
+ unlockBucket(&rootb.topHashMutex)
+ table.addSize(bidx, 1)
+ return newValue, computeOnly
+ }
+ growThreshold := float64(tableLen) * entriesPerMapBucket * mapLoadFactor
+ if table.sumSize() > int64(growThreshold) {
+ // Need to grow the table. Then go for another attempt.
+ unlockBucket(&rootb.topHashMutex)
+ m.resize(table, mapGrowHint)
+ goto compute_attempt
+ }
+ // Insertion into a new bucket.
+ var zeroedV interface{}
+ newValue, del := valueFn(zeroedV, false)
+ if del {
+ unlockBucket(&rootb.topHashMutex)
+ return newValue, false
+ }
+ // Create and append a bucket.
+ newb := new(bucketPadded)
+ newb.keys[0] = unsafe.Pointer(&key)
+ newb.values[0] = unsafe.Pointer(&newValue)
+ newb.topHashMutex = storeTopHash(hash, newb.topHashMutex, 0)
+ atomic.StorePointer(&b.next, unsafe.Pointer(newb))
+ unlockBucket(&rootb.topHashMutex)
+ table.addSize(bidx, 1)
+ return newValue, computeOnly
+ }
+ b = (*bucketPadded)(b.next)
+ }
+ }
+}
+
+func (m *Map) newerTableExists(table *mapTable) bool {
+ curTablePtr := atomic.LoadPointer(&m.table)
+ return uintptr(curTablePtr) != uintptr(unsafe.Pointer(table))
+}
+
+func (m *Map) resizeInProgress() bool {
+ return atomic.LoadInt64(&m.resizing) == 1
+}
+
+func (m *Map) waitForResize() {
+ m.resizeMu.Lock()
+ for m.resizeInProgress() {
+ m.resizeCond.Wait()
+ }
+ m.resizeMu.Unlock()
+}
+
+func (m *Map) resize(knownTable *mapTable, hint mapResizeHint) {
+ knownTableLen := len(knownTable.buckets)
+ // Fast path for shrink attempts.
+ if hint == mapShrinkHint {
+ if m.growOnly ||
+ m.minTableLen == knownTableLen ||
+ knownTable.sumSize() > int64((knownTableLen*entriesPerMapBucket)/mapShrinkFraction) {
+ return
+ }
+ }
+ // Slow path.
+ if !atomic.CompareAndSwapInt64(&m.resizing, 0, 1) {
+ // Someone else started resize. Wait for it to finish.
+ m.waitForResize()
+ return
+ }
+ var newTable *mapTable
+ table := (*mapTable)(atomic.LoadPointer(&m.table))
+ tableLen := len(table.buckets)
+ switch hint {
+ case mapGrowHint:
+ // Grow the table with factor of 2.
+ atomic.AddInt64(&m.totalGrowths, 1)
+ newTable = newMapTable(tableLen << 1)
+ case mapShrinkHint:
+ shrinkThreshold := int64((tableLen * entriesPerMapBucket) / mapShrinkFraction)
+ if tableLen > m.minTableLen && table.sumSize() <= shrinkThreshold {
+ // Shrink the table with factor of 2.
+ atomic.AddInt64(&m.totalShrinks, 1)
+ newTable = newMapTable(tableLen >> 1)
+ } else {
+ // No need to shrink. Wake up all waiters and give up.
+ m.resizeMu.Lock()
+ atomic.StoreInt64(&m.resizing, 0)
+ m.resizeCond.Broadcast()
+ m.resizeMu.Unlock()
+ return
+ }
+ case mapClearHint:
+ newTable = newMapTable(m.minTableLen)
+ default:
+ panic(fmt.Sprintf("unexpected resize hint: %d", hint))
+ }
+ // Copy the data only if we're not clearing the map.
+ if hint != mapClearHint {
+ for i := 0; i < tableLen; i++ {
+ copied := copyBucket(&table.buckets[i], newTable)
+ newTable.addSizePlain(uint64(i), copied)
+ }
+ }
+ // Publish the new table and wake up all waiters.
+ atomic.StorePointer(&m.table, unsafe.Pointer(newTable))
+ m.resizeMu.Lock()
+ atomic.StoreInt64(&m.resizing, 0)
+ m.resizeCond.Broadcast()
+ m.resizeMu.Unlock()
+}
+
+func copyBucket(b *bucketPadded, destTable *mapTable) (copied int) {
+ rootb := b
+ lockBucket(&rootb.topHashMutex)
+ for {
+ for i := 0; i < entriesPerMapBucket; i++ {
+ if b.keys[i] != nil {
+ k := derefKey(b.keys[i])
+ hash := hashString(k, destTable.seed)
+ bidx := uint64(len(destTable.buckets)-1) & hash
+ destb := &destTable.buckets[bidx]
+ appendToBucket(hash, b.keys[i], b.values[i], destb)
+ copied++
+ }
+ }
+ if b.next == nil {
+ unlockBucket(&rootb.topHashMutex)
+ return
+ }
+ b = (*bucketPadded)(b.next)
+ }
+}
+
+func appendToBucket(hash uint64, keyPtr, valPtr unsafe.Pointer, b *bucketPadded) {
+ for {
+ for i := 0; i < entriesPerMapBucket; i++ {
+ if b.keys[i] == nil {
+ b.keys[i] = keyPtr
+ b.values[i] = valPtr
+ b.topHashMutex = storeTopHash(hash, b.topHashMutex, i)
+ return
+ }
+ }
+ if b.next == nil {
+ newb := new(bucketPadded)
+ newb.keys[0] = keyPtr
+ newb.values[0] = valPtr
+ newb.topHashMutex = storeTopHash(hash, newb.topHashMutex, 0)
+ b.next = unsafe.Pointer(newb)
+ return
+ }
+ b = (*bucketPadded)(b.next)
+ }
+}
+
+func isEmptyBucket(rootb *bucketPadded) bool {
+ b := rootb
+ for {
+ for i := 0; i < entriesPerMapBucket; i++ {
+ if b.keys[i] != nil {
+ return false
+ }
+ }
+ if b.next == nil {
+ return true
+ }
+ b = (*bucketPadded)(b.next)
+ }
+}
+
+// Range calls f sequentially for each key and value present in the
+// map. If f returns false, range stops the iteration.
+//
+// Range does not necessarily correspond to any consistent snapshot
+// of the Map's contents: no key will be visited more than once, but
+// if the value for any key is stored or deleted concurrently, Range
+// may reflect any mapping for that key from any point during the
+// Range call.
+//
+// It is safe to modify the map while iterating it, including entry
+// creation, modification and deletion. However, the concurrent
+// modification rule apply, i.e. the changes may be not reflected
+// in the subsequently iterated entries.
+func (m *Map) Range(f func(key string, value interface{}) bool) {
+ var zeroEntry rangeEntry
+ // Pre-allocate array big enough to fit entries for most hash tables.
+ bentries := make([]rangeEntry, 0, 16*entriesPerMapBucket)
+ tablep := atomic.LoadPointer(&m.table)
+ table := *(*mapTable)(tablep)
+ for i := range table.buckets {
+ rootb := &table.buckets[i]
+ b := rootb
+ // Prevent concurrent modifications and copy all entries into
+ // the intermediate slice.
+ lockBucket(&rootb.topHashMutex)
+ for {
+ for i := 0; i < entriesPerMapBucket; i++ {
+ if b.keys[i] != nil {
+ bentries = append(bentries, rangeEntry{
+ key: b.keys[i],
+ value: b.values[i],
+ })
+ }
+ }
+ if b.next == nil {
+ unlockBucket(&rootb.topHashMutex)
+ break
+ }
+ b = (*bucketPadded)(b.next)
+ }
+ // Call the function for all copied entries.
+ for j := range bentries {
+ k := derefKey(bentries[j].key)
+ v := derefValue(bentries[j].value)
+ if !f(k, v) {
+ return
+ }
+ // Remove the reference to avoid preventing the copied
+ // entries from being GCed until this method finishes.
+ bentries[j] = zeroEntry
+ }
+ bentries = bentries[:0]
+ }
+}
+
+// Clear deletes all keys and values currently stored in the map.
+func (m *Map) Clear() {
+ table := (*mapTable)(atomic.LoadPointer(&m.table))
+ m.resize(table, mapClearHint)
+}
+
+// Size returns current size of the map.
+func (m *Map) Size() int {
+ table := (*mapTable)(atomic.LoadPointer(&m.table))
+ return int(table.sumSize())
+}
+
+func derefKey(keyPtr unsafe.Pointer) string {
+ return *(*string)(keyPtr)
+}
+
+func derefValue(valuePtr unsafe.Pointer) interface{} {
+ return *(*interface{})(valuePtr)
+}
+
+func lockBucket(mu *uint64) {
+ for {
+ var v uint64
+ for {
+ v = atomic.LoadUint64(mu)
+ if v&1 != 1 {
+ break
+ }
+ runtime.Gosched()
+ }
+ if atomic.CompareAndSwapUint64(mu, v, v|1) {
+ return
+ }
+ runtime.Gosched()
+ }
+}
+
+func unlockBucket(mu *uint64) {
+ v := atomic.LoadUint64(mu)
+ atomic.StoreUint64(mu, v&^1)
+}
+
+func topHashMatch(hash, topHashes uint64, idx int) bool {
+ if topHashes&(1<<(idx+1)) == 0 {
+ // Entry is not present.
+ return false
+ }
+ hash = hash & topHashMask
+ topHashes = (topHashes & topHashEntryMasks[idx]) << (20 * idx)
+ return hash == topHashes
+}
+
+func storeTopHash(hash, topHashes uint64, idx int) uint64 {
+ // Zero out top hash at idx.
+ topHashes = topHashes &^ topHashEntryMasks[idx]
+ // Chop top 20 MSBs of the given hash and position them at idx.
+ hash = (hash & topHashMask) >> (20 * idx)
+ // Store the MSBs.
+ topHashes = topHashes | hash
+ // Mark the entry as present.
+ return topHashes | (1 << (idx + 1))
+}
+
+func eraseTopHash(topHashes uint64, idx int) uint64 {
+ return topHashes &^ (1 << (idx + 1))
+}
+
+func (table *mapTable) addSize(bucketIdx uint64, delta int) {
+ cidx := uint64(len(table.size)-1) & bucketIdx
+ atomic.AddInt64(&table.size[cidx].c, int64(delta))
+}
+
+func (table *mapTable) addSizePlain(bucketIdx uint64, delta int) {
+ cidx := uint64(len(table.size)-1) & bucketIdx
+ table.size[cidx].c += int64(delta)
+}
+
+func (table *mapTable) sumSize() int64 {
+ sum := int64(0)
+ for i := range table.size {
+ sum += atomic.LoadInt64(&table.size[i].c)
+ }
+ return sum
+}
+
+// MapStats is Map/MapOf statistics.
+//
+// Warning: map statistics are intented to be used for diagnostic
+// purposes, not for production code. This means that breaking changes
+// may be introduced into this struct even between minor releases.
+type MapStats struct {
+ // RootBuckets is the number of root buckets in the hash table.
+ // Each bucket holds a few entries.
+ RootBuckets int
+ // TotalBuckets is the total number of buckets in the hash table,
+ // including root and their chained buckets. Each bucket holds
+ // a few entries.
+ TotalBuckets int
+ // EmptyBuckets is the number of buckets that hold no entries.
+ EmptyBuckets int
+ // Capacity is the Map/MapOf capacity, i.e. the total number of
+ // entries that all buckets can physically hold. This number
+ // does not consider the load factor.
+ Capacity int
+ // Size is the exact number of entries stored in the map.
+ Size int
+ // Counter is the number of entries stored in the map according
+ // to the internal atomic counter. In case of concurrent map
+ // modifications this number may be different from Size.
+ Counter int
+ // CounterLen is the number of internal atomic counter stripes.
+ // This number may grow with the map capacity to improve
+ // multithreaded scalability.
+ CounterLen int
+ // MinEntries is the minimum number of entries per a chain of
+ // buckets, i.e. a root bucket and its chained buckets.
+ MinEntries int
+ // MinEntries is the maximum number of entries per a chain of
+ // buckets, i.e. a root bucket and its chained buckets.
+ MaxEntries int
+ // TotalGrowths is the number of times the hash table grew.
+ TotalGrowths int64
+ // TotalGrowths is the number of times the hash table shrinked.
+ TotalShrinks int64
+}
+
+// ToString returns string representation of map stats.
+func (s *MapStats) ToString() string {
+ var sb strings.Builder
+ sb.WriteString("MapStats{\n")
+ sb.WriteString(fmt.Sprintf("RootBuckets: %d\n", s.RootBuckets))
+ sb.WriteString(fmt.Sprintf("TotalBuckets: %d\n", s.TotalBuckets))
+ sb.WriteString(fmt.Sprintf("EmptyBuckets: %d\n", s.EmptyBuckets))
+ sb.WriteString(fmt.Sprintf("Capacity: %d\n", s.Capacity))
+ sb.WriteString(fmt.Sprintf("Size: %d\n", s.Size))
+ sb.WriteString(fmt.Sprintf("Counter: %d\n", s.Counter))
+ sb.WriteString(fmt.Sprintf("CounterLen: %d\n", s.CounterLen))
+ sb.WriteString(fmt.Sprintf("MinEntries: %d\n", s.MinEntries))
+ sb.WriteString(fmt.Sprintf("MaxEntries: %d\n", s.MaxEntries))
+ sb.WriteString(fmt.Sprintf("TotalGrowths: %d\n", s.TotalGrowths))
+ sb.WriteString(fmt.Sprintf("TotalShrinks: %d\n", s.TotalShrinks))
+ sb.WriteString("}\n")
+ return sb.String()
+}
+
+// Stats returns statistics for the Map. Just like other map
+// methods, this one is thread-safe. Yet it's an O(N) operation,
+// so it should be used only for diagnostics or debugging purposes.
+func (m *Map) Stats() MapStats {
+ stats := MapStats{
+ TotalGrowths: atomic.LoadInt64(&m.totalGrowths),
+ TotalShrinks: atomic.LoadInt64(&m.totalShrinks),
+ MinEntries: math.MaxInt32,
+ }
+ table := (*mapTable)(atomic.LoadPointer(&m.table))
+ stats.RootBuckets = len(table.buckets)
+ stats.Counter = int(table.sumSize())
+ stats.CounterLen = len(table.size)
+ for i := range table.buckets {
+ nentries := 0
+ b := &table.buckets[i]
+ stats.TotalBuckets++
+ for {
+ nentriesLocal := 0
+ stats.Capacity += entriesPerMapBucket
+ for i := 0; i < entriesPerMapBucket; i++ {
+ if atomic.LoadPointer(&b.keys[i]) != nil {
+ stats.Size++
+ nentriesLocal++
+ }
+ }
+ nentries += nentriesLocal
+ if nentriesLocal == 0 {
+ stats.EmptyBuckets++
+ }
+ if b.next == nil {
+ break
+ }
+ b = (*bucketPadded)(atomic.LoadPointer(&b.next))
+ stats.TotalBuckets++
+ }
+ if nentries < stats.MinEntries {
+ stats.MinEntries = nentries
+ }
+ if nentries > stats.MaxEntries {
+ stats.MaxEntries = nentries
+ }
+ }
+ return stats
+}
diff --git a/vendor/github.com/puzpuzpuz/xsync/v3/mapof.go b/vendor/github.com/puzpuzpuz/xsync/v3/mapof.go
new file mode 100644
index 0000000..4c4ad08
--- /dev/null
+++ b/vendor/github.com/puzpuzpuz/xsync/v3/mapof.go
@@ -0,0 +1,694 @@
+package xsync
+
+import (
+ "fmt"
+ "math"
+ "sync"
+ "sync/atomic"
+ "unsafe"
+)
+
+const (
+ // number of MapOf entries per bucket; 5 entries lead to size of 64B
+ // (one cache line) on 64-bit machines
+ entriesPerMapOfBucket = 5
+ defaultMeta uint64 = 0x8080808080808080
+ metaMask uint64 = 0xffffffffff
+ defaultMetaMasked uint64 = defaultMeta & metaMask
+ emptyMetaSlot uint8 = 0x80
+)
+
+// MapOf is like a Go map[K]V but is safe for concurrent
+// use by multiple goroutines without additional locking or
+// coordination. It follows the interface of sync.Map with
+// a number of valuable extensions like Compute or Size.
+//
+// A MapOf must not be copied after first use.
+//
+// MapOf uses a modified version of Cache-Line Hash Table (CLHT)
+// data structure: https://github.com/LPD-EPFL/CLHT
+//
+// CLHT is built around idea to organize the hash table in
+// cache-line-sized buckets, so that on all modern CPUs update
+// operations complete with at most one cache-line transfer.
+// Also, Get operations involve no write to memory, as well as no
+// mutexes or any other sort of locks. Due to this design, in all
+// considered scenarios MapOf outperforms sync.Map.
+//
+// MapOf also borrows ideas from Java's j.u.c.ConcurrentHashMap
+// (immutable K/V pair structs instead of atomic snapshots)
+// and C++'s absl::flat_hash_map (meta memory and SWAR-based
+// lookups).
+type MapOf[K comparable, V any] struct {
+ totalGrowths int64
+ totalShrinks int64
+ resizing int64 // resize in progress flag; updated atomically
+ resizeMu sync.Mutex // only used along with resizeCond
+ resizeCond sync.Cond // used to wake up resize waiters (concurrent modifications)
+ table unsafe.Pointer // *mapOfTable
+ hasher func(K, uint64) uint64
+ minTableLen int
+ growOnly bool
+}
+
+type mapOfTable[K comparable, V any] struct {
+ buckets []bucketOfPadded
+ // striped counter for number of table entries;
+ // used to determine if a table shrinking is needed
+ // occupies min(buckets_memory/1024, 64KB) of memory
+ size []counterStripe
+ seed uint64
+}
+
+// bucketOfPadded is a CL-sized map bucket holding up to
+// entriesPerMapOfBucket entries.
+type bucketOfPadded struct {
+ //lint:ignore U1000 ensure each bucket takes two cache lines on both 32 and 64-bit archs
+ pad [cacheLineSize - unsafe.Sizeof(bucketOf{})]byte
+ bucketOf
+}
+
+type bucketOf struct {
+ meta uint64
+ entries [entriesPerMapOfBucket]unsafe.Pointer // *entryOf
+ next unsafe.Pointer // *bucketOfPadded
+ mu sync.Mutex
+}
+
+// entryOf is an immutable map entry.
+type entryOf[K comparable, V any] struct {
+ key K
+ value V
+}
+
+// NewMapOf creates a new MapOf instance configured with the given
+// options.
+func NewMapOf[K comparable, V any](options ...func(*MapConfig)) *MapOf[K, V] {
+ return NewMapOfWithHasher[K, V](defaultHasher[K](), options...)
+}
+
+// NewMapOfWithHasher creates a new MapOf instance configured with
+// the given hasher and options. The hash function is used instead
+// of the built-in hash function configured when a map is created
+// with the NewMapOf function.
+func NewMapOfWithHasher[K comparable, V any](
+ hasher func(K, uint64) uint64,
+ options ...func(*MapConfig),
+) *MapOf[K, V] {
+ c := &MapConfig{
+ sizeHint: defaultMinMapTableLen * entriesPerMapOfBucket,
+ }
+ for _, o := range options {
+ o(c)
+ }
+
+ m := &MapOf[K, V]{}
+ m.resizeCond = *sync.NewCond(&m.resizeMu)
+ m.hasher = hasher
+ var table *mapOfTable[K, V]
+ if c.sizeHint <= defaultMinMapTableLen*entriesPerMapOfBucket {
+ table = newMapOfTable[K, V](defaultMinMapTableLen)
+ } else {
+ tableLen := nextPowOf2(uint32((float64(c.sizeHint) / entriesPerMapOfBucket) / mapLoadFactor))
+ table = newMapOfTable[K, V](int(tableLen))
+ }
+ m.minTableLen = len(table.buckets)
+ m.growOnly = c.growOnly
+ atomic.StorePointer(&m.table, unsafe.Pointer(table))
+ return m
+}
+
+// NewMapOfPresized creates a new MapOf instance with capacity enough
+// to hold sizeHint entries. The capacity is treated as the minimal capacity
+// meaning that the underlying hash table will never shrink to
+// a smaller capacity. If sizeHint is zero or negative, the value
+// is ignored.
+//
+// Deprecated: use NewMapOf in combination with WithPresize.
+func NewMapOfPresized[K comparable, V any](sizeHint int) *MapOf[K, V] {
+ return NewMapOf[K, V](WithPresize(sizeHint))
+}
+
+func newMapOfTable[K comparable, V any](minTableLen int) *mapOfTable[K, V] {
+ buckets := make([]bucketOfPadded, minTableLen)
+ for i := range buckets {
+ buckets[i].meta = defaultMeta
+ }
+ counterLen := minTableLen >> 10
+ if counterLen < minMapCounterLen {
+ counterLen = minMapCounterLen
+ } else if counterLen > maxMapCounterLen {
+ counterLen = maxMapCounterLen
+ }
+ counter := make([]counterStripe, counterLen)
+ t := &mapOfTable[K, V]{
+ buckets: buckets,
+ size: counter,
+ seed: makeSeed(),
+ }
+ return t
+}
+
+// Load returns the value stored in the map for a key, or zero value
+// of type V if no value is present.
+// The ok result indicates whether value was found in the map.
+func (m *MapOf[K, V]) Load(key K) (value V, ok bool) {
+ table := (*mapOfTable[K, V])(atomic.LoadPointer(&m.table))
+ hash := m.hasher(key, table.seed)
+ h1 := h1(hash)
+ h2w := broadcast(h2(hash))
+ bidx := uint64(len(table.buckets)-1) & h1
+ b := &table.buckets[bidx]
+ for {
+ metaw := atomic.LoadUint64(&b.meta)
+ markedw := markZeroBytes(metaw^h2w) & metaMask
+ for markedw != 0 {
+ idx := firstMarkedByteIndex(markedw)
+ eptr := atomic.LoadPointer(&b.entries[idx])
+ if eptr != nil {
+ e := (*entryOf[K, V])(eptr)
+ if e.key == key {
+ return e.value, true
+ }
+ }
+ markedw &= markedw - 1
+ }
+ bptr := atomic.LoadPointer(&b.next)
+ if bptr == nil {
+ return
+ }
+ b = (*bucketOfPadded)(bptr)
+ }
+}
+
+// Store sets the value for a key.
+func (m *MapOf[K, V]) Store(key K, value V) {
+ m.doCompute(
+ key,
+ func(V, bool) (V, bool) {
+ return value, false
+ },
+ false,
+ false,
+ )
+}
+
+// LoadOrStore returns the existing value for the key if present.
+// Otherwise, it stores and returns the given value.
+// The loaded result is true if the value was loaded, false if stored.
+func (m *MapOf[K, V]) LoadOrStore(key K, value V) (actual V, loaded bool) {
+ return m.doCompute(
+ key,
+ func(V, bool) (V, bool) {
+ return value, false
+ },
+ true,
+ false,
+ )
+}
+
+// LoadAndStore returns the existing value for the key if present,
+// while setting the new value for the key.
+// It stores the new value and returns the existing one, if present.
+// The loaded result is true if the existing value was loaded,
+// false otherwise.
+func (m *MapOf[K, V]) LoadAndStore(key K, value V) (actual V, loaded bool) {
+ return m.doCompute(
+ key,
+ func(V, bool) (V, bool) {
+ return value, false
+ },
+ false,
+ false,
+ )
+}
+
+// LoadOrCompute returns the existing value for the key if present.
+// Otherwise, it computes the value using the provided function and
+// returns the computed value. The loaded result is true if the value
+// was loaded, false if stored.
+//
+// This call locks a hash table bucket while the compute function
+// is executed. It means that modifications on other entries in
+// the bucket will be blocked until the valueFn executes. Consider
+// this when the function includes long-running operations.
+func (m *MapOf[K, V]) LoadOrCompute(key K, valueFn func() V) (actual V, loaded bool) {
+ return m.doCompute(
+ key,
+ func(V, bool) (V, bool) {
+ return valueFn(), false
+ },
+ true,
+ false,
+ )
+}
+
+// Compute either sets the computed new value for the key or deletes
+// the value for the key. When the delete result of the valueFn function
+// is set to true, the value will be deleted, if it exists. When delete
+// is set to false, the value is updated to the newValue.
+// The ok result indicates whether value was computed and stored, thus, is
+// present in the map. The actual result contains the new value in cases where
+// the value was computed and stored. See the example for a few use cases.
+//
+// This call locks a hash table bucket while the compute function
+// is executed. It means that modifications on other entries in
+// the bucket will be blocked until the valueFn executes. Consider
+// this when the function includes long-running operations.
+func (m *MapOf[K, V]) Compute(
+ key K,
+ valueFn func(oldValue V, loaded bool) (newValue V, delete bool),
+) (actual V, ok bool) {
+ return m.doCompute(key, valueFn, false, true)
+}
+
+// LoadAndDelete deletes the value for a key, returning the previous
+// value if any. The loaded result reports whether the key was
+// present.
+func (m *MapOf[K, V]) LoadAndDelete(key K) (value V, loaded bool) {
+ return m.doCompute(
+ key,
+ func(value V, loaded bool) (V, bool) {
+ return value, true
+ },
+ false,
+ false,
+ )
+}
+
+// Delete deletes the value for a key.
+func (m *MapOf[K, V]) Delete(key K) {
+ m.doCompute(
+ key,
+ func(value V, loaded bool) (V, bool) {
+ return value, true
+ },
+ false,
+ false,
+ )
+}
+
+func (m *MapOf[K, V]) doCompute(
+ key K,
+ valueFn func(oldValue V, loaded bool) (V, bool),
+ loadIfExists, computeOnly bool,
+) (V, bool) {
+ // Read-only path.
+ if loadIfExists {
+ if v, ok := m.Load(key); ok {
+ return v, !computeOnly
+ }
+ }
+ // Write path.
+ for {
+ compute_attempt:
+ var (
+ emptyb *bucketOfPadded
+ emptyidx int
+ )
+ table := (*mapOfTable[K, V])(atomic.LoadPointer(&m.table))
+ tableLen := len(table.buckets)
+ hash := m.hasher(key, table.seed)
+ h1 := h1(hash)
+ h2 := h2(hash)
+ h2w := broadcast(h2)
+ bidx := uint64(len(table.buckets)-1) & h1
+ rootb := &table.buckets[bidx]
+ rootb.mu.Lock()
+ // The following two checks must go in reverse to what's
+ // in the resize method.
+ if m.resizeInProgress() {
+ // Resize is in progress. Wait, then go for another attempt.
+ rootb.mu.Unlock()
+ m.waitForResize()
+ goto compute_attempt
+ }
+ if m.newerTableExists(table) {
+ // Someone resized the table. Go for another attempt.
+ rootb.mu.Unlock()
+ goto compute_attempt
+ }
+ b := rootb
+ for {
+ metaw := b.meta
+ markedw := markZeroBytes(metaw^h2w) & metaMask
+ for markedw != 0 {
+ idx := firstMarkedByteIndex(markedw)
+ eptr := b.entries[idx]
+ if eptr != nil {
+ e := (*entryOf[K, V])(eptr)
+ if e.key == key {
+ if loadIfExists {
+ rootb.mu.Unlock()
+ return e.value, !computeOnly
+ }
+ // In-place update/delete.
+ // We get a copy of the value via an interface{} on each call,
+ // thus the live value pointers are unique. Otherwise atomic
+ // snapshot won't be correct in case of multiple Store calls
+ // using the same value.
+ oldv := e.value
+ newv, del := valueFn(oldv, true)
+ if del {
+ // Deletion.
+ // First we update the hash, then the entry.
+ newmetaw := setByte(metaw, emptyMetaSlot, idx)
+ atomic.StoreUint64(&b.meta, newmetaw)
+ atomic.StorePointer(&b.entries[idx], nil)
+ rootb.mu.Unlock()
+ table.addSize(bidx, -1)
+ // Might need to shrink the table if we left bucket empty.
+ if newmetaw == defaultMeta {
+ m.resize(table, mapShrinkHint)
+ }
+ return oldv, !computeOnly
+ }
+ newe := new(entryOf[K, V])
+ newe.key = key
+ newe.value = newv
+ atomic.StorePointer(&b.entries[idx], unsafe.Pointer(newe))
+ rootb.mu.Unlock()
+ if computeOnly {
+ // Compute expects the new value to be returned.
+ return newv, true
+ }
+ // LoadAndStore expects the old value to be returned.
+ return oldv, true
+ }
+ }
+ markedw &= markedw - 1
+ }
+ if emptyb == nil {
+ // Search for empty entries (up to 5 per bucket).
+ emptyw := metaw & defaultMetaMasked
+ if emptyw != 0 {
+ idx := firstMarkedByteIndex(emptyw)
+ emptyb = b
+ emptyidx = idx
+ }
+ }
+ if b.next == nil {
+ if emptyb != nil {
+ // Insertion into an existing bucket.
+ var zeroedV V
+ newValue, del := valueFn(zeroedV, false)
+ if del {
+ rootb.mu.Unlock()
+ return zeroedV, false
+ }
+ newe := new(entryOf[K, V])
+ newe.key = key
+ newe.value = newValue
+ // First we update meta, then the entry.
+ atomic.StoreUint64(&emptyb.meta, setByte(emptyb.meta, h2, emptyidx))
+ atomic.StorePointer(&emptyb.entries[emptyidx], unsafe.Pointer(newe))
+ rootb.mu.Unlock()
+ table.addSize(bidx, 1)
+ return newValue, computeOnly
+ }
+ growThreshold := float64(tableLen) * entriesPerMapOfBucket * mapLoadFactor
+ if table.sumSize() > int64(growThreshold) {
+ // Need to grow the table. Then go for another attempt.
+ rootb.mu.Unlock()
+ m.resize(table, mapGrowHint)
+ goto compute_attempt
+ }
+ // Insertion into a new bucket.
+ var zeroedV V
+ newValue, del := valueFn(zeroedV, false)
+ if del {
+ rootb.mu.Unlock()
+ return newValue, false
+ }
+ // Create and append a bucket.
+ newb := new(bucketOfPadded)
+ newb.meta = setByte(defaultMeta, h2, 0)
+ newe := new(entryOf[K, V])
+ newe.key = key
+ newe.value = newValue
+ newb.entries[0] = unsafe.Pointer(newe)
+ atomic.StorePointer(&b.next, unsafe.Pointer(newb))
+ rootb.mu.Unlock()
+ table.addSize(bidx, 1)
+ return newValue, computeOnly
+ }
+ b = (*bucketOfPadded)(b.next)
+ }
+ }
+}
+
+func (m *MapOf[K, V]) newerTableExists(table *mapOfTable[K, V]) bool {
+ curTablePtr := atomic.LoadPointer(&m.table)
+ return uintptr(curTablePtr) != uintptr(unsafe.Pointer(table))
+}
+
+func (m *MapOf[K, V]) resizeInProgress() bool {
+ return atomic.LoadInt64(&m.resizing) == 1
+}
+
+func (m *MapOf[K, V]) waitForResize() {
+ m.resizeMu.Lock()
+ for m.resizeInProgress() {
+ m.resizeCond.Wait()
+ }
+ m.resizeMu.Unlock()
+}
+
+func (m *MapOf[K, V]) resize(knownTable *mapOfTable[K, V], hint mapResizeHint) {
+ knownTableLen := len(knownTable.buckets)
+ // Fast path for shrink attempts.
+ if hint == mapShrinkHint {
+ if m.growOnly ||
+ m.minTableLen == knownTableLen ||
+ knownTable.sumSize() > int64((knownTableLen*entriesPerMapOfBucket)/mapShrinkFraction) {
+ return
+ }
+ }
+ // Slow path.
+ if !atomic.CompareAndSwapInt64(&m.resizing, 0, 1) {
+ // Someone else started resize. Wait for it to finish.
+ m.waitForResize()
+ return
+ }
+ var newTable *mapOfTable[K, V]
+ table := (*mapOfTable[K, V])(atomic.LoadPointer(&m.table))
+ tableLen := len(table.buckets)
+ switch hint {
+ case mapGrowHint:
+ // Grow the table with factor of 2.
+ atomic.AddInt64(&m.totalGrowths, 1)
+ newTable = newMapOfTable[K, V](tableLen << 1)
+ case mapShrinkHint:
+ shrinkThreshold := int64((tableLen * entriesPerMapOfBucket) / mapShrinkFraction)
+ if tableLen > m.minTableLen && table.sumSize() <= shrinkThreshold {
+ // Shrink the table with factor of 2.
+ atomic.AddInt64(&m.totalShrinks, 1)
+ newTable = newMapOfTable[K, V](tableLen >> 1)
+ } else {
+ // No need to shrink. Wake up all waiters and give up.
+ m.resizeMu.Lock()
+ atomic.StoreInt64(&m.resizing, 0)
+ m.resizeCond.Broadcast()
+ m.resizeMu.Unlock()
+ return
+ }
+ case mapClearHint:
+ newTable = newMapOfTable[K, V](m.minTableLen)
+ default:
+ panic(fmt.Sprintf("unexpected resize hint: %d", hint))
+ }
+ // Copy the data only if we're not clearing the map.
+ if hint != mapClearHint {
+ for i := 0; i < tableLen; i++ {
+ copied := copyBucketOf(&table.buckets[i], newTable, m.hasher)
+ newTable.addSizePlain(uint64(i), copied)
+ }
+ }
+ // Publish the new table and wake up all waiters.
+ atomic.StorePointer(&m.table, unsafe.Pointer(newTable))
+ m.resizeMu.Lock()
+ atomic.StoreInt64(&m.resizing, 0)
+ m.resizeCond.Broadcast()
+ m.resizeMu.Unlock()
+}
+
+func copyBucketOf[K comparable, V any](
+ b *bucketOfPadded,
+ destTable *mapOfTable[K, V],
+ hasher func(K, uint64) uint64,
+) (copied int) {
+ rootb := b
+ rootb.mu.Lock()
+ for {
+ for i := 0; i < entriesPerMapOfBucket; i++ {
+ if b.entries[i] != nil {
+ e := (*entryOf[K, V])(b.entries[i])
+ hash := hasher(e.key, destTable.seed)
+ bidx := uint64(len(destTable.buckets)-1) & h1(hash)
+ destb := &destTable.buckets[bidx]
+ appendToBucketOf(h2(hash), b.entries[i], destb)
+ copied++
+ }
+ }
+ if b.next == nil {
+ rootb.mu.Unlock()
+ return
+ }
+ b = (*bucketOfPadded)(b.next)
+ }
+}
+
+// Range calls f sequentially for each key and value present in the
+// map. If f returns false, range stops the iteration.
+//
+// Range does not necessarily correspond to any consistent snapshot
+// of the Map's contents: no key will be visited more than once, but
+// if the value for any key is stored or deleted concurrently, Range
+// may reflect any mapping for that key from any point during the
+// Range call.
+//
+// It is safe to modify the map while iterating it, including entry
+// creation, modification and deletion. However, the concurrent
+// modification rule apply, i.e. the changes may be not reflected
+// in the subsequently iterated entries.
+func (m *MapOf[K, V]) Range(f func(key K, value V) bool) {
+ var zeroPtr unsafe.Pointer
+ // Pre-allocate array big enough to fit entries for most hash tables.
+ bentries := make([]unsafe.Pointer, 0, 16*entriesPerMapOfBucket)
+ tablep := atomic.LoadPointer(&m.table)
+ table := *(*mapOfTable[K, V])(tablep)
+ for i := range table.buckets {
+ rootb := &table.buckets[i]
+ b := rootb
+ // Prevent concurrent modifications and copy all entries into
+ // the intermediate slice.
+ rootb.mu.Lock()
+ for {
+ for i := 0; i < entriesPerMapOfBucket; i++ {
+ if b.entries[i] != nil {
+ bentries = append(bentries, b.entries[i])
+ }
+ }
+ if b.next == nil {
+ rootb.mu.Unlock()
+ break
+ }
+ b = (*bucketOfPadded)(b.next)
+ }
+ // Call the function for all copied entries.
+ for j := range bentries {
+ entry := (*entryOf[K, V])(bentries[j])
+ if !f(entry.key, entry.value) {
+ return
+ }
+ // Remove the reference to avoid preventing the copied
+ // entries from being GCed until this method finishes.
+ bentries[j] = zeroPtr
+ }
+ bentries = bentries[:0]
+ }
+}
+
+// Clear deletes all keys and values currently stored in the map.
+func (m *MapOf[K, V]) Clear() {
+ table := (*mapOfTable[K, V])(atomic.LoadPointer(&m.table))
+ m.resize(table, mapClearHint)
+}
+
+// Size returns current size of the map.
+func (m *MapOf[K, V]) Size() int {
+ table := (*mapOfTable[K, V])(atomic.LoadPointer(&m.table))
+ return int(table.sumSize())
+}
+
+func appendToBucketOf(h2 uint8, entryPtr unsafe.Pointer, b *bucketOfPadded) {
+ for {
+ for i := 0; i < entriesPerMapOfBucket; i++ {
+ if b.entries[i] == nil {
+ b.meta = setByte(b.meta, h2, i)
+ b.entries[i] = entryPtr
+ return
+ }
+ }
+ if b.next == nil {
+ newb := new(bucketOfPadded)
+ newb.meta = setByte(defaultMeta, h2, 0)
+ newb.entries[0] = entryPtr
+ b.next = unsafe.Pointer(newb)
+ return
+ }
+ b = (*bucketOfPadded)(b.next)
+ }
+}
+
+func (table *mapOfTable[K, V]) addSize(bucketIdx uint64, delta int) {
+ cidx := uint64(len(table.size)-1) & bucketIdx
+ atomic.AddInt64(&table.size[cidx].c, int64(delta))
+}
+
+func (table *mapOfTable[K, V]) addSizePlain(bucketIdx uint64, delta int) {
+ cidx := uint64(len(table.size)-1) & bucketIdx
+ table.size[cidx].c += int64(delta)
+}
+
+func (table *mapOfTable[K, V]) sumSize() int64 {
+ sum := int64(0)
+ for i := range table.size {
+ sum += atomic.LoadInt64(&table.size[i].c)
+ }
+ return sum
+}
+
+func h1(h uint64) uint64 {
+ return h >> 7
+}
+
+func h2(h uint64) uint8 {
+ return uint8(h & 0x7f)
+}
+
+// Stats returns statistics for the MapOf. Just like other map
+// methods, this one is thread-safe. Yet it's an O(N) operation,
+// so it should be used only for diagnostics or debugging purposes.
+func (m *MapOf[K, V]) Stats() MapStats {
+ stats := MapStats{
+ TotalGrowths: atomic.LoadInt64(&m.totalGrowths),
+ TotalShrinks: atomic.LoadInt64(&m.totalShrinks),
+ MinEntries: math.MaxInt32,
+ }
+ table := (*mapOfTable[K, V])(atomic.LoadPointer(&m.table))
+ stats.RootBuckets = len(table.buckets)
+ stats.Counter = int(table.sumSize())
+ stats.CounterLen = len(table.size)
+ for i := range table.buckets {
+ nentries := 0
+ b := &table.buckets[i]
+ stats.TotalBuckets++
+ for {
+ nentriesLocal := 0
+ stats.Capacity += entriesPerMapOfBucket
+ for i := 0; i < entriesPerMapOfBucket; i++ {
+ if atomic.LoadPointer(&b.entries[i]) != nil {
+ stats.Size++
+ nentriesLocal++
+ }
+ }
+ nentries += nentriesLocal
+ if nentriesLocal == 0 {
+ stats.EmptyBuckets++
+ }
+ if b.next == nil {
+ break
+ }
+ b = (*bucketOfPadded)(atomic.LoadPointer(&b.next))
+ stats.TotalBuckets++
+ }
+ if nentries < stats.MinEntries {
+ stats.MinEntries = nentries
+ }
+ if nentries > stats.MaxEntries {
+ stats.MaxEntries = nentries
+ }
+ }
+ return stats
+}
diff --git a/vendor/github.com/puzpuzpuz/xsync/v3/mpmcqueue.go b/vendor/github.com/puzpuzpuz/xsync/v3/mpmcqueue.go
new file mode 100644
index 0000000..96584e6
--- /dev/null
+++ b/vendor/github.com/puzpuzpuz/xsync/v3/mpmcqueue.go
@@ -0,0 +1,137 @@
+package xsync
+
+import (
+ "runtime"
+ "sync/atomic"
+ "unsafe"
+)
+
+// A MPMCQueue is a bounded multi-producer multi-consumer concurrent
+// queue.
+//
+// MPMCQueue instances must be created with NewMPMCQueue function.
+// A MPMCQueue must not be copied after first use.
+//
+// Based on the data structure from the following C++ library:
+// https://github.com/rigtorp/MPMCQueue
+type MPMCQueue struct {
+ cap uint64
+ head uint64
+ //lint:ignore U1000 prevents false sharing
+ hpad [cacheLineSize - 8]byte
+ tail uint64
+ //lint:ignore U1000 prevents false sharing
+ tpad [cacheLineSize - 8]byte
+ slots []slotPadded
+}
+
+type slotPadded struct {
+ slot
+ //lint:ignore U1000 prevents false sharing
+ pad [cacheLineSize - unsafe.Sizeof(slot{})]byte
+}
+
+type slot struct {
+ turn uint64
+ item interface{}
+}
+
+// NewMPMCQueue creates a new MPMCQueue instance with the given
+// capacity.
+func NewMPMCQueue(capacity int) *MPMCQueue {
+ if capacity < 1 {
+ panic("capacity must be positive number")
+ }
+ return &MPMCQueue{
+ cap: uint64(capacity),
+ slots: make([]slotPadded, capacity),
+ }
+}
+
+// Enqueue inserts the given item into the queue.
+// Blocks, if the queue is full.
+func (q *MPMCQueue) Enqueue(item interface{}) {
+ head := atomic.AddUint64(&q.head, 1) - 1
+ slot := &q.slots[q.idx(head)]
+ turn := q.turn(head) * 2
+ for atomic.LoadUint64(&slot.turn) != turn {
+ runtime.Gosched()
+ }
+ slot.item = item
+ atomic.StoreUint64(&slot.turn, turn+1)
+}
+
+// Dequeue retrieves and removes the item from the head of the queue.
+// Blocks, if the queue is empty.
+func (q *MPMCQueue) Dequeue() interface{} {
+ tail := atomic.AddUint64(&q.tail, 1) - 1
+ slot := &q.slots[q.idx(tail)]
+ turn := q.turn(tail)*2 + 1
+ for atomic.LoadUint64(&slot.turn) != turn {
+ runtime.Gosched()
+ }
+ item := slot.item
+ slot.item = nil
+ atomic.StoreUint64(&slot.turn, turn+1)
+ return item
+}
+
+// TryEnqueue inserts the given item into the queue. Does not block
+// and returns immediately. The result indicates that the queue isn't
+// full and the item was inserted.
+func (q *MPMCQueue) TryEnqueue(item interface{}) bool {
+ head := atomic.LoadUint64(&q.head)
+ for {
+ slot := &q.slots[q.idx(head)]
+ turn := q.turn(head) * 2
+ if atomic.LoadUint64(&slot.turn) == turn {
+ if atomic.CompareAndSwapUint64(&q.head, head, head+1) {
+ slot.item = item
+ atomic.StoreUint64(&slot.turn, turn+1)
+ return true
+ }
+ } else {
+ prevHead := head
+ head = atomic.LoadUint64(&q.head)
+ if head == prevHead {
+ return false
+ }
+ }
+ runtime.Gosched()
+ }
+}
+
+// TryDequeue retrieves and removes the item from the head of the
+// queue. Does not block and returns immediately. The ok result
+// indicates that the queue isn't empty and an item was retrieved.
+func (q *MPMCQueue) TryDequeue() (item interface{}, ok bool) {
+ tail := atomic.LoadUint64(&q.tail)
+ for {
+ slot := &q.slots[q.idx(tail)]
+ turn := q.turn(tail)*2 + 1
+ if atomic.LoadUint64(&slot.turn) == turn {
+ if atomic.CompareAndSwapUint64(&q.tail, tail, tail+1) {
+ item = slot.item
+ ok = true
+ slot.item = nil
+ atomic.StoreUint64(&slot.turn, turn+1)
+ return
+ }
+ } else {
+ prevTail := tail
+ tail = atomic.LoadUint64(&q.tail)
+ if tail == prevTail {
+ return
+ }
+ }
+ runtime.Gosched()
+ }
+}
+
+func (q *MPMCQueue) idx(i uint64) uint64 {
+ return i % q.cap
+}
+
+func (q *MPMCQueue) turn(i uint64) uint64 {
+ return i / q.cap
+}
diff --git a/vendor/github.com/puzpuzpuz/xsync/v3/mpmcqueueof.go b/vendor/github.com/puzpuzpuz/xsync/v3/mpmcqueueof.go
new file mode 100644
index 0000000..38a8fa3
--- /dev/null
+++ b/vendor/github.com/puzpuzpuz/xsync/v3/mpmcqueueof.go
@@ -0,0 +1,150 @@
+//go:build go1.19
+// +build go1.19
+
+package xsync
+
+import (
+ "runtime"
+ "sync/atomic"
+ "unsafe"
+)
+
+// A MPMCQueueOf is a bounded multi-producer multi-consumer concurrent
+// queue. It's a generic version of MPMCQueue.
+//
+// MPMCQueue instances must be created with NewMPMCQueueOf function.
+// A MPMCQueueOf must not be copied after first use.
+//
+// Based on the data structure from the following C++ library:
+// https://github.com/rigtorp/MPMCQueue
+type MPMCQueueOf[I any] struct {
+ cap uint64
+ head uint64
+ //lint:ignore U1000 prevents false sharing
+ hpad [cacheLineSize - 8]byte
+ tail uint64
+ //lint:ignore U1000 prevents false sharing
+ tpad [cacheLineSize - 8]byte
+ slots []slotOfPadded[I]
+}
+
+type slotOfPadded[I any] struct {
+ slotOf[I]
+ // Unfortunately, proper padding like the below one:
+ //
+ // pad [cacheLineSize - (unsafe.Sizeof(slotOf[I]{}) % cacheLineSize)]byte
+ //
+ // won't compile, so here we add a best-effort padding for items up to
+ // 56 bytes size.
+ //lint:ignore U1000 prevents false sharing
+ pad [cacheLineSize - unsafe.Sizeof(atomic.Uint64{})]byte
+}
+
+type slotOf[I any] struct {
+ // atomic.Uint64 is used here to get proper 8 byte alignment on
+ // 32-bit archs.
+ turn atomic.Uint64
+ item I
+}
+
+// NewMPMCQueueOf creates a new MPMCQueueOf instance with the given
+// capacity.
+func NewMPMCQueueOf[I any](capacity int) *MPMCQueueOf[I] {
+ if capacity < 1 {
+ panic("capacity must be positive number")
+ }
+ return &MPMCQueueOf[I]{
+ cap: uint64(capacity),
+ slots: make([]slotOfPadded[I], capacity),
+ }
+}
+
+// Enqueue inserts the given item into the queue.
+// Blocks, if the queue is full.
+func (q *MPMCQueueOf[I]) Enqueue(item I) {
+ head := atomic.AddUint64(&q.head, 1) - 1
+ slot := &q.slots[q.idx(head)]
+ turn := q.turn(head) * 2
+ for slot.turn.Load() != turn {
+ runtime.Gosched()
+ }
+ slot.item = item
+ slot.turn.Store(turn + 1)
+}
+
+// Dequeue retrieves and removes the item from the head of the queue.
+// Blocks, if the queue is empty.
+func (q *MPMCQueueOf[I]) Dequeue() I {
+ var zeroedI I
+ tail := atomic.AddUint64(&q.tail, 1) - 1
+ slot := &q.slots[q.idx(tail)]
+ turn := q.turn(tail)*2 + 1
+ for slot.turn.Load() != turn {
+ runtime.Gosched()
+ }
+ item := slot.item
+ slot.item = zeroedI
+ slot.turn.Store(turn + 1)
+ return item
+}
+
+// TryEnqueue inserts the given item into the queue. Does not block
+// and returns immediately. The result indicates that the queue isn't
+// full and the item was inserted.
+func (q *MPMCQueueOf[I]) TryEnqueue(item I) bool {
+ head := atomic.LoadUint64(&q.head)
+ for {
+ slot := &q.slots[q.idx(head)]
+ turn := q.turn(head) * 2
+ if slot.turn.Load() == turn {
+ if atomic.CompareAndSwapUint64(&q.head, head, head+1) {
+ slot.item = item
+ slot.turn.Store(turn + 1)
+ return true
+ }
+ } else {
+ prevHead := head
+ head = atomic.LoadUint64(&q.head)
+ if head == prevHead {
+ return false
+ }
+ }
+ runtime.Gosched()
+ }
+}
+
+// TryDequeue retrieves and removes the item from the head of the
+// queue. Does not block and returns immediately. The ok result
+// indicates that the queue isn't empty and an item was retrieved.
+func (q *MPMCQueueOf[I]) TryDequeue() (item I, ok bool) {
+ tail := atomic.LoadUint64(&q.tail)
+ for {
+ slot := &q.slots[q.idx(tail)]
+ turn := q.turn(tail)*2 + 1
+ if slot.turn.Load() == turn {
+ if atomic.CompareAndSwapUint64(&q.tail, tail, tail+1) {
+ var zeroedI I
+ item = slot.item
+ ok = true
+ slot.item = zeroedI
+ slot.turn.Store(turn + 1)
+ return
+ }
+ } else {
+ prevTail := tail
+ tail = atomic.LoadUint64(&q.tail)
+ if tail == prevTail {
+ return
+ }
+ }
+ runtime.Gosched()
+ }
+}
+
+func (q *MPMCQueueOf[I]) idx(i uint64) uint64 {
+ return i % q.cap
+}
+
+func (q *MPMCQueueOf[I]) turn(i uint64) uint64 {
+ return i / q.cap
+}
diff --git a/vendor/github.com/puzpuzpuz/xsync/v3/rbmutex.go b/vendor/github.com/puzpuzpuz/xsync/v3/rbmutex.go
new file mode 100644
index 0000000..4cbd9c4
--- /dev/null
+++ b/vendor/github.com/puzpuzpuz/xsync/v3/rbmutex.go
@@ -0,0 +1,188 @@
+package xsync
+
+import (
+ "runtime"
+ "sync"
+ "sync/atomic"
+ "time"
+)
+
+// slow-down guard
+const nslowdown = 7
+
+// pool for reader tokens
+var rtokenPool sync.Pool
+
+// RToken is a reader lock token.
+type RToken struct {
+ slot uint32
+ //lint:ignore U1000 prevents false sharing
+ pad [cacheLineSize - 4]byte
+}
+
+// A RBMutex is a reader biased reader/writer mutual exclusion lock.
+// The lock can be held by an many readers or a single writer.
+// The zero value for a RBMutex is an unlocked mutex.
+//
+// A RBMutex must not be copied after first use.
+//
+// RBMutex is based on a modified version of BRAVO
+// (Biased Locking for Reader-Writer Locks) algorithm:
+// https://arxiv.org/pdf/1810.01553.pdf
+//
+// RBMutex is a specialized mutex for scenarios, such as caches,
+// where the vast majority of locks are acquired by readers and write
+// lock acquire attempts are infrequent. In such scenarios, RBMutex
+// performs better than sync.RWMutex on large multicore machines.
+//
+// RBMutex extends sync.RWMutex internally and uses it as the "reader
+// bias disabled" fallback, so the same semantics apply. The only
+// noticeable difference is in reader tokens returned from the
+// RLock/RUnlock methods.
+type RBMutex struct {
+ rslots []rslot
+ rmask uint32
+ rbias int32
+ inhibitUntil time.Time
+ rw sync.RWMutex
+}
+
+type rslot struct {
+ mu int32
+ //lint:ignore U1000 prevents false sharing
+ pad [cacheLineSize - 4]byte
+}
+
+// NewRBMutex creates a new RBMutex instance.
+func NewRBMutex() *RBMutex {
+ nslots := nextPowOf2(parallelism())
+ mu := RBMutex{
+ rslots: make([]rslot, nslots),
+ rmask: nslots - 1,
+ rbias: 1,
+ }
+ return &mu
+}
+
+// TryRLock tries to lock m for reading without blocking.
+// When TryRLock succeeds, it returns true and a reader token.
+// In case of a failure, a false is returned.
+func (mu *RBMutex) TryRLock() (bool, *RToken) {
+ if t := mu.fastRlock(); t != nil {
+ return true, t
+ }
+ // Optimistic slow path.
+ if mu.rw.TryRLock() {
+ if atomic.LoadInt32(&mu.rbias) == 0 && time.Now().After(mu.inhibitUntil) {
+ atomic.StoreInt32(&mu.rbias, 1)
+ }
+ return true, nil
+ }
+ return false, nil
+}
+
+// RLock locks m for reading and returns a reader token. The
+// token must be used in the later RUnlock call.
+//
+// Should not be used for recursive read locking; a blocked Lock
+// call excludes new readers from acquiring the lock.
+func (mu *RBMutex) RLock() *RToken {
+ if t := mu.fastRlock(); t != nil {
+ return t
+ }
+ // Slow path.
+ mu.rw.RLock()
+ if atomic.LoadInt32(&mu.rbias) == 0 && time.Now().After(mu.inhibitUntil) {
+ atomic.StoreInt32(&mu.rbias, 1)
+ }
+ return nil
+}
+
+func (mu *RBMutex) fastRlock() *RToken {
+ if atomic.LoadInt32(&mu.rbias) == 1 {
+ t, ok := rtokenPool.Get().(*RToken)
+ if !ok {
+ t = new(RToken)
+ t.slot = runtime_fastrand()
+ }
+ // Try all available slots to distribute reader threads to slots.
+ for i := 0; i < len(mu.rslots); i++ {
+ slot := t.slot + uint32(i)
+ rslot := &mu.rslots[slot&mu.rmask]
+ rslotmu := atomic.LoadInt32(&rslot.mu)
+ if atomic.CompareAndSwapInt32(&rslot.mu, rslotmu, rslotmu+1) {
+ if atomic.LoadInt32(&mu.rbias) == 1 {
+ // Hot path succeeded.
+ t.slot = slot
+ return t
+ }
+ // The mutex is no longer reader biased. Roll back.
+ atomic.AddInt32(&rslot.mu, -1)
+ rtokenPool.Put(t)
+ return nil
+ }
+ // Contention detected. Give a try with the next slot.
+ }
+ }
+ return nil
+}
+
+// RUnlock undoes a single RLock call. A reader token obtained from
+// the RLock call must be provided. RUnlock does not affect other
+// simultaneous readers. A panic is raised if m is not locked for
+// reading on entry to RUnlock.
+func (mu *RBMutex) RUnlock(t *RToken) {
+ if t == nil {
+ mu.rw.RUnlock()
+ return
+ }
+ if atomic.AddInt32(&mu.rslots[t.slot&mu.rmask].mu, -1) < 0 {
+ panic("invalid reader state detected")
+ }
+ rtokenPool.Put(t)
+}
+
+// TryLock tries to lock m for writing without blocking.
+func (mu *RBMutex) TryLock() bool {
+ if mu.rw.TryLock() {
+ if atomic.LoadInt32(&mu.rbias) == 1 {
+ atomic.StoreInt32(&mu.rbias, 0)
+ for i := 0; i < len(mu.rslots); i++ {
+ if atomic.LoadInt32(&mu.rslots[i].mu) > 0 {
+ // There is a reader. Roll back.
+ atomic.StoreInt32(&mu.rbias, 1)
+ mu.rw.Unlock()
+ return false
+ }
+ }
+ }
+ return true
+ }
+ return false
+}
+
+// Lock locks m for writing. If the lock is already locked for
+// reading or writing, Lock blocks until the lock is available.
+func (mu *RBMutex) Lock() {
+ mu.rw.Lock()
+ if atomic.LoadInt32(&mu.rbias) == 1 {
+ atomic.StoreInt32(&mu.rbias, 0)
+ start := time.Now()
+ for i := 0; i < len(mu.rslots); i++ {
+ for atomic.LoadInt32(&mu.rslots[i].mu) > 0 {
+ runtime.Gosched()
+ }
+ }
+ mu.inhibitUntil = time.Now().Add(time.Since(start) * nslowdown)
+ }
+}
+
+// Unlock unlocks m for writing. A panic is raised if m is not locked
+// for writing on entry to Unlock.
+//
+// As with RWMutex, a locked RBMutex is not associated with a
+// particular goroutine. One goroutine may RLock (Lock) a RBMutex and
+// then arrange for another goroutine to RUnlock (Unlock) it.
+func (mu *RBMutex) Unlock() {
+ mu.rw.Unlock()
+}
diff --git a/vendor/github.com/puzpuzpuz/xsync/v3/util.go b/vendor/github.com/puzpuzpuz/xsync/v3/util.go
new file mode 100644
index 0000000..7692708
--- /dev/null
+++ b/vendor/github.com/puzpuzpuz/xsync/v3/util.go
@@ -0,0 +1,66 @@
+package xsync
+
+import (
+ "math/bits"
+ "runtime"
+ _ "unsafe"
+)
+
+// test-only assert()-like flag
+var assertionsEnabled = false
+
+const (
+ // cacheLineSize is used in paddings to prevent false sharing;
+ // 64B are used instead of 128B as a compromise between
+ // memory footprint and performance; 128B usage may give ~30%
+ // improvement on NUMA machines.
+ cacheLineSize = 64
+)
+
+// nextPowOf2 computes the next highest power of 2 of 32-bit v.
+// Source: https://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
+func nextPowOf2(v uint32) uint32 {
+ if v == 0 {
+ return 1
+ }
+ v--
+ v |= v >> 1
+ v |= v >> 2
+ v |= v >> 4
+ v |= v >> 8
+ v |= v >> 16
+ v++
+ return v
+}
+
+func parallelism() uint32 {
+ maxProcs := uint32(runtime.GOMAXPROCS(0))
+ numCores := uint32(runtime.NumCPU())
+ if maxProcs < numCores {
+ return maxProcs
+ }
+ return numCores
+}
+
+//go:noescape
+//go:linkname runtime_fastrand runtime.fastrand
+func runtime_fastrand() uint32
+
+func broadcast(b uint8) uint64 {
+ return 0x101010101010101 * uint64(b)
+}
+
+func firstMarkedByteIndex(w uint64) int {
+ return bits.TrailingZeros64(w) >> 3
+}
+
+// SWAR byte search: may produce false positives, e.g. for 0x0100,
+// so make sure to double-check bytes found by this function.
+func markZeroBytes(w uint64) uint64 {
+ return ((w - 0x0101010101010101) & (^w) & 0x8080808080808080)
+}
+
+func setByte(w uint64, b uint8, idx int) uint64 {
+ shift := idx << 3
+ return (w &^ (0xff << shift)) | (uint64(b) << shift)
+}
diff --git a/vendor/github.com/puzpuzpuz/xsync/v3/util_hash.go b/vendor/github.com/puzpuzpuz/xsync/v3/util_hash.go
new file mode 100644
index 0000000..9aa6597
--- /dev/null
+++ b/vendor/github.com/puzpuzpuz/xsync/v3/util_hash.go
@@ -0,0 +1,77 @@
+package xsync
+
+import (
+ "reflect"
+ "unsafe"
+)
+
+// makeSeed creates a random seed.
+func makeSeed() uint64 {
+ var s1 uint32
+ for {
+ s1 = runtime_fastrand()
+ // We use seed 0 to indicate an uninitialized seed/hash,
+ // so keep trying until we get a non-zero seed.
+ if s1 != 0 {
+ break
+ }
+ }
+ s2 := runtime_fastrand()
+ return uint64(s1)<<32 | uint64(s2)
+}
+
+// hashString calculates a hash of s with the given seed.
+func hashString(s string, seed uint64) uint64 {
+ if s == "" {
+ return seed
+ }
+ strh := (*reflect.StringHeader)(unsafe.Pointer(&s))
+ return uint64(runtime_memhash(unsafe.Pointer(strh.Data), uintptr(seed), uintptr(strh.Len)))
+}
+
+//go:noescape
+//go:linkname runtime_memhash runtime.memhash
+func runtime_memhash(p unsafe.Pointer, h, s uintptr) uintptr
+
+// defaultHasher creates a fast hash function for the given comparable type.
+// The only limitation is that the type should not contain interfaces inside
+// based on runtime.typehash.
+func defaultHasher[T comparable]() func(T, uint64) uint64 {
+ var zero T
+
+ if reflect.TypeOf(&zero).Elem().Kind() == reflect.Interface {
+ return func(value T, seed uint64) uint64 {
+ iValue := any(value)
+ i := (*iface)(unsafe.Pointer(&iValue))
+ return runtime_typehash64(i.typ, i.word, seed)
+ }
+ } else {
+ var iZero any = zero
+ i := (*iface)(unsafe.Pointer(&iZero))
+ return func(value T, seed uint64) uint64 {
+ return runtime_typehash64(i.typ, unsafe.Pointer(&value), seed)
+ }
+ }
+}
+
+// how interface is represented in memory
+type iface struct {
+ typ uintptr
+ word unsafe.Pointer
+}
+
+// same as runtime_typehash, but always returns a uint64
+// see: maphash.rthash function for details
+func runtime_typehash64(t uintptr, p unsafe.Pointer, seed uint64) uint64 {
+ if unsafe.Sizeof(uintptr(0)) == 8 {
+ return uint64(runtime_typehash(t, p, uintptr(seed)))
+ }
+
+ lo := runtime_typehash(t, p, uintptr(seed))
+ hi := runtime_typehash(t, p, uintptr(seed>>32))
+ return uint64(hi)<<32 | uint64(lo)
+}
+
+//go:noescape
+//go:linkname runtime_typehash runtime.typehash
+func runtime_typehash(t uintptr, p unsafe.Pointer, h uintptr) uintptr
diff --git a/vendor/github.com/rs/cors/.travis.yml b/vendor/github.com/rs/cors/.travis.yml
new file mode 100644
index 0000000..9a68b56
--- /dev/null
+++ b/vendor/github.com/rs/cors/.travis.yml
@@ -0,0 +1,9 @@
+language: go
+go:
+- "1.10"
+- "1.11"
+- "1.12"
+- tip
+matrix:
+ allow_failures:
+ - go: tip
diff --git a/vendor/github.com/rs/cors/LICENSE b/vendor/github.com/rs/cors/LICENSE
new file mode 100644
index 0000000..d8e2df5
--- /dev/null
+++ b/vendor/github.com/rs/cors/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2014 Olivier Poitrey
+
+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/rs/cors/README.md b/vendor/github.com/rs/cors/README.md
new file mode 100644
index 0000000..ecc83b2
--- /dev/null
+++ b/vendor/github.com/rs/cors/README.md
@@ -0,0 +1,115 @@
+# Go CORS handler [![godoc](http://img.shields.io/badge/godoc-reference-blue.svg?style=flat)](https://godoc.org/github.com/rs/cors) [![license](http://img.shields.io/badge/license-MIT-red.svg?style=flat)](https://raw.githubusercontent.com/rs/cors/master/LICENSE) [![build](https://img.shields.io/travis/rs/cors.svg?style=flat)](https://travis-ci.org/rs/cors) [![Coverage](http://gocover.io/_badge/github.com/rs/cors)](http://gocover.io/github.com/rs/cors)
+
+CORS is a `net/http` handler implementing [Cross Origin Resource Sharing W3 specification](http://www.w3.org/TR/cors/) in Golang.
+
+## Getting Started
+
+After installing Go and setting up your [GOPATH](http://golang.org/doc/code.html#GOPATH), create your first `.go` file. We'll call it `server.go`.
+
+```go
+package main
+
+import (
+ "net/http"
+
+ "github.com/rs/cors"
+)
+
+func main() {
+ mux := http.NewServeMux()
+ mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
+ w.Header().Set("Content-Type", "application/json")
+ w.Write([]byte("{\"hello\": \"world\"}"))
+ })
+
+ // cors.Default() setup the middleware with default options being
+ // all origins accepted with simple methods (GET, POST). See
+ // documentation below for more options.
+ handler := cors.Default().Handler(mux)
+ http.ListenAndServe(":8080", handler)
+}
+```
+
+Install `cors`:
+
+ go get github.com/rs/cors
+
+Then run your server:
+
+ go run server.go
+
+The server now runs on `localhost:8080`:
+
+ $ curl -D - -H 'Origin: http://foo.com' http://localhost:8080/
+ HTTP/1.1 200 OK
+ Access-Control-Allow-Origin: foo.com
+ Content-Type: application/json
+ Date: Sat, 25 Oct 2014 03:43:57 GMT
+ Content-Length: 18
+
+ {"hello": "world"}
+
+### Allow * With Credentials Security Protection
+
+This library has been modified to avoid a well known security issue when configured with `AllowedOrigins` to `*` and `AllowCredentials` to `true`. Such setup used to make the library reflects the request `Origin` header value, working around a security protection embedded into the standard that makes clients to refuse such configuration. This behavior has been removed with [#55](https://github.com/rs/cors/issues/55) and [#57](https://github.com/rs/cors/issues/57).
+
+If you depend on this behavior and understand the implications, you can restore it using the `AllowOriginFunc` with `func(origin string) {return true}`.
+
+Please refer to [#55](https://github.com/rs/cors/issues/55) for more information about the security implications.
+
+### More Examples
+
+* `net/http`: [examples/nethttp/server.go](https://github.com/rs/cors/blob/master/examples/nethttp/server.go)
+* [Goji](https://goji.io): [examples/goji/server.go](https://github.com/rs/cors/blob/master/examples/goji/server.go)
+* [Martini](http://martini.codegangsta.io): [examples/martini/server.go](https://github.com/rs/cors/blob/master/examples/martini/server.go)
+* [Negroni](https://github.com/codegangsta/negroni): [examples/negroni/server.go](https://github.com/rs/cors/blob/master/examples/negroni/server.go)
+* [Alice](https://github.com/justinas/alice): [examples/alice/server.go](https://github.com/rs/cors/blob/master/examples/alice/server.go)
+* [HttpRouter](https://github.com/julienschmidt/httprouter): [examples/httprouter/server.go](https://github.com/rs/cors/blob/master/examples/httprouter/server.go)
+* [Gorilla](http://www.gorillatoolkit.org/pkg/mux): [examples/gorilla/server.go](https://github.com/rs/cors/blob/master/examples/gorilla/server.go)
+* [Buffalo](https://gobuffalo.io): [examples/buffalo/server.go](https://github.com/rs/cors/blob/master/examples/buffalo/server.go)
+* [Gin](https://gin-gonic.github.io/gin): [examples/gin/server.go](https://github.com/rs/cors/blob/master/examples/gin/server.go)
+* [Chi](https://github.com/go-chi/chi): [examples/chi/server.go](https://github.com/rs/cors/blob/master/examples/chi/server.go)
+
+## Parameters
+
+Parameters are passed to the middleware thru the `cors.New` method as follow:
+
+```go
+c := cors.New(cors.Options{
+ AllowedOrigins: []string{"http://foo.com", "http://foo.com:8080"},
+ AllowCredentials: true,
+ // Enable Debugging for testing, consider disabling in production
+ Debug: true,
+})
+
+// Insert the middleware
+handler = c.Handler(handler)
+```
+
+* **AllowedOrigins** `[]string`: A list of origins a cross-domain request can be executed from. If the special `*` value is present in the list, all origins will be allowed. An origin may contain a wildcard (`*`) to replace 0 or more characters (i.e.: `http://*.domain.com`). Usage of wildcards implies a small performance penality. Only one wildcard can be used per origin. The default value is `*`.
+* **AllowOriginFunc** `func (origin string) bool`: A custom function to validate the origin. It takes the origin as an argument and returns true if allowed, or false otherwise. If this option is set, the content of `AllowedOrigins` is ignored.
+* **AllowOriginRequestFunc** `func (r *http.Request origin string) bool`: A custom function to validate the origin. It takes the HTTP Request object and the origin as argument and returns true if allowed or false otherwise. If this option is set, the content of `AllowedOrigins` and `AllowOriginFunc` is ignored
+* **AllowedMethods** `[]string`: A list of methods the client is allowed to use with cross-domain requests. Default value is simple methods (`GET` and `POST`).
+* **AllowedHeaders** `[]string`: A list of non simple headers the client is allowed to use with cross-domain requests.
+* **ExposedHeaders** `[]string`: Indicates which headers are safe to expose to the API of a CORS API specification
+* **AllowCredentials** `bool`: Indicates whether the request can include user credentials like cookies, HTTP authentication or client side SSL certificates. The default is `false`.
+* **MaxAge** `int`: Indicates how long (in seconds) the results of a preflight request can be cached. The default is `0` which stands for no max age.
+* **OptionsPassthrough** `bool`: Instructs preflight to let other potential next handlers to process the `OPTIONS` method. Turn this on if your application handles `OPTIONS`.
+* **Debug** `bool`: Debugging flag adds additional output to debug server side CORS issues.
+
+See [API documentation](http://godoc.org/github.com/rs/cors) for more info.
+
+## Benchmarks
+
+ BenchmarkWithout 20000000 64.6 ns/op 8 B/op 1 allocs/op
+ BenchmarkDefault 3000000 469 ns/op 114 B/op 2 allocs/op
+ BenchmarkAllowedOrigin 3000000 608 ns/op 114 B/op 2 allocs/op
+ BenchmarkPreflight 20000000 73.2 ns/op 0 B/op 0 allocs/op
+ BenchmarkPreflightHeader 20000000 73.6 ns/op 0 B/op 0 allocs/op
+ BenchmarkParseHeaderList 2000000 847 ns/op 184 B/op 6 allocs/op
+ BenchmarkParse…Single 5000000 290 ns/op 32 B/op 3 allocs/op
+ BenchmarkParse…Normalized 2000000 776 ns/op 160 B/op 6 allocs/op
+
+## Licenses
+
+All source code is licensed under the [MIT License](https://raw.github.com/rs/cors/master/LICENSE).
diff --git a/vendor/github.com/rs/cors/cors.go b/vendor/github.com/rs/cors/cors.go
new file mode 100644
index 0000000..2730934
--- /dev/null
+++ b/vendor/github.com/rs/cors/cors.go
@@ -0,0 +1,425 @@
+/*
+Package cors is net/http handler to handle CORS related requests
+as defined by http://www.w3.org/TR/cors/
+
+You can configure it by passing an option struct to cors.New:
+
+ c := cors.New(cors.Options{
+ AllowedOrigins: []string{"foo.com"},
+ AllowedMethods: []string{http.MethodGet, http.MethodPost, http.MethodDelete},
+ AllowCredentials: true,
+ })
+
+Then insert the handler in the chain:
+
+ handler = c.Handler(handler)
+
+See Options documentation for more options.
+
+The resulting handler is a standard net/http handler.
+*/
+package cors
+
+import (
+ "log"
+ "net/http"
+ "os"
+ "strconv"
+ "strings"
+)
+
+// Options is a configuration container to setup the CORS middleware.
+type Options struct {
+ // AllowedOrigins is a list of origins a cross-domain request can be executed from.
+ // If the special "*" value is present in the list, all origins will be allowed.
+ // An origin may contain a wildcard (*) to replace 0 or more characters
+ // (i.e.: http://*.domain.com). Usage of wildcards implies a small performance penalty.
+ // Only one wildcard can be used per origin.
+ // Default value is ["*"]
+ AllowedOrigins []string
+ // AllowOriginFunc is a custom function to validate the origin. It take the origin
+ // as argument and returns true if allowed or false otherwise. If this option is
+ // set, the content of AllowedOrigins is ignored.
+ AllowOriginFunc func(origin string) bool
+ // AllowOriginFunc is a custom function to validate the origin. It takes the HTTP Request object and the origin as
+ // argument and returns true if allowed or false otherwise. If this option is set, the content of `AllowedOrigins`
+ // and `AllowOriginFunc` is ignored.
+ AllowOriginRequestFunc func(r *http.Request, origin string) bool
+ // AllowedMethods is a list of methods the client is allowed to use with
+ // cross-domain requests. Default value is simple methods (HEAD, GET and POST).
+ AllowedMethods []string
+ // AllowedHeaders is list of non simple headers the client is allowed to use with
+ // cross-domain requests.
+ // If the special "*" value is present in the list, all headers will be allowed.
+ // Default value is [] but "Origin" is always appended to the list.
+ AllowedHeaders []string
+ // ExposedHeaders indicates which headers are safe to expose to the API of a CORS
+ // API specification
+ ExposedHeaders []string
+ // MaxAge indicates how long (in seconds) the results of a preflight request
+ // can be cached
+ MaxAge int
+ // AllowCredentials indicates whether the request can include user credentials like
+ // cookies, HTTP authentication or client side SSL certificates.
+ AllowCredentials bool
+ // OptionsPassthrough instructs preflight to let other potential next handlers to
+ // process the OPTIONS method. Turn this on if your application handles OPTIONS.
+ OptionsPassthrough bool
+ // Debugging flag adds additional output to debug server side CORS issues
+ Debug bool
+}
+
+// Logger generic interface for logger
+type Logger interface {
+ Printf(string, ...interface{})
+}
+
+// Cors http handler
+type Cors struct {
+ // Debug logger
+ Log Logger
+ // Normalized list of plain allowed origins
+ allowedOrigins []string
+ // List of allowed origins containing wildcards
+ allowedWOrigins []wildcard
+ // Optional origin validator function
+ allowOriginFunc func(origin string) bool
+ // Optional origin validator (with request) function
+ allowOriginRequestFunc func(r *http.Request, origin string) bool
+ // Normalized list of allowed headers
+ allowedHeaders []string
+ // Normalized list of allowed methods
+ allowedMethods []string
+ // Normalized list of exposed headers
+ exposedHeaders []string
+ maxAge int
+ // Set to true when allowed origins contains a "*"
+ allowedOriginsAll bool
+ // Set to true when allowed headers contains a "*"
+ allowedHeadersAll bool
+ allowCredentials bool
+ optionPassthrough bool
+}
+
+// New creates a new Cors handler with the provided options.
+func New(options Options) *Cors {
+ c := &Cors{
+ exposedHeaders: convert(options.ExposedHeaders, http.CanonicalHeaderKey),
+ allowOriginFunc: options.AllowOriginFunc,
+ allowOriginRequestFunc: options.AllowOriginRequestFunc,
+ allowCredentials: options.AllowCredentials,
+ maxAge: options.MaxAge,
+ optionPassthrough: options.OptionsPassthrough,
+ }
+ if options.Debug && c.Log == nil {
+ c.Log = log.New(os.Stdout, "[cors] ", log.LstdFlags)
+ }
+
+ // Normalize options
+ // Note: for origins and methods matching, the spec requires a case-sensitive matching.
+ // As it may error prone, we chose to ignore the spec here.
+
+ // Allowed Origins
+ if len(options.AllowedOrigins) == 0 {
+ if options.AllowOriginFunc == nil && options.AllowOriginRequestFunc == nil {
+ // Default is all origins
+ c.allowedOriginsAll = true
+ }
+ } else {
+ c.allowedOrigins = []string{}
+ c.allowedWOrigins = []wildcard{}
+ for _, origin := range options.AllowedOrigins {
+ // Normalize
+ origin = strings.ToLower(origin)
+ if origin == "*" {
+ // If "*" is present in the list, turn the whole list into a match all
+ c.allowedOriginsAll = true
+ c.allowedOrigins = nil
+ c.allowedWOrigins = nil
+ break
+ } else if i := strings.IndexByte(origin, '*'); i >= 0 {
+ // Split the origin in two: start and end string without the *
+ w := wildcard{origin[0:i], origin[i+1:]}
+ c.allowedWOrigins = append(c.allowedWOrigins, w)
+ } else {
+ c.allowedOrigins = append(c.allowedOrigins, origin)
+ }
+ }
+ }
+
+ // Allowed Headers
+ if len(options.AllowedHeaders) == 0 {
+ // Use sensible defaults
+ c.allowedHeaders = []string{"Origin", "Accept", "Content-Type", "X-Requested-With"}
+ } else {
+ // Origin is always appended as some browsers will always request for this header at preflight
+ c.allowedHeaders = convert(append(options.AllowedHeaders, "Origin"), http.CanonicalHeaderKey)
+ for _, h := range options.AllowedHeaders {
+ if h == "*" {
+ c.allowedHeadersAll = true
+ c.allowedHeaders = nil
+ break
+ }
+ }
+ }
+
+ // Allowed Methods
+ if len(options.AllowedMethods) == 0 {
+ // Default is spec's "simple" methods
+ c.allowedMethods = []string{http.MethodGet, http.MethodPost, http.MethodHead}
+ } else {
+ c.allowedMethods = convert(options.AllowedMethods, strings.ToUpper)
+ }
+
+ return c
+}
+
+// Default creates a new Cors handler with default options.
+func Default() *Cors {
+ return New(Options{})
+}
+
+// AllowAll create a new Cors handler with permissive configuration allowing all
+// origins with all standard methods with any header and credentials.
+func AllowAll() *Cors {
+ return New(Options{
+ AllowedOrigins: []string{"*"},
+ AllowedMethods: []string{
+ http.MethodHead,
+ http.MethodGet,
+ http.MethodPost,
+ http.MethodPut,
+ http.MethodPatch,
+ http.MethodDelete,
+ },
+ AllowedHeaders: []string{"*"},
+ AllowCredentials: false,
+ })
+}
+
+// Handler apply the CORS specification on the request, and add relevant CORS headers
+// as necessary.
+func (c *Cors) Handler(h http.Handler) http.Handler {
+ return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ if r.Method == http.MethodOptions && r.Header.Get("Access-Control-Request-Method") != "" {
+ c.logf("Handler: Preflight request")
+ c.handlePreflight(w, r)
+ // Preflight requests are standalone and should stop the chain as some other
+ // middleware may not handle OPTIONS requests correctly. One typical example
+ // is authentication middleware ; OPTIONS requests won't carry authentication
+ // headers (see #1)
+ if c.optionPassthrough {
+ h.ServeHTTP(w, r)
+ } else {
+ w.WriteHeader(http.StatusOK)
+ }
+ } else {
+ c.logf("Handler: Actual request")
+ c.handleActualRequest(w, r)
+ h.ServeHTTP(w, r)
+ }
+ })
+}
+
+// HandlerFunc provides Martini compatible handler
+func (c *Cors) HandlerFunc(w http.ResponseWriter, r *http.Request) {
+ if r.Method == http.MethodOptions && r.Header.Get("Access-Control-Request-Method") != "" {
+ c.logf("HandlerFunc: Preflight request")
+ c.handlePreflight(w, r)
+ } else {
+ c.logf("HandlerFunc: Actual request")
+ c.handleActualRequest(w, r)
+ }
+}
+
+// Negroni compatible interface
+func (c *Cors) ServeHTTP(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
+ if r.Method == http.MethodOptions && r.Header.Get("Access-Control-Request-Method") != "" {
+ c.logf("ServeHTTP: Preflight request")
+ c.handlePreflight(w, r)
+ // Preflight requests are standalone and should stop the chain as some other
+ // middleware may not handle OPTIONS requests correctly. One typical example
+ // is authentication middleware ; OPTIONS requests won't carry authentication
+ // headers (see #1)
+ if c.optionPassthrough {
+ next(w, r)
+ } else {
+ w.WriteHeader(http.StatusOK)
+ }
+ } else {
+ c.logf("ServeHTTP: Actual request")
+ c.handleActualRequest(w, r)
+ next(w, r)
+ }
+}
+
+// handlePreflight handles pre-flight CORS requests
+func (c *Cors) handlePreflight(w http.ResponseWriter, r *http.Request) {
+ headers := w.Header()
+ origin := r.Header.Get("Origin")
+
+ if r.Method != http.MethodOptions {
+ c.logf(" Preflight aborted: %s!=OPTIONS", r.Method)
+ return
+ }
+ // Always set Vary headers
+ // see https://github.com/rs/cors/issues/10,
+ // https://github.com/rs/cors/commit/dbdca4d95feaa7511a46e6f1efb3b3aa505bc43f#commitcomment-12352001
+ headers.Add("Vary", "Origin")
+ headers.Add("Vary", "Access-Control-Request-Method")
+ headers.Add("Vary", "Access-Control-Request-Headers")
+
+ if origin == "" {
+ c.logf(" Preflight aborted: empty origin")
+ return
+ }
+ if !c.isOriginAllowed(r, origin) {
+ c.logf(" Preflight aborted: origin '%s' not allowed", origin)
+ return
+ }
+
+ reqMethod := r.Header.Get("Access-Control-Request-Method")
+ if !c.isMethodAllowed(reqMethod) {
+ c.logf(" Preflight aborted: method '%s' not allowed", reqMethod)
+ return
+ }
+ reqHeaders := parseHeaderList(r.Header.Get("Access-Control-Request-Headers"))
+ if !c.areHeadersAllowed(reqHeaders) {
+ c.logf(" Preflight aborted: headers '%v' not allowed", reqHeaders)
+ return
+ }
+ if c.allowedOriginsAll {
+ headers.Set("Access-Control-Allow-Origin", "*")
+ } else {
+ headers.Set("Access-Control-Allow-Origin", origin)
+ }
+ // Spec says: Since the list of methods can be unbounded, simply returning the method indicated
+ // by Access-Control-Request-Method (if supported) can be enough
+ headers.Set("Access-Control-Allow-Methods", strings.ToUpper(reqMethod))
+ if len(reqHeaders) > 0 {
+
+ // Spec says: Since the list of headers can be unbounded, simply returning supported headers
+ // from Access-Control-Request-Headers can be enough
+ headers.Set("Access-Control-Allow-Headers", strings.Join(reqHeaders, ", "))
+ }
+ if c.allowCredentials {
+ headers.Set("Access-Control-Allow-Credentials", "true")
+ }
+ if c.maxAge > 0 {
+ headers.Set("Access-Control-Max-Age", strconv.Itoa(c.maxAge))
+ }
+ c.logf(" Preflight response headers: %v", headers)
+}
+
+// handleActualRequest handles simple cross-origin requests, actual request or redirects
+func (c *Cors) handleActualRequest(w http.ResponseWriter, r *http.Request) {
+ headers := w.Header()
+ origin := r.Header.Get("Origin")
+
+ // Always set Vary, see https://github.com/rs/cors/issues/10
+ headers.Add("Vary", "Origin")
+ if origin == "" {
+ c.logf(" Actual request no headers added: missing origin")
+ return
+ }
+ if !c.isOriginAllowed(r, origin) {
+ c.logf(" Actual request no headers added: origin '%s' not allowed", origin)
+ return
+ }
+
+ // Note that spec does define a way to specifically disallow a simple method like GET or
+ // POST. Access-Control-Allow-Methods is only used for pre-flight requests and the
+ // spec doesn't instruct to check the allowed methods for simple cross-origin requests.
+ // We think it's a nice feature to be able to have control on those methods though.
+ if !c.isMethodAllowed(r.Method) {
+ c.logf(" Actual request no headers added: method '%s' not allowed", r.Method)
+
+ return
+ }
+ if c.allowedOriginsAll {
+ headers.Set("Access-Control-Allow-Origin", "*")
+ } else {
+ headers.Set("Access-Control-Allow-Origin", origin)
+ }
+ if len(c.exposedHeaders) > 0 {
+ headers.Set("Access-Control-Expose-Headers", strings.Join(c.exposedHeaders, ", "))
+ }
+ if c.allowCredentials {
+ headers.Set("Access-Control-Allow-Credentials", "true")
+ }
+ c.logf(" Actual response added headers: %v", headers)
+}
+
+// convenience method. checks if a logger is set.
+func (c *Cors) logf(format string, a ...interface{}) {
+ if c.Log != nil {
+ c.Log.Printf(format, a...)
+ }
+}
+
+// isOriginAllowed checks if a given origin is allowed to perform cross-domain requests
+// on the endpoint
+func (c *Cors) isOriginAllowed(r *http.Request, origin string) bool {
+ if c.allowOriginRequestFunc != nil {
+ return c.allowOriginRequestFunc(r, origin)
+ }
+ if c.allowOriginFunc != nil {
+ return c.allowOriginFunc(origin)
+ }
+ if c.allowedOriginsAll {
+ return true
+ }
+ origin = strings.ToLower(origin)
+ for _, o := range c.allowedOrigins {
+ if o == origin {
+ return true
+ }
+ }
+ for _, w := range c.allowedWOrigins {
+ if w.match(origin) {
+ return true
+ }
+ }
+ return false
+}
+
+// isMethodAllowed checks if a given method can be used as part of a cross-domain request
+// on the endpoing
+func (c *Cors) isMethodAllowed(method string) bool {
+ if len(c.allowedMethods) == 0 {
+ // If no method allowed, always return false, even for preflight request
+ return false
+ }
+ method = strings.ToUpper(method)
+ if method == http.MethodOptions {
+ // Always allow preflight requests
+ return true
+ }
+ for _, m := range c.allowedMethods {
+ if m == method {
+ return true
+ }
+ }
+ return false
+}
+
+// areHeadersAllowed checks if a given list of headers are allowed to used within
+// a cross-domain request.
+func (c *Cors) areHeadersAllowed(requestedHeaders []string) bool {
+ if c.allowedHeadersAll || len(requestedHeaders) == 0 {
+ return true
+ }
+ for _, header := range requestedHeaders {
+ header = http.CanonicalHeaderKey(header)
+ found := false
+ for _, h := range c.allowedHeaders {
+ if h == header {
+ found = true
+ }
+ }
+ if !found {
+ return false
+ }
+ }
+ return true
+}
diff --git a/vendor/github.com/rs/cors/utils.go b/vendor/github.com/rs/cors/utils.go
new file mode 100644
index 0000000..db83ac3
--- /dev/null
+++ b/vendor/github.com/rs/cors/utils.go
@@ -0,0 +1,71 @@
+package cors
+
+import "strings"
+
+const toLower = 'a' - 'A'
+
+type converter func(string) string
+
+type wildcard struct {
+ prefix string
+ suffix string
+}
+
+func (w wildcard) match(s string) bool {
+ return len(s) >= len(w.prefix)+len(w.suffix) && strings.HasPrefix(s, w.prefix) && strings.HasSuffix(s, w.suffix)
+}
+
+// convert converts a list of string using the passed converter function
+func convert(s []string, c converter) []string {
+ out := []string{}
+ for _, i := range s {
+ out = append(out, c(i))
+ }
+ return out
+}
+
+// parseHeaderList tokenize + normalize a string containing a list of headers
+func parseHeaderList(headerList string) []string {
+ l := len(headerList)
+ h := make([]byte, 0, l)
+ upper := true
+ // Estimate the number headers in order to allocate the right splice size
+ t := 0
+ for i := 0; i < l; i++ {
+ if headerList[i] == ',' {
+ t++
+ }
+ }
+ headers := make([]string, 0, t)
+ for i := 0; i < l; i++ {
+ b := headerList[i]
+ switch {
+ case b >= 'a' && b <= 'z':
+ if upper {
+ h = append(h, b-toLower)
+ } else {
+ h = append(h, b)
+ }
+ case b >= 'A' && b <= 'Z':
+ if !upper {
+ h = append(h, b+toLower)
+ } else {
+ h = append(h, b)
+ }
+ case b == '-' || b == '_' || (b >= '0' && b <= '9'):
+ h = append(h, b)
+ }
+
+ if b == ' ' || b == ',' || i == l-1 {
+ if len(h) > 0 {
+ // Flush the found header
+ headers = append(headers, string(h))
+ h = h[:0]
+ upper = true
+ }
+ } else {
+ upper = b == '-' || b == '_'
+ }
+ }
+ return headers
+}
diff --git a/vendor/github.com/rs/zerolog/.gitignore b/vendor/github.com/rs/zerolog/.gitignore
new file mode 100644
index 0000000..8ebe58b
--- /dev/null
+++ b/vendor/github.com/rs/zerolog/.gitignore
@@ -0,0 +1,25 @@
+# Compiled Object files, Static and Dynamic libs (Shared Objects)
+*.o
+*.a
+*.so
+
+# Folders
+_obj
+_test
+tmp
+
+# Architecture specific extensions/prefixes
+*.[568vq]
+[568vq].out
+
+*.cgo1.go
+*.cgo2.c
+_cgo_defun.c
+_cgo_gotypes.go
+_cgo_export.*
+
+_testmain.go
+
+*.exe
+*.test
+*.prof
diff --git a/vendor/github.com/rs/zerolog/CNAME b/vendor/github.com/rs/zerolog/CNAME
new file mode 100644
index 0000000..9ce57a6
--- /dev/null
+++ b/vendor/github.com/rs/zerolog/CNAME
@@ -0,0 +1 @@
+zerolog.io
\ No newline at end of file
diff --git a/vendor/github.com/rs/zerolog/LICENSE b/vendor/github.com/rs/zerolog/LICENSE
new file mode 100644
index 0000000..677e07f
--- /dev/null
+++ b/vendor/github.com/rs/zerolog/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2017 Olivier Poitrey
+
+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/rs/zerolog/README.md b/vendor/github.com/rs/zerolog/README.md
new file mode 100644
index 0000000..1306a6c
--- /dev/null
+++ b/vendor/github.com/rs/zerolog/README.md
@@ -0,0 +1,782 @@
+# Zero Allocation JSON Logger
+
+[![godoc](http://img.shields.io/badge/godoc-reference-blue.svg?style=flat)](https://godoc.org/github.com/rs/zerolog) [![license](http://img.shields.io/badge/license-MIT-red.svg?style=flat)](https://raw.githubusercontent.com/rs/zerolog/master/LICENSE) [![Build Status](https://github.com/rs/zerolog/actions/workflows/test.yml/badge.svg)](https://github.com/rs/zerolog/actions/workflows/test.yml) [![Go Coverage](https://github.com/rs/zerolog/wiki/coverage.svg)](https://raw.githack.com/wiki/rs/zerolog/coverage.html)
+
+The zerolog package provides a fast and simple logger dedicated to JSON output.
+
+Zerolog's API is designed to provide both a great developer experience and stunning [performance](#benchmarks). Its unique chaining API allows zerolog to write JSON (or CBOR) log events by avoiding allocations and reflection.
+
+Uber's [zap](https://godoc.org/go.uber.org/zap) library pioneered this approach. Zerolog is taking this concept to the next level with a simpler to use API and even better performance.
+
+To keep the code base and the API simple, zerolog focuses on efficient structured logging only. Pretty logging on the console is made possible using the provided (but inefficient) [`zerolog.ConsoleWriter`](#pretty-logging).
+
+![Pretty Logging Image](pretty.png)
+
+## Who uses zerolog
+
+Find out [who uses zerolog](https://github.com/rs/zerolog/wiki/Who-uses-zerolog) and add your company / project to the list.
+
+## Features
+
+* [Blazing fast](#benchmarks)
+* [Low to zero allocation](#benchmarks)
+* [Leveled logging](#leveled-logging)
+* [Sampling](#log-sampling)
+* [Hooks](#hooks)
+* [Contextual fields](#contextual-logging)
+* [`context.Context` integration](#contextcontext-integration)
+* [Integration with `net/http`](#integration-with-nethttp)
+* [JSON and CBOR encoding formats](#binary-encoding)
+* [Pretty logging for development](#pretty-logging)
+* [Error Logging (with optional Stacktrace)](#error-logging)
+
+## Installation
+
+```bash
+go get -u github.com/rs/zerolog/log
+```
+
+## Getting Started
+
+### Simple Logging Example
+
+For simple logging, import the global logger package **github.com/rs/zerolog/log**
+
+```go
+package main
+
+import (
+ "github.com/rs/zerolog"
+ "github.com/rs/zerolog/log"
+)
+
+func main() {
+ // UNIX Time is faster and smaller than most timestamps
+ zerolog.TimeFieldFormat = zerolog.TimeFormatUnix
+
+ log.Print("hello world")
+}
+
+// Output: {"time":1516134303,"level":"debug","message":"hello world"}
+```
+> Note: By default log writes to `os.Stderr`
+> Note: The default log level for `log.Print` is *trace*
+
+### Contextual Logging
+
+**zerolog** allows data to be added to log messages in the form of key:value pairs. The data added to the message adds "context" about the log event that can be critical for debugging as well as myriad other purposes. An example of this is below:
+
+```go
+package main
+
+import (
+ "github.com/rs/zerolog"
+ "github.com/rs/zerolog/log"
+)
+
+func main() {
+ zerolog.TimeFieldFormat = zerolog.TimeFormatUnix
+
+ log.Debug().
+ Str("Scale", "833 cents").
+ Float64("Interval", 833.09).
+ Msg("Fibonacci is everywhere")
+
+ log.Debug().
+ Str("Name", "Tom").
+ Send()
+}
+
+// Output: {"level":"debug","Scale":"833 cents","Interval":833.09,"time":1562212768,"message":"Fibonacci is everywhere"}
+// Output: {"level":"debug","Name":"Tom","time":1562212768}
+```
+
+> You'll note in the above example that when adding contextual fields, the fields are strongly typed. You can find the full list of supported fields [here](#standard-types)
+
+### Leveled Logging
+
+#### Simple Leveled Logging Example
+
+```go
+package main
+
+import (
+ "github.com/rs/zerolog"
+ "github.com/rs/zerolog/log"
+)
+
+func main() {
+ zerolog.TimeFieldFormat = zerolog.TimeFormatUnix
+
+ log.Info().Msg("hello world")
+}
+
+// Output: {"time":1516134303,"level":"info","message":"hello world"}
+```
+
+> It is very important to note that when using the **zerolog** chaining API, as shown above (`log.Info().Msg("hello world"`), the chain must have either the `Msg` or `Msgf` method call. If you forget to add either of these, the log will not occur and there is no compile time error to alert you of this.
+
+**zerolog** allows for logging at the following levels (from highest to lowest):
+
+* panic (`zerolog.PanicLevel`, 5)
+* fatal (`zerolog.FatalLevel`, 4)
+* error (`zerolog.ErrorLevel`, 3)
+* warn (`zerolog.WarnLevel`, 2)
+* info (`zerolog.InfoLevel`, 1)
+* debug (`zerolog.DebugLevel`, 0)
+* trace (`zerolog.TraceLevel`, -1)
+
+You can set the Global logging level to any of these options using the `SetGlobalLevel` function in the zerolog package, passing in one of the given constants above, e.g. `zerolog.InfoLevel` would be the "info" level. Whichever level is chosen, all logs with a level greater than or equal to that level will be written. To turn off logging entirely, pass the `zerolog.Disabled` constant.
+
+#### Setting Global Log Level
+
+This example uses command-line flags to demonstrate various outputs depending on the chosen log level.
+
+```go
+package main
+
+import (
+ "flag"
+
+ "github.com/rs/zerolog"
+ "github.com/rs/zerolog/log"
+)
+
+func main() {
+ zerolog.TimeFieldFormat = zerolog.TimeFormatUnix
+ debug := flag.Bool("debug", false, "sets log level to debug")
+
+ flag.Parse()
+
+ // Default level for this example is info, unless debug flag is present
+ zerolog.SetGlobalLevel(zerolog.InfoLevel)
+ if *debug {
+ zerolog.SetGlobalLevel(zerolog.DebugLevel)
+ }
+
+ log.Debug().Msg("This message appears only when log level set to Debug")
+ log.Info().Msg("This message appears when log level set to Debug or Info")
+
+ if e := log.Debug(); e.Enabled() {
+ // Compute log output only if enabled.
+ value := "bar"
+ e.Str("foo", value).Msg("some debug message")
+ }
+}
+```
+
+Info Output (no flag)
+
+```bash
+$ ./logLevelExample
+{"time":1516387492,"level":"info","message":"This message appears when log level set to Debug or Info"}
+```
+
+Debug Output (debug flag set)
+
+```bash
+$ ./logLevelExample -debug
+{"time":1516387573,"level":"debug","message":"This message appears only when log level set to Debug"}
+{"time":1516387573,"level":"info","message":"This message appears when log level set to Debug or Info"}
+{"time":1516387573,"level":"debug","foo":"bar","message":"some debug message"}
+```
+
+#### Logging without Level or Message
+
+You may choose to log without a specific level by using the `Log` method. You may also write without a message by setting an empty string in the `msg string` parameter of the `Msg` method. Both are demonstrated in the example below.
+
+```go
+package main
+
+import (
+ "github.com/rs/zerolog"
+ "github.com/rs/zerolog/log"
+)
+
+func main() {
+ zerolog.TimeFieldFormat = zerolog.TimeFormatUnix
+
+ log.Log().
+ Str("foo", "bar").
+ Msg("")
+}
+
+// Output: {"time":1494567715,"foo":"bar"}
+```
+
+### Error Logging
+
+You can log errors using the `Err` method
+
+```go
+package main
+
+import (
+ "errors"
+
+ "github.com/rs/zerolog"
+ "github.com/rs/zerolog/log"
+)
+
+func main() {
+ zerolog.TimeFieldFormat = zerolog.TimeFormatUnix
+
+ err := errors.New("seems we have an error here")
+ log.Error().Err(err).Msg("")
+}
+
+// Output: {"level":"error","error":"seems we have an error here","time":1609085256}
+```
+
+> The default field name for errors is `error`, you can change this by setting `zerolog.ErrorFieldName` to meet your needs.
+
+#### Error Logging with Stacktrace
+
+Using `github.com/pkg/errors`, you can add a formatted stacktrace to your errors.
+
+```go
+package main
+
+import (
+ "github.com/pkg/errors"
+ "github.com/rs/zerolog/pkgerrors"
+
+ "github.com/rs/zerolog"
+ "github.com/rs/zerolog/log"
+)
+
+func main() {
+ zerolog.TimeFieldFormat = zerolog.TimeFormatUnix
+ zerolog.ErrorStackMarshaler = pkgerrors.MarshalStack
+
+ err := outer()
+ log.Error().Stack().Err(err).Msg("")
+}
+
+func inner() error {
+ return errors.New("seems we have an error here")
+}
+
+func middle() error {
+ err := inner()
+ if err != nil {
+ return err
+ }
+ return nil
+}
+
+func outer() error {
+ err := middle()
+ if err != nil {
+ return err
+ }
+ return nil
+}
+
+// Output: {"level":"error","stack":[{"func":"inner","line":"20","source":"errors.go"},{"func":"middle","line":"24","source":"errors.go"},{"func":"outer","line":"32","source":"errors.go"},{"func":"main","line":"15","source":"errors.go"},{"func":"main","line":"204","source":"proc.go"},{"func":"goexit","line":"1374","source":"asm_amd64.s"}],"error":"seems we have an error here","time":1609086683}
+```
+
+> zerolog.ErrorStackMarshaler must be set in order for the stack to output anything.
+
+#### Logging Fatal Messages
+
+```go
+package main
+
+import (
+ "errors"
+
+ "github.com/rs/zerolog"
+ "github.com/rs/zerolog/log"
+)
+
+func main() {
+ err := errors.New("A repo man spends his life getting into tense situations")
+ service := "myservice"
+
+ zerolog.TimeFieldFormat = zerolog.TimeFormatUnix
+
+ log.Fatal().
+ Err(err).
+ Str("service", service).
+ Msgf("Cannot start %s", service)
+}
+
+// Output: {"time":1516133263,"level":"fatal","error":"A repo man spends his life getting into tense situations","service":"myservice","message":"Cannot start myservice"}
+// exit status 1
+```
+
+> NOTE: Using `Msgf` generates one allocation even when the logger is disabled.
+
+
+### Create logger instance to manage different outputs
+
+```go
+logger := zerolog.New(os.Stderr).With().Timestamp().Logger()
+
+logger.Info().Str("foo", "bar").Msg("hello world")
+
+// Output: {"level":"info","time":1494567715,"message":"hello world","foo":"bar"}
+```
+
+### Sub-loggers let you chain loggers with additional context
+
+```go
+sublogger := log.With().
+ Str("component", "foo").
+ Logger()
+sublogger.Info().Msg("hello world")
+
+// Output: {"level":"info","time":1494567715,"message":"hello world","component":"foo"}
+```
+
+### Pretty logging
+
+To log a human-friendly, colorized output, use `zerolog.ConsoleWriter`:
+
+```go
+log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr})
+
+log.Info().Str("foo", "bar").Msg("Hello world")
+
+// Output: 3:04PM INF Hello World foo=bar
+```
+
+To customize the configuration and formatting:
+
+```go
+output := zerolog.ConsoleWriter{Out: os.Stdout, TimeFormat: time.RFC3339}
+output.FormatLevel = func(i interface{}) string {
+ return strings.ToUpper(fmt.Sprintf("| %-6s|", i))
+}
+output.FormatMessage = func(i interface{}) string {
+ return fmt.Sprintf("***%s****", i)
+}
+output.FormatFieldName = func(i interface{}) string {
+ return fmt.Sprintf("%s:", i)
+}
+output.FormatFieldValue = func(i interface{}) string {
+ return strings.ToUpper(fmt.Sprintf("%s", i))
+}
+
+log := zerolog.New(output).With().Timestamp().Logger()
+
+log.Info().Str("foo", "bar").Msg("Hello World")
+
+// Output: 2006-01-02T15:04:05Z07:00 | INFO | ***Hello World**** foo:BAR
+```
+
+### Sub dictionary
+
+```go
+log.Info().
+ Str("foo", "bar").
+ Dict("dict", zerolog.Dict().
+ Str("bar", "baz").
+ Int("n", 1),
+ ).Msg("hello world")
+
+// Output: {"level":"info","time":1494567715,"foo":"bar","dict":{"bar":"baz","n":1},"message":"hello world"}
+```
+
+### Customize automatic field names
+
+```go
+zerolog.TimestampFieldName = "t"
+zerolog.LevelFieldName = "l"
+zerolog.MessageFieldName = "m"
+
+log.Info().Msg("hello world")
+
+// Output: {"l":"info","t":1494567715,"m":"hello world"}
+```
+
+### Add contextual fields to the global logger
+
+```go
+log.Logger = log.With().Str("foo", "bar").Logger()
+```
+
+### Add file and line number to log
+
+Equivalent of `Llongfile`:
+
+```go
+log.Logger = log.With().Caller().Logger()
+log.Info().Msg("hello world")
+
+// Output: {"level": "info", "message": "hello world", "caller": "/go/src/your_project/some_file:21"}
+```
+
+Equivalent of `Lshortfile`:
+
+```go
+zerolog.CallerMarshalFunc = func(pc uintptr, file string, line int) string {
+ return filepath.Base(file) + ":" + strconv.Itoa(line)
+}
+log.Logger = log.With().Caller().Logger()
+log.Info().Msg("hello world")
+
+// Output: {"level": "info", "message": "hello world", "caller": "some_file:21"}
+```
+
+### Thread-safe, lock-free, non-blocking writer
+
+If your writer might be slow or not thread-safe and you need your log producers to never get slowed down by a slow writer, you can use a `diode.Writer` as follows:
+
+```go
+wr := diode.NewWriter(os.Stdout, 1000, 10*time.Millisecond, func(missed int) {
+ fmt.Printf("Logger Dropped %d messages", missed)
+ })
+log := zerolog.New(wr)
+log.Print("test")
+```
+
+You will need to install `code.cloudfoundry.org/go-diodes` to use this feature.
+
+### Log Sampling
+
+```go
+sampled := log.Sample(&zerolog.BasicSampler{N: 10})
+sampled.Info().Msg("will be logged every 10 messages")
+
+// Output: {"time":1494567715,"level":"info","message":"will be logged every 10 messages"}
+```
+
+More advanced sampling:
+
+```go
+// Will let 5 debug messages per period of 1 second.
+// Over 5 debug message, 1 every 100 debug messages are logged.
+// Other levels are not sampled.
+sampled := log.Sample(zerolog.LevelSampler{
+ DebugSampler: &zerolog.BurstSampler{
+ Burst: 5,
+ Period: 1*time.Second,
+ NextSampler: &zerolog.BasicSampler{N: 100},
+ },
+})
+sampled.Debug().Msg("hello world")
+
+// Output: {"time":1494567715,"level":"debug","message":"hello world"}
+```
+
+### Hooks
+
+```go
+type SeverityHook struct{}
+
+func (h SeverityHook) Run(e *zerolog.Event, level zerolog.Level, msg string) {
+ if level != zerolog.NoLevel {
+ e.Str("severity", level.String())
+ }
+}
+
+hooked := log.Hook(SeverityHook{})
+hooked.Warn().Msg("")
+
+// Output: {"level":"warn","severity":"warn"}
+```
+
+### Pass a sub-logger by context
+
+```go
+ctx := log.With().Str("component", "module").Logger().WithContext(ctx)
+
+log.Ctx(ctx).Info().Msg("hello world")
+
+// Output: {"component":"module","level":"info","message":"hello world"}
+```
+
+### Set as standard logger output
+
+```go
+log := zerolog.New(os.Stdout).With().
+ Str("foo", "bar").
+ Logger()
+
+stdlog.SetFlags(0)
+stdlog.SetOutput(log)
+
+stdlog.Print("hello world")
+
+// Output: {"foo":"bar","message":"hello world"}
+```
+
+### context.Context integration
+
+Go contexts are commonly passed throughout Go code, and this can help you pass
+your Logger into places it might otherwise be hard to inject. The `Logger`
+instance may be attached to Go context (`context.Context`) using
+`Logger.WithContext(ctx)` and extracted from it using `zerolog.Ctx(ctx)`.
+For example:
+
+```go
+func f() {
+ logger := zerolog.New(os.Stdout)
+ ctx := context.Background()
+
+ // Attach the Logger to the context.Context
+ ctx = logger.WithContext(ctx)
+ someFunc(ctx)
+}
+
+func someFunc(ctx context.Context) {
+ // Get Logger from the go Context. if it's nil, then
+ // `zerolog.DefaultContextLogger` is returned, if
+ // `DefaultContextLogger` is nil, then a disabled logger is returned.
+ logger := zerolog.Ctx(ctx)
+ logger.Info().Msg("Hello")
+}
+```
+
+A second form of `context.Context` integration allows you to pass the current
+context.Context into the logged event, and retrieve it from hooks. This can be
+useful to log trace and span IDs or other information stored in the go context,
+and facilitates the unification of logging and tracing in some systems:
+
+```go
+type TracingHook struct{}
+
+func (h TracingHook) Run(e *zerolog.Event, level zerolog.Level, msg string) {
+ ctx := e.GetCtx()
+ spanId := getSpanIdFromContext(ctx) // as per your tracing framework
+ e.Str("span-id", spanId)
+}
+
+func f() {
+ // Setup the logger
+ logger := zerolog.New(os.Stdout)
+ logger = logger.Hook(TracingHook{})
+
+ ctx := context.Background()
+ // Use the Ctx function to make the context available to the hook
+ logger.Info().Ctx(ctx).Msg("Hello")
+}
+```
+
+### Integration with `net/http`
+
+The `github.com/rs/zerolog/hlog` package provides some helpers to integrate zerolog with `http.Handler`.
+
+In this example we use [alice](https://github.com/justinas/alice) to install logger for better readability.
+
+```go
+log := zerolog.New(os.Stdout).With().
+ Timestamp().
+ Str("role", "my-service").
+ Str("host", host).
+ Logger()
+
+c := alice.New()
+
+// Install the logger handler with default output on the console
+c = c.Append(hlog.NewHandler(log))
+
+// Install some provided extra handler to set some request's context fields.
+// Thanks to that handler, all our logs will come with some prepopulated fields.
+c = c.Append(hlog.AccessHandler(func(r *http.Request, status, size int, duration time.Duration) {
+ hlog.FromRequest(r).Info().
+ Str("method", r.Method).
+ Stringer("url", r.URL).
+ Int("status", status).
+ Int("size", size).
+ Dur("duration", duration).
+ Msg("")
+}))
+c = c.Append(hlog.RemoteAddrHandler("ip"))
+c = c.Append(hlog.UserAgentHandler("user_agent"))
+c = c.Append(hlog.RefererHandler("referer"))
+c = c.Append(hlog.RequestIDHandler("req_id", "Request-Id"))
+
+// Here is your final handler
+h := c.Then(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ // Get the logger from the request's context. You can safely assume it
+ // will be always there: if the handler is removed, hlog.FromRequest
+ // will return a no-op logger.
+ hlog.FromRequest(r).Info().
+ Str("user", "current user").
+ Str("status", "ok").
+ Msg("Something happened")
+
+ // Output: {"level":"info","time":"2001-02-03T04:05:06Z","role":"my-service","host":"local-hostname","req_id":"b4g0l5t6tfid6dtrapu0","user":"current user","status":"ok","message":"Something happened"}
+}))
+http.Handle("/", h)
+
+if err := http.ListenAndServe(":8080", nil); err != nil {
+ log.Fatal().Err(err).Msg("Startup failed")
+}
+```
+
+## Multiple Log Output
+`zerolog.MultiLevelWriter` may be used to send the log message to multiple outputs.
+In this example, we send the log message to both `os.Stdout` and the in-built ConsoleWriter.
+```go
+func main() {
+ consoleWriter := zerolog.ConsoleWriter{Out: os.Stdout}
+
+ multi := zerolog.MultiLevelWriter(consoleWriter, os.Stdout)
+
+ logger := zerolog.New(multi).With().Timestamp().Logger()
+
+ logger.Info().Msg("Hello World!")
+}
+
+// Output (Line 1: Console; Line 2: Stdout)
+// 12:36PM INF Hello World!
+// {"level":"info","time":"2019-11-07T12:36:38+03:00","message":"Hello World!"}
+```
+
+## Global Settings
+
+Some settings can be changed and will be applied to all loggers:
+
+* `log.Logger`: You can set this value to customize the global logger (the one used by package level methods).
+* `zerolog.SetGlobalLevel`: Can raise the minimum level of all loggers. Call this with `zerolog.Disabled` to disable logging altogether (quiet mode).
+* `zerolog.DisableSampling`: If argument is `true`, all sampled loggers will stop sampling and issue 100% of their log events.
+* `zerolog.TimestampFieldName`: Can be set to customize `Timestamp` field name.
+* `zerolog.LevelFieldName`: Can be set to customize level field name.
+* `zerolog.MessageFieldName`: Can be set to customize message field name.
+* `zerolog.ErrorFieldName`: Can be set to customize `Err` field name.
+* `zerolog.TimeFieldFormat`: Can be set to customize `Time` field value formatting. If set with `zerolog.TimeFormatUnix`, `zerolog.TimeFormatUnixMs` or `zerolog.TimeFormatUnixMicro`, times are formatted as UNIX timestamp.
+* `zerolog.DurationFieldUnit`: Can be set to customize the unit for time.Duration type fields added by `Dur` (default: `time.Millisecond`).
+* `zerolog.DurationFieldInteger`: If set to `true`, `Dur` fields are formatted as integers instead of floats (default: `false`).
+* `zerolog.ErrorHandler`: Called whenever zerolog fails to write an event on its output. If not set, an error is printed on the stderr. This handler must be thread safe and non-blocking.
+* `zerolog.FloatingPointPrecision`: If set to a value other than -1, controls the number
+of digits when formatting float numbers in JSON. See
+[strconv.FormatFloat](https://pkg.go.dev/strconv#FormatFloat)
+for more details.
+
+## Field Types
+
+### Standard Types
+
+* `Str`
+* `Bool`
+* `Int`, `Int8`, `Int16`, `Int32`, `Int64`
+* `Uint`, `Uint8`, `Uint16`, `Uint32`, `Uint64`
+* `Float32`, `Float64`
+
+### Advanced Fields
+
+* `Err`: Takes an `error` and renders it as a string using the `zerolog.ErrorFieldName` field name.
+* `Func`: Run a `func` only if the level is enabled.
+* `Timestamp`: Inserts a timestamp field with `zerolog.TimestampFieldName` field name, formatted using `zerolog.TimeFieldFormat`.
+* `Time`: Adds a field with time formatted with `zerolog.TimeFieldFormat`.
+* `Dur`: Adds a field with `time.Duration`.
+* `Dict`: Adds a sub-key/value as a field of the event.
+* `RawJSON`: Adds a field with an already encoded JSON (`[]byte`)
+* `Hex`: Adds a field with value formatted as a hexadecimal string (`[]byte`)
+* `Interface`: Uses reflection to marshal the type.
+
+Most fields are also available in the slice format (`Strs` for `[]string`, `Errs` for `[]error` etc.)
+
+## Binary Encoding
+
+In addition to the default JSON encoding, `zerolog` can produce binary logs using [CBOR](https://cbor.io) encoding. The choice of encoding can be decided at compile time using the build tag `binary_log` as follows:
+
+```bash
+go build -tags binary_log .
+```
+
+To Decode binary encoded log files you can use any CBOR decoder. One has been tested to work
+with zerolog library is [CSD](https://github.com/toravir/csd/).
+
+## Related Projects
+
+* [grpc-zerolog](https://github.com/cheapRoc/grpc-zerolog): Implementation of `grpclog.LoggerV2` interface using `zerolog`
+* [overlog](https://github.com/Trendyol/overlog): Implementation of `Mapped Diagnostic Context` interface using `zerolog`
+* [zerologr](https://github.com/go-logr/zerologr): Implementation of `logr.LogSink` interface using `zerolog`
+
+## Benchmarks
+
+See [logbench](http://bench.zerolog.io/) for more comprehensive and up-to-date benchmarks.
+
+All operations are allocation free (those numbers *include* JSON encoding):
+
+```text
+BenchmarkLogEmpty-8 100000000 19.1 ns/op 0 B/op 0 allocs/op
+BenchmarkDisabled-8 500000000 4.07 ns/op 0 B/op 0 allocs/op
+BenchmarkInfo-8 30000000 42.5 ns/op 0 B/op 0 allocs/op
+BenchmarkContextFields-8 30000000 44.9 ns/op 0 B/op 0 allocs/op
+BenchmarkLogFields-8 10000000 184 ns/op 0 B/op 0 allocs/op
+```
+
+There are a few Go logging benchmarks and comparisons that include zerolog.
+
+* [imkira/go-loggers-bench](https://github.com/imkira/go-loggers-bench)
+* [uber-common/zap](https://github.com/uber-go/zap#performance)
+
+Using Uber's zap comparison benchmark:
+
+Log a message and 10 fields:
+
+| Library | Time | Bytes Allocated | Objects Allocated |
+| :--- | :---: | :---: | :---: |
+| zerolog | 767 ns/op | 552 B/op | 6 allocs/op |
+| :zap: zap | 848 ns/op | 704 B/op | 2 allocs/op |
+| :zap: zap (sugared) | 1363 ns/op | 1610 B/op | 20 allocs/op |
+| go-kit | 3614 ns/op | 2895 B/op | 66 allocs/op |
+| lion | 5392 ns/op | 5807 B/op | 63 allocs/op |
+| logrus | 5661 ns/op | 6092 B/op | 78 allocs/op |
+| apex/log | 15332 ns/op | 3832 B/op | 65 allocs/op |
+| log15 | 20657 ns/op | 5632 B/op | 93 allocs/op |
+
+Log a message with a logger that already has 10 fields of context:
+
+| Library | Time | Bytes Allocated | Objects Allocated |
+| :--- | :---: | :---: | :---: |
+| zerolog | 52 ns/op | 0 B/op | 0 allocs/op |
+| :zap: zap | 283 ns/op | 0 B/op | 0 allocs/op |
+| :zap: zap (sugared) | 337 ns/op | 80 B/op | 2 allocs/op |
+| lion | 2702 ns/op | 4074 B/op | 38 allocs/op |
+| go-kit | 3378 ns/op | 3046 B/op | 52 allocs/op |
+| logrus | 4309 ns/op | 4564 B/op | 63 allocs/op |
+| apex/log | 13456 ns/op | 2898 B/op | 51 allocs/op |
+| log15 | 14179 ns/op | 2642 B/op | 44 allocs/op |
+
+Log a static string, without any context or `printf`-style templating:
+
+| Library | Time | Bytes Allocated | Objects Allocated |
+| :--- | :---: | :---: | :---: |
+| zerolog | 50 ns/op | 0 B/op | 0 allocs/op |
+| :zap: zap | 236 ns/op | 0 B/op | 0 allocs/op |
+| standard library | 453 ns/op | 80 B/op | 2 allocs/op |
+| :zap: zap (sugared) | 337 ns/op | 80 B/op | 2 allocs/op |
+| go-kit | 508 ns/op | 656 B/op | 13 allocs/op |
+| lion | 771 ns/op | 1224 B/op | 10 allocs/op |
+| logrus | 1244 ns/op | 1505 B/op | 27 allocs/op |
+| apex/log | 2751 ns/op | 584 B/op | 11 allocs/op |
+| log15 | 5181 ns/op | 1592 B/op | 26 allocs/op |
+
+## Caveats
+
+### Field duplication
+
+Note that zerolog does no de-duplication of fields. Using the same key multiple times creates multiple keys in final JSON:
+
+```go
+logger := zerolog.New(os.Stderr).With().Timestamp().Logger()
+logger.Info().
+ Timestamp().
+ Msg("dup")
+// Output: {"level":"info","time":1494567715,"time":1494567715,"message":"dup"}
+```
+
+In this case, many consumers will take the last value, but this is not guaranteed; check yours if in doubt.
+
+### Concurrency safety
+
+Be careful when calling UpdateContext. It is not concurrency safe. Use the With method to create a child logger:
+
+```go
+func handler(w http.ResponseWriter, r *http.Request) {
+ // Create a child logger for concurrency safety
+ logger := log.Logger.With().Logger()
+
+ // Add context fields, for example User-Agent from HTTP headers
+ logger.UpdateContext(func(c zerolog.Context) zerolog.Context {
+ ...
+ })
+}
+```
diff --git a/vendor/github.com/rs/zerolog/_config.yml b/vendor/github.com/rs/zerolog/_config.yml
new file mode 100644
index 0000000..a1e896d
--- /dev/null
+++ b/vendor/github.com/rs/zerolog/_config.yml
@@ -0,0 +1 @@
+remote_theme: rs/gh-readme
diff --git a/vendor/github.com/rs/zerolog/array.go b/vendor/github.com/rs/zerolog/array.go
new file mode 100644
index 0000000..ba35b28
--- /dev/null
+++ b/vendor/github.com/rs/zerolog/array.go
@@ -0,0 +1,240 @@
+package zerolog
+
+import (
+ "net"
+ "sync"
+ "time"
+)
+
+var arrayPool = &sync.Pool{
+ New: func() interface{} {
+ return &Array{
+ buf: make([]byte, 0, 500),
+ }
+ },
+}
+
+// Array is used to prepopulate an array of items
+// which can be re-used to add to log messages.
+type Array struct {
+ buf []byte
+}
+
+func putArray(a *Array) {
+ // Proper usage of a sync.Pool requires each entry to have approximately
+ // the same memory cost. To obtain this property when the stored type
+ // contains a variably-sized buffer, we add a hard limit on the maximum buffer
+ // to place back in the pool.
+ //
+ // See https://golang.org/issue/23199
+ const maxSize = 1 << 16 // 64KiB
+ if cap(a.buf) > maxSize {
+ return
+ }
+ arrayPool.Put(a)
+}
+
+// Arr creates an array to be added to an Event or Context.
+func Arr() *Array {
+ a := arrayPool.Get().(*Array)
+ a.buf = a.buf[:0]
+ return a
+}
+
+// MarshalZerologArray method here is no-op - since data is
+// already in the needed format.
+func (*Array) MarshalZerologArray(*Array) {
+}
+
+func (a *Array) write(dst []byte) []byte {
+ dst = enc.AppendArrayStart(dst)
+ if len(a.buf) > 0 {
+ dst = append(dst, a.buf...)
+ }
+ dst = enc.AppendArrayEnd(dst)
+ putArray(a)
+ return dst
+}
+
+// Object marshals an object that implement the LogObjectMarshaler
+// interface and appends it to the array.
+func (a *Array) Object(obj LogObjectMarshaler) *Array {
+ e := Dict()
+ obj.MarshalZerologObject(e)
+ e.buf = enc.AppendEndMarker(e.buf)
+ a.buf = append(enc.AppendArrayDelim(a.buf), e.buf...)
+ putEvent(e)
+ return a
+}
+
+// Str appends the val as a string to the array.
+func (a *Array) Str(val string) *Array {
+ a.buf = enc.AppendString(enc.AppendArrayDelim(a.buf), val)
+ return a
+}
+
+// Bytes appends the val as a string to the array.
+func (a *Array) Bytes(val []byte) *Array {
+ a.buf = enc.AppendBytes(enc.AppendArrayDelim(a.buf), val)
+ return a
+}
+
+// Hex appends the val as a hex string to the array.
+func (a *Array) Hex(val []byte) *Array {
+ a.buf = enc.AppendHex(enc.AppendArrayDelim(a.buf), val)
+ return a
+}
+
+// RawJSON adds already encoded JSON to the array.
+func (a *Array) RawJSON(val []byte) *Array {
+ a.buf = appendJSON(enc.AppendArrayDelim(a.buf), val)
+ return a
+}
+
+// Err serializes and appends the err to the array.
+func (a *Array) Err(err error) *Array {
+ switch m := ErrorMarshalFunc(err).(type) {
+ case LogObjectMarshaler:
+ e := newEvent(nil, 0)
+ e.buf = e.buf[:0]
+ e.appendObject(m)
+ a.buf = append(enc.AppendArrayDelim(a.buf), e.buf...)
+ putEvent(e)
+ case error:
+ if m == nil || isNilValue(m) {
+ a.buf = enc.AppendNil(enc.AppendArrayDelim(a.buf))
+ } else {
+ a.buf = enc.AppendString(enc.AppendArrayDelim(a.buf), m.Error())
+ }
+ case string:
+ a.buf = enc.AppendString(enc.AppendArrayDelim(a.buf), m)
+ default:
+ a.buf = enc.AppendInterface(enc.AppendArrayDelim(a.buf), m)
+ }
+
+ return a
+}
+
+// Bool appends the val as a bool to the array.
+func (a *Array) Bool(b bool) *Array {
+ a.buf = enc.AppendBool(enc.AppendArrayDelim(a.buf), b)
+ return a
+}
+
+// Int appends i as a int to the array.
+func (a *Array) Int(i int) *Array {
+ a.buf = enc.AppendInt(enc.AppendArrayDelim(a.buf), i)
+ return a
+}
+
+// Int8 appends i as a int8 to the array.
+func (a *Array) Int8(i int8) *Array {
+ a.buf = enc.AppendInt8(enc.AppendArrayDelim(a.buf), i)
+ return a
+}
+
+// Int16 appends i as a int16 to the array.
+func (a *Array) Int16(i int16) *Array {
+ a.buf = enc.AppendInt16(enc.AppendArrayDelim(a.buf), i)
+ return a
+}
+
+// Int32 appends i as a int32 to the array.
+func (a *Array) Int32(i int32) *Array {
+ a.buf = enc.AppendInt32(enc.AppendArrayDelim(a.buf), i)
+ return a
+}
+
+// Int64 appends i as a int64 to the array.
+func (a *Array) Int64(i int64) *Array {
+ a.buf = enc.AppendInt64(enc.AppendArrayDelim(a.buf), i)
+ return a
+}
+
+// Uint appends i as a uint to the array.
+func (a *Array) Uint(i uint) *Array {
+ a.buf = enc.AppendUint(enc.AppendArrayDelim(a.buf), i)
+ return a
+}
+
+// Uint8 appends i as a uint8 to the array.
+func (a *Array) Uint8(i uint8) *Array {
+ a.buf = enc.AppendUint8(enc.AppendArrayDelim(a.buf), i)
+ return a
+}
+
+// Uint16 appends i as a uint16 to the array.
+func (a *Array) Uint16(i uint16) *Array {
+ a.buf = enc.AppendUint16(enc.AppendArrayDelim(a.buf), i)
+ return a
+}
+
+// Uint32 appends i as a uint32 to the array.
+func (a *Array) Uint32(i uint32) *Array {
+ a.buf = enc.AppendUint32(enc.AppendArrayDelim(a.buf), i)
+ return a
+}
+
+// Uint64 appends i as a uint64 to the array.
+func (a *Array) Uint64(i uint64) *Array {
+ a.buf = enc.AppendUint64(enc.AppendArrayDelim(a.buf), i)
+ return a
+}
+
+// Float32 appends f as a float32 to the array.
+func (a *Array) Float32(f float32) *Array {
+ a.buf = enc.AppendFloat32(enc.AppendArrayDelim(a.buf), f, FloatingPointPrecision)
+ return a
+}
+
+// Float64 appends f as a float64 to the array.
+func (a *Array) Float64(f float64) *Array {
+ a.buf = enc.AppendFloat64(enc.AppendArrayDelim(a.buf), f, FloatingPointPrecision)
+ return a
+}
+
+// Time appends t formatted as string using zerolog.TimeFieldFormat.
+func (a *Array) Time(t time.Time) *Array {
+ a.buf = enc.AppendTime(enc.AppendArrayDelim(a.buf), t, TimeFieldFormat)
+ return a
+}
+
+// Dur appends d to the array.
+func (a *Array) Dur(d time.Duration) *Array {
+ a.buf = enc.AppendDuration(enc.AppendArrayDelim(a.buf), d, DurationFieldUnit, DurationFieldInteger, FloatingPointPrecision)
+ return a
+}
+
+// Interface appends i marshaled using reflection.
+func (a *Array) Interface(i interface{}) *Array {
+ if obj, ok := i.(LogObjectMarshaler); ok {
+ return a.Object(obj)
+ }
+ a.buf = enc.AppendInterface(enc.AppendArrayDelim(a.buf), i)
+ return a
+}
+
+// IPAddr adds IPv4 or IPv6 address to the array
+func (a *Array) IPAddr(ip net.IP) *Array {
+ a.buf = enc.AppendIPAddr(enc.AppendArrayDelim(a.buf), ip)
+ return a
+}
+
+// IPPrefix adds IPv4 or IPv6 Prefix (IP + mask) to the array
+func (a *Array) IPPrefix(pfx net.IPNet) *Array {
+ a.buf = enc.AppendIPPrefix(enc.AppendArrayDelim(a.buf), pfx)
+ return a
+}
+
+// MACAddr adds a MAC (Ethernet) address to the array
+func (a *Array) MACAddr(ha net.HardwareAddr) *Array {
+ a.buf = enc.AppendMACAddr(enc.AppendArrayDelim(a.buf), ha)
+ return a
+}
+
+// Dict adds the dict Event to the array
+func (a *Array) Dict(dict *Event) *Array {
+ dict.buf = enc.AppendEndMarker(dict.buf)
+ a.buf = append(enc.AppendArrayDelim(a.buf), dict.buf...)
+ return a
+}
diff --git a/vendor/github.com/rs/zerolog/console.go b/vendor/github.com/rs/zerolog/console.go
new file mode 100644
index 0000000..7e65e86
--- /dev/null
+++ b/vendor/github.com/rs/zerolog/console.go
@@ -0,0 +1,520 @@
+package zerolog
+
+import (
+ "bytes"
+ "encoding/json"
+ "fmt"
+ "io"
+ "os"
+ "path/filepath"
+ "sort"
+ "strconv"
+ "strings"
+ "sync"
+ "time"
+
+ "github.com/mattn/go-colorable"
+)
+
+const (
+ colorBlack = iota + 30
+ colorRed
+ colorGreen
+ colorYellow
+ colorBlue
+ colorMagenta
+ colorCyan
+ colorWhite
+
+ colorBold = 1
+ colorDarkGray = 90
+
+ unknownLevel = "???"
+)
+
+var (
+ consoleBufPool = sync.Pool{
+ New: func() interface{} {
+ return bytes.NewBuffer(make([]byte, 0, 100))
+ },
+ }
+)
+
+const (
+ consoleDefaultTimeFormat = time.Kitchen
+)
+
+// Formatter transforms the input into a formatted string.
+type Formatter func(interface{}) string
+
+// ConsoleWriter parses the JSON input and writes it in an
+// (optionally) colorized, human-friendly format to Out.
+type ConsoleWriter struct {
+ // Out is the output destination.
+ Out io.Writer
+
+ // NoColor disables the colorized output.
+ NoColor bool
+
+ // TimeFormat specifies the format for timestamp in output.
+ TimeFormat string
+
+ // TimeLocation tells ConsoleWriter’s default FormatTimestamp
+ // how to localize the time.
+ TimeLocation *time.Location
+
+ // PartsOrder defines the order of parts in output.
+ PartsOrder []string
+
+ // PartsExclude defines parts to not display in output.
+ PartsExclude []string
+
+ // FieldsOrder defines the order of contextual fields in output.
+ FieldsOrder []string
+
+ fieldIsOrdered map[string]int
+
+ // FieldsExclude defines contextual fields to not display in output.
+ FieldsExclude []string
+
+ FormatTimestamp Formatter
+ FormatLevel Formatter
+ FormatCaller Formatter
+ FormatMessage Formatter
+ FormatFieldName Formatter
+ FormatFieldValue Formatter
+ FormatErrFieldName Formatter
+ FormatErrFieldValue Formatter
+
+ FormatExtra func(map[string]interface{}, *bytes.Buffer) error
+
+ FormatPrepare func(map[string]interface{}) error
+}
+
+// NewConsoleWriter creates and initializes a new ConsoleWriter.
+func NewConsoleWriter(options ...func(w *ConsoleWriter)) ConsoleWriter {
+ w := ConsoleWriter{
+ Out: os.Stdout,
+ TimeFormat: consoleDefaultTimeFormat,
+ PartsOrder: consoleDefaultPartsOrder(),
+ }
+
+ for _, opt := range options {
+ opt(&w)
+ }
+
+ // Fix color on Windows
+ if w.Out == os.Stdout || w.Out == os.Stderr {
+ w.Out = colorable.NewColorable(w.Out.(*os.File))
+ }
+
+ return w
+}
+
+// Write transforms the JSON input with formatters and appends to w.Out.
+func (w ConsoleWriter) Write(p []byte) (n int, err error) {
+ // Fix color on Windows
+ if w.Out == os.Stdout || w.Out == os.Stderr {
+ w.Out = colorable.NewColorable(w.Out.(*os.File))
+ }
+
+ if w.PartsOrder == nil {
+ w.PartsOrder = consoleDefaultPartsOrder()
+ }
+
+ var buf = consoleBufPool.Get().(*bytes.Buffer)
+ defer func() {
+ buf.Reset()
+ consoleBufPool.Put(buf)
+ }()
+
+ var evt map[string]interface{}
+ p = decodeIfBinaryToBytes(p)
+ d := json.NewDecoder(bytes.NewReader(p))
+ d.UseNumber()
+ err = d.Decode(&evt)
+ if err != nil {
+ return n, fmt.Errorf("cannot decode event: %s", err)
+ }
+
+ if w.FormatPrepare != nil {
+ err = w.FormatPrepare(evt)
+ if err != nil {
+ return n, err
+ }
+ }
+
+ for _, p := range w.PartsOrder {
+ w.writePart(buf, evt, p)
+ }
+
+ w.writeFields(evt, buf)
+
+ if w.FormatExtra != nil {
+ err = w.FormatExtra(evt, buf)
+ if err != nil {
+ return n, err
+ }
+ }
+
+ err = buf.WriteByte('\n')
+ if err != nil {
+ return n, err
+ }
+
+ _, err = buf.WriteTo(w.Out)
+ return len(p), err
+}
+
+// Call the underlying writer's Close method if it is an io.Closer. Otherwise
+// does nothing.
+func (w ConsoleWriter) Close() error {
+ if closer, ok := w.Out.(io.Closer); ok {
+ return closer.Close()
+ }
+ return nil
+}
+
+// writeFields appends formatted key-value pairs to buf.
+func (w ConsoleWriter) writeFields(evt map[string]interface{}, buf *bytes.Buffer) {
+ var fields = make([]string, 0, len(evt))
+ for field := range evt {
+ var isExcluded bool
+ for _, excluded := range w.FieldsExclude {
+ if field == excluded {
+ isExcluded = true
+ break
+ }
+ }
+ if isExcluded {
+ continue
+ }
+
+ switch field {
+ case LevelFieldName, TimestampFieldName, MessageFieldName, CallerFieldName:
+ continue
+ }
+ fields = append(fields, field)
+ }
+
+ if len(w.FieldsOrder) > 0 {
+ w.orderFields(fields)
+ } else {
+ sort.Strings(fields)
+ }
+
+ // Write space only if something has already been written to the buffer, and if there are fields.
+ if buf.Len() > 0 && len(fields) > 0 {
+ buf.WriteByte(' ')
+ }
+
+ // Move the "error" field to the front
+ ei := sort.Search(len(fields), func(i int) bool { return fields[i] >= ErrorFieldName })
+ if ei < len(fields) && fields[ei] == ErrorFieldName {
+ fields[ei] = ""
+ fields = append([]string{ErrorFieldName}, fields...)
+ var xfields = make([]string, 0, len(fields))
+ for _, field := range fields {
+ if field == "" { // Skip empty fields
+ continue
+ }
+ xfields = append(xfields, field)
+ }
+ fields = xfields
+ }
+
+ for i, field := range fields {
+ var fn Formatter
+ var fv Formatter
+
+ if field == ErrorFieldName {
+ if w.FormatErrFieldName == nil {
+ fn = consoleDefaultFormatErrFieldName(w.NoColor)
+ } else {
+ fn = w.FormatErrFieldName
+ }
+
+ if w.FormatErrFieldValue == nil {
+ fv = consoleDefaultFormatErrFieldValue(w.NoColor)
+ } else {
+ fv = w.FormatErrFieldValue
+ }
+ } else {
+ if w.FormatFieldName == nil {
+ fn = consoleDefaultFormatFieldName(w.NoColor)
+ } else {
+ fn = w.FormatFieldName
+ }
+
+ if w.FormatFieldValue == nil {
+ fv = consoleDefaultFormatFieldValue
+ } else {
+ fv = w.FormatFieldValue
+ }
+ }
+
+ buf.WriteString(fn(field))
+
+ switch fValue := evt[field].(type) {
+ case string:
+ if needsQuote(fValue) {
+ buf.WriteString(fv(strconv.Quote(fValue)))
+ } else {
+ buf.WriteString(fv(fValue))
+ }
+ case json.Number:
+ buf.WriteString(fv(fValue))
+ default:
+ b, err := InterfaceMarshalFunc(fValue)
+ if err != nil {
+ fmt.Fprintf(buf, colorize("[error: %v]", colorRed, w.NoColor), err)
+ } else {
+ fmt.Fprint(buf, fv(b))
+ }
+ }
+
+ if i < len(fields)-1 { // Skip space for last field
+ buf.WriteByte(' ')
+ }
+ }
+}
+
+// writePart appends a formatted part to buf.
+func (w ConsoleWriter) writePart(buf *bytes.Buffer, evt map[string]interface{}, p string) {
+ var f Formatter
+
+ if w.PartsExclude != nil && len(w.PartsExclude) > 0 {
+ for _, exclude := range w.PartsExclude {
+ if exclude == p {
+ return
+ }
+ }
+ }
+
+ switch p {
+ case LevelFieldName:
+ if w.FormatLevel == nil {
+ f = consoleDefaultFormatLevel(w.NoColor)
+ } else {
+ f = w.FormatLevel
+ }
+ case TimestampFieldName:
+ if w.FormatTimestamp == nil {
+ f = consoleDefaultFormatTimestamp(w.TimeFormat, w.TimeLocation, w.NoColor)
+ } else {
+ f = w.FormatTimestamp
+ }
+ case MessageFieldName:
+ if w.FormatMessage == nil {
+ f = consoleDefaultFormatMessage(w.NoColor, evt[LevelFieldName])
+ } else {
+ f = w.FormatMessage
+ }
+ case CallerFieldName:
+ if w.FormatCaller == nil {
+ f = consoleDefaultFormatCaller(w.NoColor)
+ } else {
+ f = w.FormatCaller
+ }
+ default:
+ if w.FormatFieldValue == nil {
+ f = consoleDefaultFormatFieldValue
+ } else {
+ f = w.FormatFieldValue
+ }
+ }
+
+ var s = f(evt[p])
+
+ if len(s) > 0 {
+ if buf.Len() > 0 {
+ buf.WriteByte(' ') // Write space only if not the first part
+ }
+ buf.WriteString(s)
+ }
+}
+
+// orderFields takes an array of field names and an array representing field order
+// and returns an array with any ordered fields at the beginning, in order,
+// and the remaining fields after in their original order.
+func (w ConsoleWriter) orderFields(fields []string) {
+ if w.fieldIsOrdered == nil {
+ w.fieldIsOrdered = make(map[string]int)
+ for i, fieldName := range w.FieldsOrder {
+ w.fieldIsOrdered[fieldName] = i
+ }
+ }
+ sort.Slice(fields, func(i, j int) bool {
+ ii, iOrdered := w.fieldIsOrdered[fields[i]]
+ jj, jOrdered := w.fieldIsOrdered[fields[j]]
+ if iOrdered && jOrdered {
+ return ii < jj
+ }
+ if iOrdered {
+ return true
+ }
+ if jOrdered {
+ return false
+ }
+ return fields[i] < fields[j]
+ })
+}
+
+// needsQuote returns true when the string s should be quoted in output.
+func needsQuote(s string) bool {
+ for i := range s {
+ if s[i] < 0x20 || s[i] > 0x7e || s[i] == ' ' || s[i] == '\\' || s[i] == '"' {
+ return true
+ }
+ }
+ return false
+}
+
+// colorize returns the string s wrapped in ANSI code c, unless disabled is true or c is 0.
+func colorize(s interface{}, c int, disabled bool) string {
+ e := os.Getenv("NO_COLOR")
+ if e != "" || c == 0 {
+ disabled = true
+ }
+
+ if disabled {
+ return fmt.Sprintf("%s", s)
+ }
+ return fmt.Sprintf("\x1b[%dm%v\x1b[0m", c, s)
+}
+
+// ----- DEFAULT FORMATTERS ---------------------------------------------------
+
+func consoleDefaultPartsOrder() []string {
+ return []string{
+ TimestampFieldName,
+ LevelFieldName,
+ CallerFieldName,
+ MessageFieldName,
+ }
+}
+
+func consoleDefaultFormatTimestamp(timeFormat string, location *time.Location, noColor bool) Formatter {
+ if timeFormat == "" {
+ timeFormat = consoleDefaultTimeFormat
+ }
+ if location == nil {
+ location = time.Local
+ }
+
+ return func(i interface{}) string {
+ t := ""
+ switch tt := i.(type) {
+ case string:
+ ts, err := time.ParseInLocation(TimeFieldFormat, tt, location)
+ if err != nil {
+ t = tt
+ } else {
+ t = ts.In(location).Format(timeFormat)
+ }
+ case json.Number:
+ i, err := tt.Int64()
+ if err != nil {
+ t = tt.String()
+ } else {
+ var sec, nsec int64
+
+ switch TimeFieldFormat {
+ case TimeFormatUnixNano:
+ sec, nsec = 0, i
+ case TimeFormatUnixMicro:
+ sec, nsec = 0, int64(time.Duration(i)*time.Microsecond)
+ case TimeFormatUnixMs:
+ sec, nsec = 0, int64(time.Duration(i)*time.Millisecond)
+ default:
+ sec, nsec = i, 0
+ }
+
+ ts := time.Unix(sec, nsec)
+ t = ts.In(location).Format(timeFormat)
+ }
+ }
+ return colorize(t, colorDarkGray, noColor)
+ }
+}
+
+func stripLevel(ll string) string {
+ if len(ll) == 0 {
+ return unknownLevel
+ }
+ if len(ll) > 3 {
+ ll = ll[:3]
+ }
+ return strings.ToUpper(ll)
+}
+
+func consoleDefaultFormatLevel(noColor bool) Formatter {
+ return func(i interface{}) string {
+ if ll, ok := i.(string); ok {
+ level, _ := ParseLevel(ll)
+ fl, ok := FormattedLevels[level]
+ if ok {
+ return colorize(fl, LevelColors[level], noColor)
+ }
+ return stripLevel(ll)
+ }
+ if i == nil {
+ return unknownLevel
+ }
+ return stripLevel(fmt.Sprintf("%s", i))
+ }
+}
+
+func consoleDefaultFormatCaller(noColor bool) Formatter {
+ return func(i interface{}) string {
+ var c string
+ if cc, ok := i.(string); ok {
+ c = cc
+ }
+ if len(c) > 0 {
+ if cwd, err := os.Getwd(); err == nil {
+ if rel, err := filepath.Rel(cwd, c); err == nil {
+ c = rel
+ }
+ }
+ c = colorize(c, colorBold, noColor) + colorize(" >", colorCyan, noColor)
+ }
+ return c
+ }
+}
+
+func consoleDefaultFormatMessage(noColor bool, level interface{}) Formatter {
+ return func(i interface{}) string {
+ if i == nil || i == "" {
+ return ""
+ }
+ switch level {
+ case LevelInfoValue, LevelWarnValue, LevelErrorValue, LevelFatalValue, LevelPanicValue:
+ return colorize(fmt.Sprintf("%s", i), colorBold, noColor)
+ default:
+ return fmt.Sprintf("%s", i)
+ }
+ }
+}
+
+func consoleDefaultFormatFieldName(noColor bool) Formatter {
+ return func(i interface{}) string {
+ return colorize(fmt.Sprintf("%s=", i), colorCyan, noColor)
+ }
+}
+
+func consoleDefaultFormatFieldValue(i interface{}) string {
+ return fmt.Sprintf("%s", i)
+}
+
+func consoleDefaultFormatErrFieldName(noColor bool) Formatter {
+ return func(i interface{}) string {
+ return colorize(fmt.Sprintf("%s=", i), colorCyan, noColor)
+ }
+}
+
+func consoleDefaultFormatErrFieldValue(noColor bool) Formatter {
+ return func(i interface{}) string {
+ return colorize(colorize(fmt.Sprintf("%s", i), colorBold, noColor), colorRed, noColor)
+ }
+}
diff --git a/vendor/github.com/rs/zerolog/context.go b/vendor/github.com/rs/zerolog/context.go
new file mode 100644
index 0000000..ff9a3ae
--- /dev/null
+++ b/vendor/github.com/rs/zerolog/context.go
@@ -0,0 +1,480 @@
+package zerolog
+
+import (
+ "context"
+ "fmt"
+ "io"
+ "math"
+ "net"
+ "time"
+)
+
+// Context configures a new sub-logger with contextual fields.
+type Context struct {
+ l Logger
+}
+
+// Logger returns the logger with the context previously set.
+func (c Context) Logger() Logger {
+ return c.l
+}
+
+// Fields is a helper function to use a map or slice to set fields using type assertion.
+// Only map[string]interface{} and []interface{} are accepted. []interface{} must
+// alternate string keys and arbitrary values, and extraneous ones are ignored.
+func (c Context) Fields(fields interface{}) Context {
+ c.l.context = appendFields(c.l.context, fields, c.l.stack)
+ return c
+}
+
+// Dict adds the field key with the dict to the logger context.
+func (c Context) Dict(key string, dict *Event) Context {
+ dict.buf = enc.AppendEndMarker(dict.buf)
+ c.l.context = append(enc.AppendKey(c.l.context, key), dict.buf...)
+ putEvent(dict)
+ return c
+}
+
+// Array adds the field key with an array to the event context.
+// Use zerolog.Arr() to create the array or pass a type that
+// implement the LogArrayMarshaler interface.
+func (c Context) Array(key string, arr LogArrayMarshaler) Context {
+ c.l.context = enc.AppendKey(c.l.context, key)
+ if arr, ok := arr.(*Array); ok {
+ c.l.context = arr.write(c.l.context)
+ return c
+ }
+ var a *Array
+ if aa, ok := arr.(*Array); ok {
+ a = aa
+ } else {
+ a = Arr()
+ arr.MarshalZerologArray(a)
+ }
+ c.l.context = a.write(c.l.context)
+ return c
+}
+
+// Object marshals an object that implement the LogObjectMarshaler interface.
+func (c Context) Object(key string, obj LogObjectMarshaler) Context {
+ e := newEvent(LevelWriterAdapter{io.Discard}, 0)
+ e.Object(key, obj)
+ c.l.context = enc.AppendObjectData(c.l.context, e.buf)
+ putEvent(e)
+ return c
+}
+
+// EmbedObject marshals and Embeds an object that implement the LogObjectMarshaler interface.
+func (c Context) EmbedObject(obj LogObjectMarshaler) Context {
+ e := newEvent(LevelWriterAdapter{io.Discard}, 0)
+ e.EmbedObject(obj)
+ c.l.context = enc.AppendObjectData(c.l.context, e.buf)
+ putEvent(e)
+ return c
+}
+
+// Str adds the field key with val as a string to the logger context.
+func (c Context) Str(key, val string) Context {
+ c.l.context = enc.AppendString(enc.AppendKey(c.l.context, key), val)
+ return c
+}
+
+// Strs adds the field key with val as a string to the logger context.
+func (c Context) Strs(key string, vals []string) Context {
+ c.l.context = enc.AppendStrings(enc.AppendKey(c.l.context, key), vals)
+ return c
+}
+
+// Stringer adds the field key with val.String() (or null if val is nil) to the logger context.
+func (c Context) Stringer(key string, val fmt.Stringer) Context {
+ if val != nil {
+ c.l.context = enc.AppendString(enc.AppendKey(c.l.context, key), val.String())
+ return c
+ }
+
+ c.l.context = enc.AppendInterface(enc.AppendKey(c.l.context, key), nil)
+ return c
+}
+
+// Bytes adds the field key with val as a []byte to the logger context.
+func (c Context) Bytes(key string, val []byte) Context {
+ c.l.context = enc.AppendBytes(enc.AppendKey(c.l.context, key), val)
+ return c
+}
+
+// Hex adds the field key with val as a hex string to the logger context.
+func (c Context) Hex(key string, val []byte) Context {
+ c.l.context = enc.AppendHex(enc.AppendKey(c.l.context, key), val)
+ return c
+}
+
+// RawJSON adds already encoded JSON to context.
+//
+// No sanity check is performed on b; it must not contain carriage returns and
+// be valid JSON.
+func (c Context) RawJSON(key string, b []byte) Context {
+ c.l.context = appendJSON(enc.AppendKey(c.l.context, key), b)
+ return c
+}
+
+// AnErr adds the field key with serialized err to the logger context.
+func (c Context) AnErr(key string, err error) Context {
+ switch m := ErrorMarshalFunc(err).(type) {
+ case nil:
+ return c
+ case LogObjectMarshaler:
+ return c.Object(key, m)
+ case error:
+ if m == nil || isNilValue(m) {
+ return c
+ } else {
+ return c.Str(key, m.Error())
+ }
+ case string:
+ return c.Str(key, m)
+ default:
+ return c.Interface(key, m)
+ }
+}
+
+// Errs adds the field key with errs as an array of serialized errors to the
+// logger context.
+func (c Context) Errs(key string, errs []error) Context {
+ arr := Arr()
+ for _, err := range errs {
+ switch m := ErrorMarshalFunc(err).(type) {
+ case LogObjectMarshaler:
+ arr = arr.Object(m)
+ case error:
+ if m == nil || isNilValue(m) {
+ arr = arr.Interface(nil)
+ } else {
+ arr = arr.Str(m.Error())
+ }
+ case string:
+ arr = arr.Str(m)
+ default:
+ arr = arr.Interface(m)
+ }
+ }
+
+ return c.Array(key, arr)
+}
+
+// Err adds the field "error" with serialized err to the logger context.
+func (c Context) Err(err error) Context {
+ if c.l.stack && ErrorStackMarshaler != nil {
+ switch m := ErrorStackMarshaler(err).(type) {
+ case nil:
+ case LogObjectMarshaler:
+ c = c.Object(ErrorStackFieldName, m)
+ case error:
+ if m != nil && !isNilValue(m) {
+ c = c.Str(ErrorStackFieldName, m.Error())
+ }
+ case string:
+ c = c.Str(ErrorStackFieldName, m)
+ default:
+ c = c.Interface(ErrorStackFieldName, m)
+ }
+ }
+
+ return c.AnErr(ErrorFieldName, err)
+}
+
+// Ctx adds the context.Context to the logger context. The context.Context is
+// not rendered in the error message, but is made available for hooks to use.
+// A typical use case is to extract tracing information from the
+// context.Context.
+func (c Context) Ctx(ctx context.Context) Context {
+ c.l.ctx = ctx
+ return c
+}
+
+// Bool adds the field key with val as a bool to the logger context.
+func (c Context) Bool(key string, b bool) Context {
+ c.l.context = enc.AppendBool(enc.AppendKey(c.l.context, key), b)
+ return c
+}
+
+// Bools adds the field key with val as a []bool to the logger context.
+func (c Context) Bools(key string, b []bool) Context {
+ c.l.context = enc.AppendBools(enc.AppendKey(c.l.context, key), b)
+ return c
+}
+
+// Int adds the field key with i as a int to the logger context.
+func (c Context) Int(key string, i int) Context {
+ c.l.context = enc.AppendInt(enc.AppendKey(c.l.context, key), i)
+ return c
+}
+
+// Ints adds the field key with i as a []int to the logger context.
+func (c Context) Ints(key string, i []int) Context {
+ c.l.context = enc.AppendInts(enc.AppendKey(c.l.context, key), i)
+ return c
+}
+
+// Int8 adds the field key with i as a int8 to the logger context.
+func (c Context) Int8(key string, i int8) Context {
+ c.l.context = enc.AppendInt8(enc.AppendKey(c.l.context, key), i)
+ return c
+}
+
+// Ints8 adds the field key with i as a []int8 to the logger context.
+func (c Context) Ints8(key string, i []int8) Context {
+ c.l.context = enc.AppendInts8(enc.AppendKey(c.l.context, key), i)
+ return c
+}
+
+// Int16 adds the field key with i as a int16 to the logger context.
+func (c Context) Int16(key string, i int16) Context {
+ c.l.context = enc.AppendInt16(enc.AppendKey(c.l.context, key), i)
+ return c
+}
+
+// Ints16 adds the field key with i as a []int16 to the logger context.
+func (c Context) Ints16(key string, i []int16) Context {
+ c.l.context = enc.AppendInts16(enc.AppendKey(c.l.context, key), i)
+ return c
+}
+
+// Int32 adds the field key with i as a int32 to the logger context.
+func (c Context) Int32(key string, i int32) Context {
+ c.l.context = enc.AppendInt32(enc.AppendKey(c.l.context, key), i)
+ return c
+}
+
+// Ints32 adds the field key with i as a []int32 to the logger context.
+func (c Context) Ints32(key string, i []int32) Context {
+ c.l.context = enc.AppendInts32(enc.AppendKey(c.l.context, key), i)
+ return c
+}
+
+// Int64 adds the field key with i as a int64 to the logger context.
+func (c Context) Int64(key string, i int64) Context {
+ c.l.context = enc.AppendInt64(enc.AppendKey(c.l.context, key), i)
+ return c
+}
+
+// Ints64 adds the field key with i as a []int64 to the logger context.
+func (c Context) Ints64(key string, i []int64) Context {
+ c.l.context = enc.AppendInts64(enc.AppendKey(c.l.context, key), i)
+ return c
+}
+
+// Uint adds the field key with i as a uint to the logger context.
+func (c Context) Uint(key string, i uint) Context {
+ c.l.context = enc.AppendUint(enc.AppendKey(c.l.context, key), i)
+ return c
+}
+
+// Uints adds the field key with i as a []uint to the logger context.
+func (c Context) Uints(key string, i []uint) Context {
+ c.l.context = enc.AppendUints(enc.AppendKey(c.l.context, key), i)
+ return c
+}
+
+// Uint8 adds the field key with i as a uint8 to the logger context.
+func (c Context) Uint8(key string, i uint8) Context {
+ c.l.context = enc.AppendUint8(enc.AppendKey(c.l.context, key), i)
+ return c
+}
+
+// Uints8 adds the field key with i as a []uint8 to the logger context.
+func (c Context) Uints8(key string, i []uint8) Context {
+ c.l.context = enc.AppendUints8(enc.AppendKey(c.l.context, key), i)
+ return c
+}
+
+// Uint16 adds the field key with i as a uint16 to the logger context.
+func (c Context) Uint16(key string, i uint16) Context {
+ c.l.context = enc.AppendUint16(enc.AppendKey(c.l.context, key), i)
+ return c
+}
+
+// Uints16 adds the field key with i as a []uint16 to the logger context.
+func (c Context) Uints16(key string, i []uint16) Context {
+ c.l.context = enc.AppendUints16(enc.AppendKey(c.l.context, key), i)
+ return c
+}
+
+// Uint32 adds the field key with i as a uint32 to the logger context.
+func (c Context) Uint32(key string, i uint32) Context {
+ c.l.context = enc.AppendUint32(enc.AppendKey(c.l.context, key), i)
+ return c
+}
+
+// Uints32 adds the field key with i as a []uint32 to the logger context.
+func (c Context) Uints32(key string, i []uint32) Context {
+ c.l.context = enc.AppendUints32(enc.AppendKey(c.l.context, key), i)
+ return c
+}
+
+// Uint64 adds the field key with i as a uint64 to the logger context.
+func (c Context) Uint64(key string, i uint64) Context {
+ c.l.context = enc.AppendUint64(enc.AppendKey(c.l.context, key), i)
+ return c
+}
+
+// Uints64 adds the field key with i as a []uint64 to the logger context.
+func (c Context) Uints64(key string, i []uint64) Context {
+ c.l.context = enc.AppendUints64(enc.AppendKey(c.l.context, key), i)
+ return c
+}
+
+// Float32 adds the field key with f as a float32 to the logger context.
+func (c Context) Float32(key string, f float32) Context {
+ c.l.context = enc.AppendFloat32(enc.AppendKey(c.l.context, key), f, FloatingPointPrecision)
+ return c
+}
+
+// Floats32 adds the field key with f as a []float32 to the logger context.
+func (c Context) Floats32(key string, f []float32) Context {
+ c.l.context = enc.AppendFloats32(enc.AppendKey(c.l.context, key), f, FloatingPointPrecision)
+ return c
+}
+
+// Float64 adds the field key with f as a float64 to the logger context.
+func (c Context) Float64(key string, f float64) Context {
+ c.l.context = enc.AppendFloat64(enc.AppendKey(c.l.context, key), f, FloatingPointPrecision)
+ return c
+}
+
+// Floats64 adds the field key with f as a []float64 to the logger context.
+func (c Context) Floats64(key string, f []float64) Context {
+ c.l.context = enc.AppendFloats64(enc.AppendKey(c.l.context, key), f, FloatingPointPrecision)
+ return c
+}
+
+type timestampHook struct{}
+
+func (ts timestampHook) Run(e *Event, level Level, msg string) {
+ e.Timestamp()
+}
+
+var th = timestampHook{}
+
+// Timestamp adds the current local time to the logger context with the "time" key, formatted using zerolog.TimeFieldFormat.
+// To customize the key name, change zerolog.TimestampFieldName.
+// To customize the time format, change zerolog.TimeFieldFormat.
+//
+// NOTE: It won't dedupe the "time" key if the *Context has one already.
+func (c Context) Timestamp() Context {
+ c.l = c.l.Hook(th)
+ return c
+}
+
+// Time adds the field key with t formatted as string using zerolog.TimeFieldFormat.
+func (c Context) Time(key string, t time.Time) Context {
+ c.l.context = enc.AppendTime(enc.AppendKey(c.l.context, key), t, TimeFieldFormat)
+ return c
+}
+
+// Times adds the field key with t formatted as string using zerolog.TimeFieldFormat.
+func (c Context) Times(key string, t []time.Time) Context {
+ c.l.context = enc.AppendTimes(enc.AppendKey(c.l.context, key), t, TimeFieldFormat)
+ return c
+}
+
+// Dur adds the fields key with d divided by unit and stored as a float.
+func (c Context) Dur(key string, d time.Duration) Context {
+ c.l.context = enc.AppendDuration(enc.AppendKey(c.l.context, key), d, DurationFieldUnit, DurationFieldInteger, FloatingPointPrecision)
+ return c
+}
+
+// Durs adds the fields key with d divided by unit and stored as a float.
+func (c Context) Durs(key string, d []time.Duration) Context {
+ c.l.context = enc.AppendDurations(enc.AppendKey(c.l.context, key), d, DurationFieldUnit, DurationFieldInteger, FloatingPointPrecision)
+ return c
+}
+
+// Interface adds the field key with obj marshaled using reflection.
+func (c Context) Interface(key string, i interface{}) Context {
+ if obj, ok := i.(LogObjectMarshaler); ok {
+ return c.Object(key, obj)
+ }
+ c.l.context = enc.AppendInterface(enc.AppendKey(c.l.context, key), i)
+ return c
+}
+
+// Type adds the field key with val's type using reflection.
+func (c Context) Type(key string, val interface{}) Context {
+ c.l.context = enc.AppendType(enc.AppendKey(c.l.context, key), val)
+ return c
+}
+
+// Any is a wrapper around Context.Interface.
+func (c Context) Any(key string, i interface{}) Context {
+ return c.Interface(key, i)
+}
+
+// Reset removes all the context fields.
+func (c Context) Reset() Context {
+ c.l.context = enc.AppendBeginMarker(make([]byte, 0, 500))
+ return c
+}
+
+type callerHook struct {
+ callerSkipFrameCount int
+}
+
+func newCallerHook(skipFrameCount int) callerHook {
+ return callerHook{callerSkipFrameCount: skipFrameCount}
+}
+
+func (ch callerHook) Run(e *Event, level Level, msg string) {
+ switch ch.callerSkipFrameCount {
+ case useGlobalSkipFrameCount:
+ // Extra frames to skip (added by hook infra).
+ e.caller(CallerSkipFrameCount + contextCallerSkipFrameCount)
+ default:
+ // Extra frames to skip (added by hook infra).
+ e.caller(ch.callerSkipFrameCount + contextCallerSkipFrameCount)
+ }
+}
+
+// useGlobalSkipFrameCount acts as a flag to informat callerHook.Run
+// to use the global CallerSkipFrameCount.
+const useGlobalSkipFrameCount = math.MinInt32
+
+// ch is the default caller hook using the global CallerSkipFrameCount.
+var ch = newCallerHook(useGlobalSkipFrameCount)
+
+// Caller adds the file:line of the caller with the zerolog.CallerFieldName key.
+func (c Context) Caller() Context {
+ c.l = c.l.Hook(ch)
+ return c
+}
+
+// CallerWithSkipFrameCount adds the file:line of the caller with the zerolog.CallerFieldName key.
+// The specified skipFrameCount int will override the global CallerSkipFrameCount for this context's respective logger.
+// If set to -1 the global CallerSkipFrameCount will be used.
+func (c Context) CallerWithSkipFrameCount(skipFrameCount int) Context {
+ c.l = c.l.Hook(newCallerHook(skipFrameCount))
+ return c
+}
+
+// Stack enables stack trace printing for the error passed to Err().
+func (c Context) Stack() Context {
+ c.l.stack = true
+ return c
+}
+
+// IPAddr adds IPv4 or IPv6 Address to the context
+func (c Context) IPAddr(key string, ip net.IP) Context {
+ c.l.context = enc.AppendIPAddr(enc.AppendKey(c.l.context, key), ip)
+ return c
+}
+
+// IPPrefix adds IPv4 or IPv6 Prefix (address and mask) to the context
+func (c Context) IPPrefix(key string, pfx net.IPNet) Context {
+ c.l.context = enc.AppendIPPrefix(enc.AppendKey(c.l.context, key), pfx)
+ return c
+}
+
+// MACAddr adds MAC address to the context
+func (c Context) MACAddr(key string, ha net.HardwareAddr) Context {
+ c.l.context = enc.AppendMACAddr(enc.AppendKey(c.l.context, key), ha)
+ return c
+}
diff --git a/vendor/github.com/rs/zerolog/ctx.go b/vendor/github.com/rs/zerolog/ctx.go
new file mode 100644
index 0000000..60432d1
--- /dev/null
+++ b/vendor/github.com/rs/zerolog/ctx.go
@@ -0,0 +1,52 @@
+package zerolog
+
+import (
+ "context"
+)
+
+var disabledLogger *Logger
+
+func init() {
+ SetGlobalLevel(TraceLevel)
+ l := Nop()
+ disabledLogger = &l
+}
+
+type ctxKey struct{}
+
+// WithContext returns a copy of ctx with the receiver attached. The Logger
+// attached to the provided Context (if any) will not be effected. If the
+// receiver's log level is Disabled it will only be attached to the returned
+// Context if the provided Context has a previously attached Logger. If the
+// provided Context has no attached Logger, a Disabled Logger will not be
+// attached.
+//
+// Note: to modify the existing Logger attached to a Context (instead of
+// replacing it in a new Context), use UpdateContext with the following
+// notation:
+//
+// ctx := r.Context()
+// l := zerolog.Ctx(ctx)
+// l.UpdateContext(func(c Context) Context {
+// return c.Str("bar", "baz")
+// })
+//
+func (l Logger) WithContext(ctx context.Context) context.Context {
+ if _, ok := ctx.Value(ctxKey{}).(*Logger); !ok && l.level == Disabled {
+ // Do not store disabled logger.
+ return ctx
+ }
+ return context.WithValue(ctx, ctxKey{}, &l)
+}
+
+// Ctx returns the Logger associated with the ctx. If no logger
+// is associated, DefaultContextLogger is returned, unless DefaultContextLogger
+// is nil, in which case a disabled logger is returned.
+func Ctx(ctx context.Context) *Logger {
+ if l, ok := ctx.Value(ctxKey{}).(*Logger); ok {
+ return l
+ } else if l = DefaultContextLogger; l != nil {
+ return l
+ }
+ return disabledLogger
+}
diff --git a/vendor/github.com/rs/zerolog/encoder.go b/vendor/github.com/rs/zerolog/encoder.go
new file mode 100644
index 0000000..4dbaf38
--- /dev/null
+++ b/vendor/github.com/rs/zerolog/encoder.go
@@ -0,0 +1,56 @@
+package zerolog
+
+import (
+ "net"
+ "time"
+)
+
+type encoder interface {
+ AppendArrayDelim(dst []byte) []byte
+ AppendArrayEnd(dst []byte) []byte
+ AppendArrayStart(dst []byte) []byte
+ AppendBeginMarker(dst []byte) []byte
+ AppendBool(dst []byte, val bool) []byte
+ AppendBools(dst []byte, vals []bool) []byte
+ AppendBytes(dst, s []byte) []byte
+ AppendDuration(dst []byte, d time.Duration, unit time.Duration, useInt bool, precision int) []byte
+ AppendDurations(dst []byte, vals []time.Duration, unit time.Duration, useInt bool, precision int) []byte
+ AppendEndMarker(dst []byte) []byte
+ AppendFloat32(dst []byte, val float32, precision int) []byte
+ AppendFloat64(dst []byte, val float64, precision int) []byte
+ AppendFloats32(dst []byte, vals []float32, precision int) []byte
+ AppendFloats64(dst []byte, vals []float64, precision int) []byte
+ AppendHex(dst, s []byte) []byte
+ AppendIPAddr(dst []byte, ip net.IP) []byte
+ AppendIPPrefix(dst []byte, pfx net.IPNet) []byte
+ AppendInt(dst []byte, val int) []byte
+ AppendInt16(dst []byte, val int16) []byte
+ AppendInt32(dst []byte, val int32) []byte
+ AppendInt64(dst []byte, val int64) []byte
+ AppendInt8(dst []byte, val int8) []byte
+ AppendInterface(dst []byte, i interface{}) []byte
+ AppendInts(dst []byte, vals []int) []byte
+ AppendInts16(dst []byte, vals []int16) []byte
+ AppendInts32(dst []byte, vals []int32) []byte
+ AppendInts64(dst []byte, vals []int64) []byte
+ AppendInts8(dst []byte, vals []int8) []byte
+ AppendKey(dst []byte, key string) []byte
+ AppendLineBreak(dst []byte) []byte
+ AppendMACAddr(dst []byte, ha net.HardwareAddr) []byte
+ AppendNil(dst []byte) []byte
+ AppendObjectData(dst []byte, o []byte) []byte
+ AppendString(dst []byte, s string) []byte
+ AppendStrings(dst []byte, vals []string) []byte
+ AppendTime(dst []byte, t time.Time, format string) []byte
+ AppendTimes(dst []byte, vals []time.Time, format string) []byte
+ AppendUint(dst []byte, val uint) []byte
+ AppendUint16(dst []byte, val uint16) []byte
+ AppendUint32(dst []byte, val uint32) []byte
+ AppendUint64(dst []byte, val uint64) []byte
+ AppendUint8(dst []byte, val uint8) []byte
+ AppendUints(dst []byte, vals []uint) []byte
+ AppendUints16(dst []byte, vals []uint16) []byte
+ AppendUints32(dst []byte, vals []uint32) []byte
+ AppendUints64(dst []byte, vals []uint64) []byte
+ AppendUints8(dst []byte, vals []uint8) []byte
+}
diff --git a/vendor/github.com/rs/zerolog/encoder_cbor.go b/vendor/github.com/rs/zerolog/encoder_cbor.go
new file mode 100644
index 0000000..36cb994
--- /dev/null
+++ b/vendor/github.com/rs/zerolog/encoder_cbor.go
@@ -0,0 +1,45 @@
+// +build binary_log
+
+package zerolog
+
+// This file contains bindings to do binary encoding.
+
+import (
+ "github.com/rs/zerolog/internal/cbor"
+)
+
+var (
+ _ encoder = (*cbor.Encoder)(nil)
+
+ enc = cbor.Encoder{}
+)
+
+func init() {
+ // using closure to reflect the changes at runtime.
+ cbor.JSONMarshalFunc = func(v interface{}) ([]byte, error) {
+ return InterfaceMarshalFunc(v)
+ }
+}
+
+func appendJSON(dst []byte, j []byte) []byte {
+ return cbor.AppendEmbeddedJSON(dst, j)
+}
+func appendCBOR(dst []byte, c []byte) []byte {
+ return cbor.AppendEmbeddedCBOR(dst, c)
+}
+
+// decodeIfBinaryToString - converts a binary formatted log msg to a
+// JSON formatted String Log message.
+func decodeIfBinaryToString(in []byte) string {
+ return cbor.DecodeIfBinaryToString(in)
+}
+
+func decodeObjectToStr(in []byte) string {
+ return cbor.DecodeObjectToStr(in)
+}
+
+// decodeIfBinaryToBytes - converts a binary formatted log msg to a
+// JSON formatted Bytes Log message.
+func decodeIfBinaryToBytes(in []byte) []byte {
+ return cbor.DecodeIfBinaryToBytes(in)
+}
diff --git a/vendor/github.com/rs/zerolog/encoder_json.go b/vendor/github.com/rs/zerolog/encoder_json.go
new file mode 100644
index 0000000..6f96c68
--- /dev/null
+++ b/vendor/github.com/rs/zerolog/encoder_json.go
@@ -0,0 +1,51 @@
+// +build !binary_log
+
+package zerolog
+
+// encoder_json.go file contains bindings to generate
+// JSON encoded byte stream.
+
+import (
+ "encoding/base64"
+ "github.com/rs/zerolog/internal/json"
+)
+
+var (
+ _ encoder = (*json.Encoder)(nil)
+
+ enc = json.Encoder{}
+)
+
+func init() {
+ // using closure to reflect the changes at runtime.
+ json.JSONMarshalFunc = func(v interface{}) ([]byte, error) {
+ return InterfaceMarshalFunc(v)
+ }
+}
+
+func appendJSON(dst []byte, j []byte) []byte {
+ return append(dst, j...)
+}
+func appendCBOR(dst []byte, cbor []byte) []byte {
+ dst = append(dst, []byte("\"data:application/cbor;base64,")...)
+ l := len(dst)
+ enc := base64.StdEncoding
+ n := enc.EncodedLen(len(cbor))
+ for i := 0; i < n; i++ {
+ dst = append(dst, '.')
+ }
+ enc.Encode(dst[l:], cbor)
+ return append(dst, '"')
+}
+
+func decodeIfBinaryToString(in []byte) string {
+ return string(in)
+}
+
+func decodeObjectToStr(in []byte) string {
+ return string(in)
+}
+
+func decodeIfBinaryToBytes(in []byte) []byte {
+ return in
+}
diff --git a/vendor/github.com/rs/zerolog/event.go b/vendor/github.com/rs/zerolog/event.go
new file mode 100644
index 0000000..56de606
--- /dev/null
+++ b/vendor/github.com/rs/zerolog/event.go
@@ -0,0 +1,830 @@
+package zerolog
+
+import (
+ "context"
+ "fmt"
+ "net"
+ "os"
+ "runtime"
+ "sync"
+ "time"
+)
+
+var eventPool = &sync.Pool{
+ New: func() interface{} {
+ return &Event{
+ buf: make([]byte, 0, 500),
+ }
+ },
+}
+
+// Event represents a log event. It is instanced by one of the level method of
+// Logger and finalized by the Msg or Msgf method.
+type Event struct {
+ buf []byte
+ w LevelWriter
+ level Level
+ done func(msg string)
+ stack bool // enable error stack trace
+ ch []Hook // hooks from context
+ skipFrame int // The number of additional frames to skip when printing the caller.
+ ctx context.Context // Optional Go context for event
+}
+
+func putEvent(e *Event) {
+ // Proper usage of a sync.Pool requires each entry to have approximately
+ // the same memory cost. To obtain this property when the stored type
+ // contains a variably-sized buffer, we add a hard limit on the maximum buffer
+ // to place back in the pool.
+ //
+ // See https://golang.org/issue/23199
+ const maxSize = 1 << 16 // 64KiB
+ if cap(e.buf) > maxSize {
+ return
+ }
+ eventPool.Put(e)
+}
+
+// LogObjectMarshaler provides a strongly-typed and encoding-agnostic interface
+// to be implemented by types used with Event/Context's Object methods.
+type LogObjectMarshaler interface {
+ MarshalZerologObject(e *Event)
+}
+
+// LogArrayMarshaler provides a strongly-typed and encoding-agnostic interface
+// to be implemented by types used with Event/Context's Array methods.
+type LogArrayMarshaler interface {
+ MarshalZerologArray(a *Array)
+}
+
+func newEvent(w LevelWriter, level Level) *Event {
+ e := eventPool.Get().(*Event)
+ e.buf = e.buf[:0]
+ e.ch = nil
+ e.buf = enc.AppendBeginMarker(e.buf)
+ e.w = w
+ e.level = level
+ e.stack = false
+ e.skipFrame = 0
+ return e
+}
+
+func (e *Event) write() (err error) {
+ if e == nil {
+ return nil
+ }
+ if e.level != Disabled {
+ e.buf = enc.AppendEndMarker(e.buf)
+ e.buf = enc.AppendLineBreak(e.buf)
+ if e.w != nil {
+ _, err = e.w.WriteLevel(e.level, e.buf)
+ }
+ }
+ putEvent(e)
+ return
+}
+
+// Enabled return false if the *Event is going to be filtered out by
+// log level or sampling.
+func (e *Event) Enabled() bool {
+ return e != nil && e.level != Disabled
+}
+
+// Discard disables the event so Msg(f) won't print it.
+func (e *Event) Discard() *Event {
+ if e == nil {
+ return e
+ }
+ e.level = Disabled
+ return nil
+}
+
+// Msg sends the *Event with msg added as the message field if not empty.
+//
+// NOTICE: once this method is called, the *Event should be disposed.
+// Calling Msg twice can have unexpected result.
+func (e *Event) Msg(msg string) {
+ if e == nil {
+ return
+ }
+ e.msg(msg)
+}
+
+// Send is equivalent to calling Msg("").
+//
+// NOTICE: once this method is called, the *Event should be disposed.
+func (e *Event) Send() {
+ if e == nil {
+ return
+ }
+ e.msg("")
+}
+
+// Msgf sends the event with formatted msg added as the message field if not empty.
+//
+// NOTICE: once this method is called, the *Event should be disposed.
+// Calling Msgf twice can have unexpected result.
+func (e *Event) Msgf(format string, v ...interface{}) {
+ if e == nil {
+ return
+ }
+ e.msg(fmt.Sprintf(format, v...))
+}
+
+func (e *Event) MsgFunc(createMsg func() string) {
+ if e == nil {
+ return
+ }
+ e.msg(createMsg())
+}
+
+func (e *Event) msg(msg string) {
+ for _, hook := range e.ch {
+ hook.Run(e, e.level, msg)
+ }
+ if msg != "" {
+ e.buf = enc.AppendString(enc.AppendKey(e.buf, MessageFieldName), msg)
+ }
+ if e.done != nil {
+ defer e.done(msg)
+ }
+ if err := e.write(); err != nil {
+ if ErrorHandler != nil {
+ ErrorHandler(err)
+ } else {
+ fmt.Fprintf(os.Stderr, "zerolog: could not write event: %v\n", err)
+ }
+ }
+}
+
+// Fields is a helper function to use a map or slice to set fields using type assertion.
+// Only map[string]interface{} and []interface{} are accepted. []interface{} must
+// alternate string keys and arbitrary values, and extraneous ones are ignored.
+func (e *Event) Fields(fields interface{}) *Event {
+ if e == nil {
+ return e
+ }
+ e.buf = appendFields(e.buf, fields, e.stack)
+ return e
+}
+
+// Dict adds the field key with a dict to the event context.
+// Use zerolog.Dict() to create the dictionary.
+func (e *Event) Dict(key string, dict *Event) *Event {
+ if e == nil {
+ return e
+ }
+ dict.buf = enc.AppendEndMarker(dict.buf)
+ e.buf = append(enc.AppendKey(e.buf, key), dict.buf...)
+ putEvent(dict)
+ return e
+}
+
+// Dict creates an Event to be used with the *Event.Dict method.
+// Call usual field methods like Str, Int etc to add fields to this
+// event and give it as argument the *Event.Dict method.
+func Dict() *Event {
+ return newEvent(nil, 0)
+}
+
+// Array adds the field key with an array to the event context.
+// Use zerolog.Arr() to create the array or pass a type that
+// implement the LogArrayMarshaler interface.
+func (e *Event) Array(key string, arr LogArrayMarshaler) *Event {
+ if e == nil {
+ return e
+ }
+ e.buf = enc.AppendKey(e.buf, key)
+ var a *Array
+ if aa, ok := arr.(*Array); ok {
+ a = aa
+ } else {
+ a = Arr()
+ arr.MarshalZerologArray(a)
+ }
+ e.buf = a.write(e.buf)
+ return e
+}
+
+func (e *Event) appendObject(obj LogObjectMarshaler) {
+ e.buf = enc.AppendBeginMarker(e.buf)
+ obj.MarshalZerologObject(e)
+ e.buf = enc.AppendEndMarker(e.buf)
+}
+
+// Object marshals an object that implement the LogObjectMarshaler interface.
+func (e *Event) Object(key string, obj LogObjectMarshaler) *Event {
+ if e == nil {
+ return e
+ }
+ e.buf = enc.AppendKey(e.buf, key)
+ if obj == nil {
+ e.buf = enc.AppendNil(e.buf)
+
+ return e
+ }
+
+ e.appendObject(obj)
+ return e
+}
+
+// Func allows an anonymous func to run only if the event is enabled.
+func (e *Event) Func(f func(e *Event)) *Event {
+ if e != nil && e.Enabled() {
+ f(e)
+ }
+ return e
+}
+
+// EmbedObject marshals an object that implement the LogObjectMarshaler interface.
+func (e *Event) EmbedObject(obj LogObjectMarshaler) *Event {
+ if e == nil {
+ return e
+ }
+ if obj == nil {
+ return e
+ }
+ obj.MarshalZerologObject(e)
+ return e
+}
+
+// Str adds the field key with val as a string to the *Event context.
+func (e *Event) Str(key, val string) *Event {
+ if e == nil {
+ return e
+ }
+ e.buf = enc.AppendString(enc.AppendKey(e.buf, key), val)
+ return e
+}
+
+// Strs adds the field key with vals as a []string to the *Event context.
+func (e *Event) Strs(key string, vals []string) *Event {
+ if e == nil {
+ return e
+ }
+ e.buf = enc.AppendStrings(enc.AppendKey(e.buf, key), vals)
+ return e
+}
+
+// Stringer adds the field key with val.String() (or null if val is nil)
+// to the *Event context.
+func (e *Event) Stringer(key string, val fmt.Stringer) *Event {
+ if e == nil {
+ return e
+ }
+ e.buf = enc.AppendStringer(enc.AppendKey(e.buf, key), val)
+ return e
+}
+
+// Stringers adds the field key with vals where each individual val
+// is used as val.String() (or null if val is empty) to the *Event
+// context.
+func (e *Event) Stringers(key string, vals []fmt.Stringer) *Event {
+ if e == nil {
+ return e
+ }
+ e.buf = enc.AppendStringers(enc.AppendKey(e.buf, key), vals)
+ return e
+}
+
+// Bytes adds the field key with val as a string to the *Event context.
+//
+// Runes outside of normal ASCII ranges will be hex-encoded in the resulting
+// JSON.
+func (e *Event) Bytes(key string, val []byte) *Event {
+ if e == nil {
+ return e
+ }
+ e.buf = enc.AppendBytes(enc.AppendKey(e.buf, key), val)
+ return e
+}
+
+// Hex adds the field key with val as a hex string to the *Event context.
+func (e *Event) Hex(key string, val []byte) *Event {
+ if e == nil {
+ return e
+ }
+ e.buf = enc.AppendHex(enc.AppendKey(e.buf, key), val)
+ return e
+}
+
+// RawJSON adds already encoded JSON to the log line under key.
+//
+// No sanity check is performed on b; it must not contain carriage returns and
+// be valid JSON.
+func (e *Event) RawJSON(key string, b []byte) *Event {
+ if e == nil {
+ return e
+ }
+ e.buf = appendJSON(enc.AppendKey(e.buf, key), b)
+ return e
+}
+
+// RawCBOR adds already encoded CBOR to the log line under key.
+//
+// No sanity check is performed on b
+// Note: The full featureset of CBOR is supported as data will not be mapped to json but stored as data-url
+func (e *Event) RawCBOR(key string, b []byte) *Event {
+ if e == nil {
+ return e
+ }
+ e.buf = appendCBOR(enc.AppendKey(e.buf, key), b)
+ return e
+}
+
+// AnErr adds the field key with serialized err to the *Event context.
+// If err is nil, no field is added.
+func (e *Event) AnErr(key string, err error) *Event {
+ if e == nil {
+ return e
+ }
+ switch m := ErrorMarshalFunc(err).(type) {
+ case nil:
+ return e
+ case LogObjectMarshaler:
+ return e.Object(key, m)
+ case error:
+ if m == nil || isNilValue(m) {
+ return e
+ } else {
+ return e.Str(key, m.Error())
+ }
+ case string:
+ return e.Str(key, m)
+ default:
+ return e.Interface(key, m)
+ }
+}
+
+// Errs adds the field key with errs as an array of serialized errors to the
+// *Event context.
+func (e *Event) Errs(key string, errs []error) *Event {
+ if e == nil {
+ return e
+ }
+ arr := Arr()
+ for _, err := range errs {
+ switch m := ErrorMarshalFunc(err).(type) {
+ case LogObjectMarshaler:
+ arr = arr.Object(m)
+ case error:
+ arr = arr.Err(m)
+ case string:
+ arr = arr.Str(m)
+ default:
+ arr = arr.Interface(m)
+ }
+ }
+
+ return e.Array(key, arr)
+}
+
+// Err adds the field "error" with serialized err to the *Event context.
+// If err is nil, no field is added.
+//
+// To customize the key name, change zerolog.ErrorFieldName.
+//
+// If Stack() has been called before and zerolog.ErrorStackMarshaler is defined,
+// the err is passed to ErrorStackMarshaler and the result is appended to the
+// zerolog.ErrorStackFieldName.
+func (e *Event) Err(err error) *Event {
+ if e == nil {
+ return e
+ }
+ if e.stack && ErrorStackMarshaler != nil {
+ switch m := ErrorStackMarshaler(err).(type) {
+ case nil:
+ case LogObjectMarshaler:
+ e.Object(ErrorStackFieldName, m)
+ case error:
+ if m != nil && !isNilValue(m) {
+ e.Str(ErrorStackFieldName, m.Error())
+ }
+ case string:
+ e.Str(ErrorStackFieldName, m)
+ default:
+ e.Interface(ErrorStackFieldName, m)
+ }
+ }
+ return e.AnErr(ErrorFieldName, err)
+}
+
+// Stack enables stack trace printing for the error passed to Err().
+//
+// ErrorStackMarshaler must be set for this method to do something.
+func (e *Event) Stack() *Event {
+ if e != nil {
+ e.stack = true
+ }
+ return e
+}
+
+// Ctx adds the Go Context to the *Event context. The context is not rendered
+// in the output message, but is available to hooks and to Func() calls via the
+// GetCtx() accessor. A typical use case is to extract tracing information from
+// the Go Ctx.
+func (e *Event) Ctx(ctx context.Context) *Event {
+ if e != nil {
+ e.ctx = ctx
+ }
+ return e
+}
+
+// GetCtx retrieves the Go context.Context which is optionally stored in the
+// Event. This allows Hooks and functions passed to Func() to retrieve values
+// which are stored in the context.Context. This can be useful in tracing,
+// where span information is commonly propagated in the context.Context.
+func (e *Event) GetCtx() context.Context {
+ if e == nil || e.ctx == nil {
+ return context.Background()
+ }
+ return e.ctx
+}
+
+// Bool adds the field key with val as a bool to the *Event context.
+func (e *Event) Bool(key string, b bool) *Event {
+ if e == nil {
+ return e
+ }
+ e.buf = enc.AppendBool(enc.AppendKey(e.buf, key), b)
+ return e
+}
+
+// Bools adds the field key with val as a []bool to the *Event context.
+func (e *Event) Bools(key string, b []bool) *Event {
+ if e == nil {
+ return e
+ }
+ e.buf = enc.AppendBools(enc.AppendKey(e.buf, key), b)
+ return e
+}
+
+// Int adds the field key with i as a int to the *Event context.
+func (e *Event) Int(key string, i int) *Event {
+ if e == nil {
+ return e
+ }
+ e.buf = enc.AppendInt(enc.AppendKey(e.buf, key), i)
+ return e
+}
+
+// Ints adds the field key with i as a []int to the *Event context.
+func (e *Event) Ints(key string, i []int) *Event {
+ if e == nil {
+ return e
+ }
+ e.buf = enc.AppendInts(enc.AppendKey(e.buf, key), i)
+ return e
+}
+
+// Int8 adds the field key with i as a int8 to the *Event context.
+func (e *Event) Int8(key string, i int8) *Event {
+ if e == nil {
+ return e
+ }
+ e.buf = enc.AppendInt8(enc.AppendKey(e.buf, key), i)
+ return e
+}
+
+// Ints8 adds the field key with i as a []int8 to the *Event context.
+func (e *Event) Ints8(key string, i []int8) *Event {
+ if e == nil {
+ return e
+ }
+ e.buf = enc.AppendInts8(enc.AppendKey(e.buf, key), i)
+ return e
+}
+
+// Int16 adds the field key with i as a int16 to the *Event context.
+func (e *Event) Int16(key string, i int16) *Event {
+ if e == nil {
+ return e
+ }
+ e.buf = enc.AppendInt16(enc.AppendKey(e.buf, key), i)
+ return e
+}
+
+// Ints16 adds the field key with i as a []int16 to the *Event context.
+func (e *Event) Ints16(key string, i []int16) *Event {
+ if e == nil {
+ return e
+ }
+ e.buf = enc.AppendInts16(enc.AppendKey(e.buf, key), i)
+ return e
+}
+
+// Int32 adds the field key with i as a int32 to the *Event context.
+func (e *Event) Int32(key string, i int32) *Event {
+ if e == nil {
+ return e
+ }
+ e.buf = enc.AppendInt32(enc.AppendKey(e.buf, key), i)
+ return e
+}
+
+// Ints32 adds the field key with i as a []int32 to the *Event context.
+func (e *Event) Ints32(key string, i []int32) *Event {
+ if e == nil {
+ return e
+ }
+ e.buf = enc.AppendInts32(enc.AppendKey(e.buf, key), i)
+ return e
+}
+
+// Int64 adds the field key with i as a int64 to the *Event context.
+func (e *Event) Int64(key string, i int64) *Event {
+ if e == nil {
+ return e
+ }
+ e.buf = enc.AppendInt64(enc.AppendKey(e.buf, key), i)
+ return e
+}
+
+// Ints64 adds the field key with i as a []int64 to the *Event context.
+func (e *Event) Ints64(key string, i []int64) *Event {
+ if e == nil {
+ return e
+ }
+ e.buf = enc.AppendInts64(enc.AppendKey(e.buf, key), i)
+ return e
+}
+
+// Uint adds the field key with i as a uint to the *Event context.
+func (e *Event) Uint(key string, i uint) *Event {
+ if e == nil {
+ return e
+ }
+ e.buf = enc.AppendUint(enc.AppendKey(e.buf, key), i)
+ return e
+}
+
+// Uints adds the field key with i as a []int to the *Event context.
+func (e *Event) Uints(key string, i []uint) *Event {
+ if e == nil {
+ return e
+ }
+ e.buf = enc.AppendUints(enc.AppendKey(e.buf, key), i)
+ return e
+}
+
+// Uint8 adds the field key with i as a uint8 to the *Event context.
+func (e *Event) Uint8(key string, i uint8) *Event {
+ if e == nil {
+ return e
+ }
+ e.buf = enc.AppendUint8(enc.AppendKey(e.buf, key), i)
+ return e
+}
+
+// Uints8 adds the field key with i as a []int8 to the *Event context.
+func (e *Event) Uints8(key string, i []uint8) *Event {
+ if e == nil {
+ return e
+ }
+ e.buf = enc.AppendUints8(enc.AppendKey(e.buf, key), i)
+ return e
+}
+
+// Uint16 adds the field key with i as a uint16 to the *Event context.
+func (e *Event) Uint16(key string, i uint16) *Event {
+ if e == nil {
+ return e
+ }
+ e.buf = enc.AppendUint16(enc.AppendKey(e.buf, key), i)
+ return e
+}
+
+// Uints16 adds the field key with i as a []int16 to the *Event context.
+func (e *Event) Uints16(key string, i []uint16) *Event {
+ if e == nil {
+ return e
+ }
+ e.buf = enc.AppendUints16(enc.AppendKey(e.buf, key), i)
+ return e
+}
+
+// Uint32 adds the field key with i as a uint32 to the *Event context.
+func (e *Event) Uint32(key string, i uint32) *Event {
+ if e == nil {
+ return e
+ }
+ e.buf = enc.AppendUint32(enc.AppendKey(e.buf, key), i)
+ return e
+}
+
+// Uints32 adds the field key with i as a []int32 to the *Event context.
+func (e *Event) Uints32(key string, i []uint32) *Event {
+ if e == nil {
+ return e
+ }
+ e.buf = enc.AppendUints32(enc.AppendKey(e.buf, key), i)
+ return e
+}
+
+// Uint64 adds the field key with i as a uint64 to the *Event context.
+func (e *Event) Uint64(key string, i uint64) *Event {
+ if e == nil {
+ return e
+ }
+ e.buf = enc.AppendUint64(enc.AppendKey(e.buf, key), i)
+ return e
+}
+
+// Uints64 adds the field key with i as a []int64 to the *Event context.
+func (e *Event) Uints64(key string, i []uint64) *Event {
+ if e == nil {
+ return e
+ }
+ e.buf = enc.AppendUints64(enc.AppendKey(e.buf, key), i)
+ return e
+}
+
+// Float32 adds the field key with f as a float32 to the *Event context.
+func (e *Event) Float32(key string, f float32) *Event {
+ if e == nil {
+ return e
+ }
+ e.buf = enc.AppendFloat32(enc.AppendKey(e.buf, key), f, FloatingPointPrecision)
+ return e
+}
+
+// Floats32 adds the field key with f as a []float32 to the *Event context.
+func (e *Event) Floats32(key string, f []float32) *Event {
+ if e == nil {
+ return e
+ }
+ e.buf = enc.AppendFloats32(enc.AppendKey(e.buf, key), f, FloatingPointPrecision)
+ return e
+}
+
+// Float64 adds the field key with f as a float64 to the *Event context.
+func (e *Event) Float64(key string, f float64) *Event {
+ if e == nil {
+ return e
+ }
+ e.buf = enc.AppendFloat64(enc.AppendKey(e.buf, key), f, FloatingPointPrecision)
+ return e
+}
+
+// Floats64 adds the field key with f as a []float64 to the *Event context.
+func (e *Event) Floats64(key string, f []float64) *Event {
+ if e == nil {
+ return e
+ }
+ e.buf = enc.AppendFloats64(enc.AppendKey(e.buf, key), f, FloatingPointPrecision)
+ return e
+}
+
+// Timestamp adds the current local time as UNIX timestamp to the *Event context with the "time" key.
+// To customize the key name, change zerolog.TimestampFieldName.
+//
+// NOTE: It won't dedupe the "time" key if the *Event (or *Context) has one
+// already.
+func (e *Event) Timestamp() *Event {
+ if e == nil {
+ return e
+ }
+ e.buf = enc.AppendTime(enc.AppendKey(e.buf, TimestampFieldName), TimestampFunc(), TimeFieldFormat)
+ return e
+}
+
+// Time adds the field key with t formatted as string using zerolog.TimeFieldFormat.
+func (e *Event) Time(key string, t time.Time) *Event {
+ if e == nil {
+ return e
+ }
+ e.buf = enc.AppendTime(enc.AppendKey(e.buf, key), t, TimeFieldFormat)
+ return e
+}
+
+// Times adds the field key with t formatted as string using zerolog.TimeFieldFormat.
+func (e *Event) Times(key string, t []time.Time) *Event {
+ if e == nil {
+ return e
+ }
+ e.buf = enc.AppendTimes(enc.AppendKey(e.buf, key), t, TimeFieldFormat)
+ return e
+}
+
+// Dur adds the field key with duration d stored as zerolog.DurationFieldUnit.
+// If zerolog.DurationFieldInteger is true, durations are rendered as integer
+// instead of float.
+func (e *Event) Dur(key string, d time.Duration) *Event {
+ if e == nil {
+ return e
+ }
+ e.buf = enc.AppendDuration(enc.AppendKey(e.buf, key), d, DurationFieldUnit, DurationFieldInteger, FloatingPointPrecision)
+ return e
+}
+
+// Durs adds the field key with duration d stored as zerolog.DurationFieldUnit.
+// If zerolog.DurationFieldInteger is true, durations are rendered as integer
+// instead of float.
+func (e *Event) Durs(key string, d []time.Duration) *Event {
+ if e == nil {
+ return e
+ }
+ e.buf = enc.AppendDurations(enc.AppendKey(e.buf, key), d, DurationFieldUnit, DurationFieldInteger, FloatingPointPrecision)
+ return e
+}
+
+// TimeDiff adds the field key with positive duration between time t and start.
+// If time t is not greater than start, duration will be 0.
+// Duration format follows the same principle as Dur().
+func (e *Event) TimeDiff(key string, t time.Time, start time.Time) *Event {
+ if e == nil {
+ return e
+ }
+ var d time.Duration
+ if t.After(start) {
+ d = t.Sub(start)
+ }
+ e.buf = enc.AppendDuration(enc.AppendKey(e.buf, key), d, DurationFieldUnit, DurationFieldInteger, FloatingPointPrecision)
+ return e
+}
+
+// Any is a wrapper around Event.Interface.
+func (e *Event) Any(key string, i interface{}) *Event {
+ return e.Interface(key, i)
+}
+
+// Interface adds the field key with i marshaled using reflection.
+func (e *Event) Interface(key string, i interface{}) *Event {
+ if e == nil {
+ return e
+ }
+ if obj, ok := i.(LogObjectMarshaler); ok {
+ return e.Object(key, obj)
+ }
+ e.buf = enc.AppendInterface(enc.AppendKey(e.buf, key), i)
+ return e
+}
+
+// Type adds the field key with val's type using reflection.
+func (e *Event) Type(key string, val interface{}) *Event {
+ if e == nil {
+ return e
+ }
+ e.buf = enc.AppendType(enc.AppendKey(e.buf, key), val)
+ return e
+}
+
+// CallerSkipFrame instructs any future Caller calls to skip the specified number of frames.
+// This includes those added via hooks from the context.
+func (e *Event) CallerSkipFrame(skip int) *Event {
+ if e == nil {
+ return e
+ }
+ e.skipFrame += skip
+ return e
+}
+
+// Caller adds the file:line of the caller with the zerolog.CallerFieldName key.
+// The argument skip is the number of stack frames to ascend
+// Skip If not passed, use the global variable CallerSkipFrameCount
+func (e *Event) Caller(skip ...int) *Event {
+ sk := CallerSkipFrameCount
+ if len(skip) > 0 {
+ sk = skip[0] + CallerSkipFrameCount
+ }
+ return e.caller(sk)
+}
+
+func (e *Event) caller(skip int) *Event {
+ if e == nil {
+ return e
+ }
+ pc, file, line, ok := runtime.Caller(skip + e.skipFrame)
+ if !ok {
+ return e
+ }
+ e.buf = enc.AppendString(enc.AppendKey(e.buf, CallerFieldName), CallerMarshalFunc(pc, file, line))
+ return e
+}
+
+// IPAddr adds IPv4 or IPv6 Address to the event
+func (e *Event) IPAddr(key string, ip net.IP) *Event {
+ if e == nil {
+ return e
+ }
+ e.buf = enc.AppendIPAddr(enc.AppendKey(e.buf, key), ip)
+ return e
+}
+
+// IPPrefix adds IPv4 or IPv6 Prefix (address and mask) to the event
+func (e *Event) IPPrefix(key string, pfx net.IPNet) *Event {
+ if e == nil {
+ return e
+ }
+ e.buf = enc.AppendIPPrefix(enc.AppendKey(e.buf, key), pfx)
+ return e
+}
+
+// MACAddr adds MAC address to the event
+func (e *Event) MACAddr(key string, ha net.HardwareAddr) *Event {
+ if e == nil {
+ return e
+ }
+ e.buf = enc.AppendMACAddr(enc.AppendKey(e.buf, key), ha)
+ return e
+}
diff --git a/vendor/github.com/rs/zerolog/example.jsonl b/vendor/github.com/rs/zerolog/example.jsonl
new file mode 100644
index 0000000..d73193d
--- /dev/null
+++ b/vendor/github.com/rs/zerolog/example.jsonl
@@ -0,0 +1,7 @@
+{"time":"5:41PM","level":"info","message":"Starting listener","listen":":8080","pid":37556}
+{"time":"5:41PM","level":"debug","message":"Access","database":"myapp","host":"localhost:4962","pid":37556}
+{"time":"5:41PM","level":"info","message":"Access","method":"GET","path":"/users","pid":37556,"resp_time":23}
+{"time":"5:41PM","level":"info","message":"Access","method":"POST","path":"/posts","pid":37556,"resp_time":532}
+{"time":"5:41PM","level":"warn","message":"Slow request","method":"POST","path":"/posts","pid":37556,"resp_time":532}
+{"time":"5:41PM","level":"info","message":"Access","method":"GET","path":"/users","pid":37556,"resp_time":10}
+{"time":"5:41PM","level":"error","message":"Database connection lost","database":"myapp","pid":37556,"error":"connection reset by peer"}
diff --git a/vendor/github.com/rs/zerolog/fields.go b/vendor/github.com/rs/zerolog/fields.go
new file mode 100644
index 0000000..99f5271
--- /dev/null
+++ b/vendor/github.com/rs/zerolog/fields.go
@@ -0,0 +1,292 @@
+package zerolog
+
+import (
+ "encoding/json"
+ "net"
+ "sort"
+ "time"
+ "unsafe"
+)
+
+func isNilValue(i interface{}) bool {
+ return (*[2]uintptr)(unsafe.Pointer(&i))[1] == 0
+}
+
+func appendFields(dst []byte, fields interface{}, stack bool) []byte {
+ switch fields := fields.(type) {
+ case []interface{}:
+ if n := len(fields); n&0x1 == 1 { // odd number
+ fields = fields[:n-1]
+ }
+ dst = appendFieldList(dst, fields, stack)
+ case map[string]interface{}:
+ keys := make([]string, 0, len(fields))
+ for key := range fields {
+ keys = append(keys, key)
+ }
+ sort.Strings(keys)
+ kv := make([]interface{}, 2)
+ for _, key := range keys {
+ kv[0], kv[1] = key, fields[key]
+ dst = appendFieldList(dst, kv, stack)
+ }
+ }
+ return dst
+}
+
+func appendFieldList(dst []byte, kvList []interface{}, stack bool) []byte {
+ for i, n := 0, len(kvList); i < n; i += 2 {
+ key, val := kvList[i], kvList[i+1]
+ if key, ok := key.(string); ok {
+ dst = enc.AppendKey(dst, key)
+ } else {
+ continue
+ }
+ if val, ok := val.(LogObjectMarshaler); ok {
+ e := newEvent(nil, 0)
+ e.buf = e.buf[:0]
+ e.appendObject(val)
+ dst = append(dst, e.buf...)
+ putEvent(e)
+ continue
+ }
+ switch val := val.(type) {
+ case string:
+ dst = enc.AppendString(dst, val)
+ case []byte:
+ dst = enc.AppendBytes(dst, val)
+ case error:
+ switch m := ErrorMarshalFunc(val).(type) {
+ case LogObjectMarshaler:
+ e := newEvent(nil, 0)
+ e.buf = e.buf[:0]
+ e.appendObject(m)
+ dst = append(dst, e.buf...)
+ putEvent(e)
+ case error:
+ if m == nil || isNilValue(m) {
+ dst = enc.AppendNil(dst)
+ } else {
+ dst = enc.AppendString(dst, m.Error())
+ }
+ case string:
+ dst = enc.AppendString(dst, m)
+ default:
+ dst = enc.AppendInterface(dst, m)
+ }
+
+ if stack && ErrorStackMarshaler != nil {
+ dst = enc.AppendKey(dst, ErrorStackFieldName)
+ switch m := ErrorStackMarshaler(val).(type) {
+ case nil:
+ case error:
+ if m != nil && !isNilValue(m) {
+ dst = enc.AppendString(dst, m.Error())
+ }
+ case string:
+ dst = enc.AppendString(dst, m)
+ default:
+ dst = enc.AppendInterface(dst, m)
+ }
+ }
+ case []error:
+ dst = enc.AppendArrayStart(dst)
+ for i, err := range val {
+ switch m := ErrorMarshalFunc(err).(type) {
+ case LogObjectMarshaler:
+ e := newEvent(nil, 0)
+ e.buf = e.buf[:0]
+ e.appendObject(m)
+ dst = append(dst, e.buf...)
+ putEvent(e)
+ case error:
+ if m == nil || isNilValue(m) {
+ dst = enc.AppendNil(dst)
+ } else {
+ dst = enc.AppendString(dst, m.Error())
+ }
+ case string:
+ dst = enc.AppendString(dst, m)
+ default:
+ dst = enc.AppendInterface(dst, m)
+ }
+
+ if i < (len(val) - 1) {
+ enc.AppendArrayDelim(dst)
+ }
+ }
+ dst = enc.AppendArrayEnd(dst)
+ case bool:
+ dst = enc.AppendBool(dst, val)
+ case int:
+ dst = enc.AppendInt(dst, val)
+ case int8:
+ dst = enc.AppendInt8(dst, val)
+ case int16:
+ dst = enc.AppendInt16(dst, val)
+ case int32:
+ dst = enc.AppendInt32(dst, val)
+ case int64:
+ dst = enc.AppendInt64(dst, val)
+ case uint:
+ dst = enc.AppendUint(dst, val)
+ case uint8:
+ dst = enc.AppendUint8(dst, val)
+ case uint16:
+ dst = enc.AppendUint16(dst, val)
+ case uint32:
+ dst = enc.AppendUint32(dst, val)
+ case uint64:
+ dst = enc.AppendUint64(dst, val)
+ case float32:
+ dst = enc.AppendFloat32(dst, val, FloatingPointPrecision)
+ case float64:
+ dst = enc.AppendFloat64(dst, val, FloatingPointPrecision)
+ case time.Time:
+ dst = enc.AppendTime(dst, val, TimeFieldFormat)
+ case time.Duration:
+ dst = enc.AppendDuration(dst, val, DurationFieldUnit, DurationFieldInteger, FloatingPointPrecision)
+ case *string:
+ if val != nil {
+ dst = enc.AppendString(dst, *val)
+ } else {
+ dst = enc.AppendNil(dst)
+ }
+ case *bool:
+ if val != nil {
+ dst = enc.AppendBool(dst, *val)
+ } else {
+ dst = enc.AppendNil(dst)
+ }
+ case *int:
+ if val != nil {
+ dst = enc.AppendInt(dst, *val)
+ } else {
+ dst = enc.AppendNil(dst)
+ }
+ case *int8:
+ if val != nil {
+ dst = enc.AppendInt8(dst, *val)
+ } else {
+ dst = enc.AppendNil(dst)
+ }
+ case *int16:
+ if val != nil {
+ dst = enc.AppendInt16(dst, *val)
+ } else {
+ dst = enc.AppendNil(dst)
+ }
+ case *int32:
+ if val != nil {
+ dst = enc.AppendInt32(dst, *val)
+ } else {
+ dst = enc.AppendNil(dst)
+ }
+ case *int64:
+ if val != nil {
+ dst = enc.AppendInt64(dst, *val)
+ } else {
+ dst = enc.AppendNil(dst)
+ }
+ case *uint:
+ if val != nil {
+ dst = enc.AppendUint(dst, *val)
+ } else {
+ dst = enc.AppendNil(dst)
+ }
+ case *uint8:
+ if val != nil {
+ dst = enc.AppendUint8(dst, *val)
+ } else {
+ dst = enc.AppendNil(dst)
+ }
+ case *uint16:
+ if val != nil {
+ dst = enc.AppendUint16(dst, *val)
+ } else {
+ dst = enc.AppendNil(dst)
+ }
+ case *uint32:
+ if val != nil {
+ dst = enc.AppendUint32(dst, *val)
+ } else {
+ dst = enc.AppendNil(dst)
+ }
+ case *uint64:
+ if val != nil {
+ dst = enc.AppendUint64(dst, *val)
+ } else {
+ dst = enc.AppendNil(dst)
+ }
+ case *float32:
+ if val != nil {
+ dst = enc.AppendFloat32(dst, *val, FloatingPointPrecision)
+ } else {
+ dst = enc.AppendNil(dst)
+ }
+ case *float64:
+ if val != nil {
+ dst = enc.AppendFloat64(dst, *val, FloatingPointPrecision)
+ } else {
+ dst = enc.AppendNil(dst)
+ }
+ case *time.Time:
+ if val != nil {
+ dst = enc.AppendTime(dst, *val, TimeFieldFormat)
+ } else {
+ dst = enc.AppendNil(dst)
+ }
+ case *time.Duration:
+ if val != nil {
+ dst = enc.AppendDuration(dst, *val, DurationFieldUnit, DurationFieldInteger, FloatingPointPrecision)
+ } else {
+ dst = enc.AppendNil(dst)
+ }
+ case []string:
+ dst = enc.AppendStrings(dst, val)
+ case []bool:
+ dst = enc.AppendBools(dst, val)
+ case []int:
+ dst = enc.AppendInts(dst, val)
+ case []int8:
+ dst = enc.AppendInts8(dst, val)
+ case []int16:
+ dst = enc.AppendInts16(dst, val)
+ case []int32:
+ dst = enc.AppendInts32(dst, val)
+ case []int64:
+ dst = enc.AppendInts64(dst, val)
+ case []uint:
+ dst = enc.AppendUints(dst, val)
+ // case []uint8:
+ // dst = enc.AppendUints8(dst, val)
+ case []uint16:
+ dst = enc.AppendUints16(dst, val)
+ case []uint32:
+ dst = enc.AppendUints32(dst, val)
+ case []uint64:
+ dst = enc.AppendUints64(dst, val)
+ case []float32:
+ dst = enc.AppendFloats32(dst, val, FloatingPointPrecision)
+ case []float64:
+ dst = enc.AppendFloats64(dst, val, FloatingPointPrecision)
+ case []time.Time:
+ dst = enc.AppendTimes(dst, val, TimeFieldFormat)
+ case []time.Duration:
+ dst = enc.AppendDurations(dst, val, DurationFieldUnit, DurationFieldInteger, FloatingPointPrecision)
+ case nil:
+ dst = enc.AppendNil(dst)
+ case net.IP:
+ dst = enc.AppendIPAddr(dst, val)
+ case net.IPNet:
+ dst = enc.AppendIPPrefix(dst, val)
+ case net.HardwareAddr:
+ dst = enc.AppendMACAddr(dst, val)
+ case json.RawMessage:
+ dst = appendJSON(dst, val)
+ default:
+ dst = enc.AppendInterface(dst, val)
+ }
+ }
+ return dst
+}
diff --git a/vendor/github.com/rs/zerolog/globals.go b/vendor/github.com/rs/zerolog/globals.go
new file mode 100644
index 0000000..9a9be71
--- /dev/null
+++ b/vendor/github.com/rs/zerolog/globals.go
@@ -0,0 +1,190 @@
+package zerolog
+
+import (
+ "bytes"
+ "encoding/json"
+ "strconv"
+ "sync/atomic"
+ "time"
+)
+
+const (
+ // TimeFormatUnix defines a time format that makes time fields to be
+ // serialized as Unix timestamp integers.
+ TimeFormatUnix = ""
+
+ // TimeFormatUnixMs defines a time format that makes time fields to be
+ // serialized as Unix timestamp integers in milliseconds.
+ TimeFormatUnixMs = "UNIXMS"
+
+ // TimeFormatUnixMicro defines a time format that makes time fields to be
+ // serialized as Unix timestamp integers in microseconds.
+ TimeFormatUnixMicro = "UNIXMICRO"
+
+ // TimeFormatUnixNano defines a time format that makes time fields to be
+ // serialized as Unix timestamp integers in nanoseconds.
+ TimeFormatUnixNano = "UNIXNANO"
+)
+
+var (
+ // TimestampFieldName is the field name used for the timestamp field.
+ TimestampFieldName = "time"
+
+ // LevelFieldName is the field name used for the level field.
+ LevelFieldName = "level"
+
+ // LevelTraceValue is the value used for the trace level field.
+ LevelTraceValue = "trace"
+ // LevelDebugValue is the value used for the debug level field.
+ LevelDebugValue = "debug"
+ // LevelInfoValue is the value used for the info level field.
+ LevelInfoValue = "info"
+ // LevelWarnValue is the value used for the warn level field.
+ LevelWarnValue = "warn"
+ // LevelErrorValue is the value used for the error level field.
+ LevelErrorValue = "error"
+ // LevelFatalValue is the value used for the fatal level field.
+ LevelFatalValue = "fatal"
+ // LevelPanicValue is the value used for the panic level field.
+ LevelPanicValue = "panic"
+
+ // LevelFieldMarshalFunc allows customization of global level field marshaling.
+ LevelFieldMarshalFunc = func(l Level) string {
+ return l.String()
+ }
+
+ // MessageFieldName is the field name used for the message field.
+ MessageFieldName = "message"
+
+ // ErrorFieldName is the field name used for error fields.
+ ErrorFieldName = "error"
+
+ // CallerFieldName is the field name used for caller field.
+ CallerFieldName = "caller"
+
+ // CallerSkipFrameCount is the number of stack frames to skip to find the caller.
+ CallerSkipFrameCount = 2
+
+ // CallerMarshalFunc allows customization of global caller marshaling
+ CallerMarshalFunc = func(pc uintptr, file string, line int) string {
+ return file + ":" + strconv.Itoa(line)
+ }
+
+ // ErrorStackFieldName is the field name used for error stacks.
+ ErrorStackFieldName = "stack"
+
+ // ErrorStackMarshaler extract the stack from err if any.
+ ErrorStackMarshaler func(err error) interface{}
+
+ // ErrorMarshalFunc allows customization of global error marshaling
+ ErrorMarshalFunc = func(err error) interface{} {
+ return err
+ }
+
+ // InterfaceMarshalFunc allows customization of interface marshaling.
+ // Default: "encoding/json.Marshal" with disabled HTML escaping
+ InterfaceMarshalFunc = func(v interface{}) ([]byte, error) {
+ var buf bytes.Buffer
+ encoder := json.NewEncoder(&buf)
+ encoder.SetEscapeHTML(false)
+ err := encoder.Encode(v)
+ if err != nil {
+ return nil, err
+ }
+ b := buf.Bytes()
+ if len(b) > 0 {
+ // Remove trailing \n which is added by Encode.
+ return b[:len(b)-1], nil
+ }
+ return b, nil
+ }
+
+ // TimeFieldFormat defines the time format of the Time field type. If set to
+ // TimeFormatUnix, TimeFormatUnixMs, TimeFormatUnixMicro or TimeFormatUnixNano, the time is formatted as a UNIX
+ // timestamp as integer.
+ TimeFieldFormat = time.RFC3339
+
+ // TimestampFunc defines the function called to generate a timestamp.
+ TimestampFunc = time.Now
+
+ // DurationFieldUnit defines the unit for time.Duration type fields added
+ // using the Dur method.
+ DurationFieldUnit = time.Millisecond
+
+ // DurationFieldInteger renders Dur fields as integer instead of float if
+ // set to true.
+ DurationFieldInteger = false
+
+ // ErrorHandler is called whenever zerolog fails to write an event on its
+ // output. If not set, an error is printed on the stderr. This handler must
+ // be thread safe and non-blocking.
+ ErrorHandler func(err error)
+
+ // DefaultContextLogger is returned from Ctx() if there is no logger associated
+ // with the context.
+ DefaultContextLogger *Logger
+
+ // LevelColors are used by ConsoleWriter's consoleDefaultFormatLevel to color
+ // log levels.
+ LevelColors = map[Level]int{
+ TraceLevel: colorBlue,
+ DebugLevel: 0,
+ InfoLevel: colorGreen,
+ WarnLevel: colorYellow,
+ ErrorLevel: colorRed,
+ FatalLevel: colorRed,
+ PanicLevel: colorRed,
+ }
+
+ // FormattedLevels are used by ConsoleWriter's consoleDefaultFormatLevel
+ // for a short level name.
+ FormattedLevels = map[Level]string{
+ TraceLevel: "TRC",
+ DebugLevel: "DBG",
+ InfoLevel: "INF",
+ WarnLevel: "WRN",
+ ErrorLevel: "ERR",
+ FatalLevel: "FTL",
+ PanicLevel: "PNC",
+ }
+
+ // TriggerLevelWriterBufferReuseLimit is a limit in bytes that a buffer is dropped
+ // from the TriggerLevelWriter buffer pool if the buffer grows above the limit.
+ TriggerLevelWriterBufferReuseLimit = 64 * 1024
+
+ // FloatingPointPrecision, if set to a value other than -1, controls the number
+ // of digits when formatting float numbers in JSON. See strconv.FormatFloat for
+ // more details.
+ FloatingPointPrecision = -1
+)
+
+var (
+ gLevel = new(int32)
+ disableSampling = new(int32)
+)
+
+// SetGlobalLevel sets the global override for log level. If this
+// values is raised, all Loggers will use at least this value.
+//
+// To globally disable logs, set GlobalLevel to Disabled.
+func SetGlobalLevel(l Level) {
+ atomic.StoreInt32(gLevel, int32(l))
+}
+
+// GlobalLevel returns the current global log level
+func GlobalLevel() Level {
+ return Level(atomic.LoadInt32(gLevel))
+}
+
+// DisableSampling will disable sampling in all Loggers if true.
+func DisableSampling(v bool) {
+ var i int32
+ if v {
+ i = 1
+ }
+ atomic.StoreInt32(disableSampling, i)
+}
+
+func samplingDisabled() bool {
+ return atomic.LoadInt32(disableSampling) == 1
+}
diff --git a/vendor/github.com/rs/zerolog/go112.go b/vendor/github.com/rs/zerolog/go112.go
new file mode 100644
index 0000000..e7b5a1b
--- /dev/null
+++ b/vendor/github.com/rs/zerolog/go112.go
@@ -0,0 +1,7 @@
+// +build go1.12
+
+package zerolog
+
+// Since go 1.12, some auto generated init functions are hidden from
+// runtime.Caller.
+const contextCallerSkipFrameCount = 2
diff --git a/vendor/github.com/rs/zerolog/hook.go b/vendor/github.com/rs/zerolog/hook.go
new file mode 100644
index 0000000..ec6effc
--- /dev/null
+++ b/vendor/github.com/rs/zerolog/hook.go
@@ -0,0 +1,64 @@
+package zerolog
+
+// Hook defines an interface to a log hook.
+type Hook interface {
+ // Run runs the hook with the event.
+ Run(e *Event, level Level, message string)
+}
+
+// HookFunc is an adaptor to allow the use of an ordinary function
+// as a Hook.
+type HookFunc func(e *Event, level Level, message string)
+
+// Run implements the Hook interface.
+func (h HookFunc) Run(e *Event, level Level, message string) {
+ h(e, level, message)
+}
+
+// LevelHook applies a different hook for each level.
+type LevelHook struct {
+ NoLevelHook, TraceHook, DebugHook, InfoHook, WarnHook, ErrorHook, FatalHook, PanicHook Hook
+}
+
+// Run implements the Hook interface.
+func (h LevelHook) Run(e *Event, level Level, message string) {
+ switch level {
+ case TraceLevel:
+ if h.TraceHook != nil {
+ h.TraceHook.Run(e, level, message)
+ }
+ case DebugLevel:
+ if h.DebugHook != nil {
+ h.DebugHook.Run(e, level, message)
+ }
+ case InfoLevel:
+ if h.InfoHook != nil {
+ h.InfoHook.Run(e, level, message)
+ }
+ case WarnLevel:
+ if h.WarnHook != nil {
+ h.WarnHook.Run(e, level, message)
+ }
+ case ErrorLevel:
+ if h.ErrorHook != nil {
+ h.ErrorHook.Run(e, level, message)
+ }
+ case FatalLevel:
+ if h.FatalHook != nil {
+ h.FatalHook.Run(e, level, message)
+ }
+ case PanicLevel:
+ if h.PanicHook != nil {
+ h.PanicHook.Run(e, level, message)
+ }
+ case NoLevel:
+ if h.NoLevelHook != nil {
+ h.NoLevelHook.Run(e, level, message)
+ }
+ }
+}
+
+// NewLevelHook returns a new LevelHook.
+func NewLevelHook() LevelHook {
+ return LevelHook{}
+}
diff --git a/vendor/github.com/rs/zerolog/internal/cbor/README.md b/vendor/github.com/rs/zerolog/internal/cbor/README.md
new file mode 100644
index 0000000..92c2e8c
--- /dev/null
+++ b/vendor/github.com/rs/zerolog/internal/cbor/README.md
@@ -0,0 +1,56 @@
+## Reference:
+ CBOR Encoding is described in [RFC7049](https://tools.ietf.org/html/rfc7049)
+
+## Comparison of JSON vs CBOR
+
+Two main areas of reduction are:
+
+1. CPU usage to write a log msg
+2. Size (in bytes) of log messages.
+
+
+CPU Usage savings are below:
+```
+name JSON time/op CBOR time/op delta
+Info-32 15.3ns ± 1% 11.7ns ± 3% -23.78% (p=0.000 n=9+10)
+ContextFields-32 16.2ns ± 2% 12.3ns ± 3% -23.97% (p=0.000 n=9+9)
+ContextAppend-32 6.70ns ± 0% 6.20ns ± 0% -7.44% (p=0.000 n=9+9)
+LogFields-32 66.4ns ± 0% 24.6ns ± 2% -62.89% (p=0.000 n=10+9)
+LogArrayObject-32 911ns ±11% 768ns ± 6% -15.64% (p=0.000 n=10+10)
+LogFieldType/Floats-32 70.3ns ± 2% 29.5ns ± 1% -57.98% (p=0.000 n=10+10)
+LogFieldType/Err-32 14.0ns ± 3% 12.1ns ± 8% -13.20% (p=0.000 n=8+10)
+LogFieldType/Dur-32 17.2ns ± 2% 13.1ns ± 1% -24.27% (p=0.000 n=10+9)
+LogFieldType/Object-32 54.3ns ±11% 52.3ns ± 7% ~ (p=0.239 n=10+10)
+LogFieldType/Ints-32 20.3ns ± 2% 15.1ns ± 2% -25.50% (p=0.000 n=9+10)
+LogFieldType/Interfaces-32 642ns ±11% 621ns ± 9% ~ (p=0.118 n=10+10)
+LogFieldType/Interface(Objects)-32 635ns ±13% 632ns ± 9% ~ (p=0.592 n=10+10)
+LogFieldType/Times-32 294ns ± 0% 27ns ± 1% -90.71% (p=0.000 n=10+9)
+LogFieldType/Durs-32 121ns ± 0% 33ns ± 2% -72.44% (p=0.000 n=9+9)
+LogFieldType/Interface(Object)-32 56.6ns ± 8% 52.3ns ± 8% -7.54% (p=0.007 n=10+10)
+LogFieldType/Errs-32 17.8ns ± 3% 16.1ns ± 2% -9.71% (p=0.000 n=10+9)
+LogFieldType/Time-32 40.5ns ± 1% 12.7ns ± 6% -68.66% (p=0.000 n=8+9)
+LogFieldType/Bool-32 12.0ns ± 5% 10.2ns ± 2% -15.18% (p=0.000 n=10+8)
+LogFieldType/Bools-32 17.2ns ± 2% 12.6ns ± 4% -26.63% (p=0.000 n=10+10)
+LogFieldType/Int-32 12.3ns ± 2% 11.2ns ± 4% -9.27% (p=0.000 n=9+10)
+LogFieldType/Float-32 16.7ns ± 1% 12.6ns ± 2% -24.42% (p=0.000 n=7+9)
+LogFieldType/Str-32 12.7ns ± 7% 11.3ns ± 7% -10.88% (p=0.000 n=10+9)
+LogFieldType/Strs-32 20.3ns ± 3% 18.2ns ± 3% -10.25% (p=0.000 n=9+10)
+LogFieldType/Interface-32 183ns ±12% 175ns ± 9% ~ (p=0.078 n=10+10)
+```
+
+Log message size savings is greatly dependent on the number and type of fields in the log message.
+Assuming this log message (with an Integer, timestamp and string, in addition to level).
+
+`{"level":"error","Fault":41650,"time":"2018-04-01T15:18:19-07:00","message":"Some Message"}`
+
+Two measurements were done for the log file sizes - one without any compression, second
+using [compress/zlib](https://golang.org/pkg/compress/zlib/).
+
+Results for 10,000 log messages:
+
+| Log Format | Plain File Size (in KB) | Compressed File Size (in KB) |
+| :--- | :---: | :---: |
+| JSON | 920 | 28 |
+| CBOR | 550 | 28 |
+
+The example used to calculate the above data is available in [Examples](examples).
diff --git a/vendor/github.com/rs/zerolog/internal/cbor/base.go b/vendor/github.com/rs/zerolog/internal/cbor/base.go
new file mode 100644
index 0000000..51fe86c
--- /dev/null
+++ b/vendor/github.com/rs/zerolog/internal/cbor/base.go
@@ -0,0 +1,19 @@
+package cbor
+
+// JSONMarshalFunc is used to marshal interface to JSON encoded byte slice.
+// Making it package level instead of embedded in Encoder brings
+// some extra efforts at importing, but avoids value copy when the functions
+// of Encoder being invoked.
+// DO REMEMBER to set this variable at importing, or
+// you might get a nil pointer dereference panic at runtime.
+var JSONMarshalFunc func(v interface{}) ([]byte, error)
+
+type Encoder struct{}
+
+// AppendKey adds a key (string) to the binary encoded log message
+func (e Encoder) AppendKey(dst []byte, key string) []byte {
+ if len(dst) < 1 {
+ dst = e.AppendBeginMarker(dst)
+ }
+ return e.AppendString(dst, key)
+}
diff --git a/vendor/github.com/rs/zerolog/internal/cbor/cbor.go b/vendor/github.com/rs/zerolog/internal/cbor/cbor.go
new file mode 100644
index 0000000..1bf1443
--- /dev/null
+++ b/vendor/github.com/rs/zerolog/internal/cbor/cbor.go
@@ -0,0 +1,102 @@
+// Package cbor provides primitives for storing different data
+// in the CBOR (binary) format. CBOR is defined in RFC7049.
+package cbor
+
+import "time"
+
+const (
+ majorOffset = 5
+ additionalMax = 23
+
+ // Non Values.
+ additionalTypeBoolFalse byte = 20
+ additionalTypeBoolTrue byte = 21
+ additionalTypeNull byte = 22
+
+ // Integer (+ve and -ve) Sub-types.
+ additionalTypeIntUint8 byte = 24
+ additionalTypeIntUint16 byte = 25
+ additionalTypeIntUint32 byte = 26
+ additionalTypeIntUint64 byte = 27
+
+ // Float Sub-types.
+ additionalTypeFloat16 byte = 25
+ additionalTypeFloat32 byte = 26
+ additionalTypeFloat64 byte = 27
+ additionalTypeBreak byte = 31
+
+ // Tag Sub-types.
+ additionalTypeTimestamp byte = 01
+ additionalTypeEmbeddedCBOR byte = 63
+
+ // Extended Tags - from https://www.iana.org/assignments/cbor-tags/cbor-tags.xhtml
+ additionalTypeTagNetworkAddr uint16 = 260
+ additionalTypeTagNetworkPrefix uint16 = 261
+ additionalTypeEmbeddedJSON uint16 = 262
+ additionalTypeTagHexString uint16 = 263
+
+ // Unspecified number of elements.
+ additionalTypeInfiniteCount byte = 31
+)
+const (
+ majorTypeUnsignedInt byte = iota << majorOffset // Major type 0
+ majorTypeNegativeInt // Major type 1
+ majorTypeByteString // Major type 2
+ majorTypeUtf8String // Major type 3
+ majorTypeArray // Major type 4
+ majorTypeMap // Major type 5
+ majorTypeTags // Major type 6
+ majorTypeSimpleAndFloat // Major type 7
+)
+
+const (
+ maskOutAdditionalType byte = (7 << majorOffset)
+ maskOutMajorType byte = 31
+)
+
+const (
+ float32Nan = "\xfa\x7f\xc0\x00\x00"
+ float32PosInfinity = "\xfa\x7f\x80\x00\x00"
+ float32NegInfinity = "\xfa\xff\x80\x00\x00"
+ float64Nan = "\xfb\x7f\xf8\x00\x00\x00\x00\x00\x00"
+ float64PosInfinity = "\xfb\x7f\xf0\x00\x00\x00\x00\x00\x00"
+ float64NegInfinity = "\xfb\xff\xf0\x00\x00\x00\x00\x00\x00"
+)
+
+// IntegerTimeFieldFormat indicates the format of timestamp decoded
+// from an integer (time in seconds).
+var IntegerTimeFieldFormat = time.RFC3339
+
+// NanoTimeFieldFormat indicates the format of timestamp decoded
+// from a float value (time in seconds and nanoseconds).
+var NanoTimeFieldFormat = time.RFC3339Nano
+
+func appendCborTypePrefix(dst []byte, major byte, number uint64) []byte {
+ byteCount := 8
+ var minor byte
+ switch {
+ case number < 256:
+ byteCount = 1
+ minor = additionalTypeIntUint8
+
+ case number < 65536:
+ byteCount = 2
+ minor = additionalTypeIntUint16
+
+ case number < 4294967296:
+ byteCount = 4
+ minor = additionalTypeIntUint32
+
+ default:
+ byteCount = 8
+ minor = additionalTypeIntUint64
+
+ }
+
+ dst = append(dst, major|minor)
+ byteCount--
+ for ; byteCount >= 0; byteCount-- {
+ dst = append(dst, byte(number>>(uint(byteCount)*8)))
+ }
+ return dst
+}
diff --git a/vendor/github.com/rs/zerolog/internal/cbor/decode_stream.go b/vendor/github.com/rs/zerolog/internal/cbor/decode_stream.go
new file mode 100644
index 0000000..5633e66
--- /dev/null
+++ b/vendor/github.com/rs/zerolog/internal/cbor/decode_stream.go
@@ -0,0 +1,654 @@
+package cbor
+
+// This file contains code to decode a stream of CBOR Data into JSON.
+
+import (
+ "bufio"
+ "bytes"
+ "encoding/base64"
+ "fmt"
+ "io"
+ "math"
+ "net"
+ "runtime"
+ "strconv"
+ "strings"
+ "time"
+ "unicode/utf8"
+)
+
+var decodeTimeZone *time.Location
+
+const hexTable = "0123456789abcdef"
+
+const isFloat32 = 4
+const isFloat64 = 8
+
+func readNBytes(src *bufio.Reader, n int) []byte {
+ ret := make([]byte, n)
+ for i := 0; i < n; i++ {
+ ch, e := src.ReadByte()
+ if e != nil {
+ panic(fmt.Errorf("Tried to Read %d Bytes.. But hit end of file", n))
+ }
+ ret[i] = ch
+ }
+ return ret
+}
+
+func readByte(src *bufio.Reader) byte {
+ b, e := src.ReadByte()
+ if e != nil {
+ panic(fmt.Errorf("Tried to Read 1 Byte.. But hit end of file"))
+ }
+ return b
+}
+
+func decodeIntAdditionalType(src *bufio.Reader, minor byte) int64 {
+ val := int64(0)
+ if minor <= 23 {
+ val = int64(minor)
+ } else {
+ bytesToRead := 0
+ switch minor {
+ case additionalTypeIntUint8:
+ bytesToRead = 1
+ case additionalTypeIntUint16:
+ bytesToRead = 2
+ case additionalTypeIntUint32:
+ bytesToRead = 4
+ case additionalTypeIntUint64:
+ bytesToRead = 8
+ default:
+ panic(fmt.Errorf("Invalid Additional Type: %d in decodeInteger (expected <28)", minor))
+ }
+ pb := readNBytes(src, bytesToRead)
+ for i := 0; i < bytesToRead; i++ {
+ val = val * 256
+ val += int64(pb[i])
+ }
+ }
+ return val
+}
+
+func decodeInteger(src *bufio.Reader) int64 {
+ pb := readByte(src)
+ major := pb & maskOutAdditionalType
+ minor := pb & maskOutMajorType
+ if major != majorTypeUnsignedInt && major != majorTypeNegativeInt {
+ panic(fmt.Errorf("Major type is: %d in decodeInteger!! (expected 0 or 1)", major))
+ }
+ val := decodeIntAdditionalType(src, minor)
+ if major == 0 {
+ return val
+ }
+ return (-1 - val)
+}
+
+func decodeFloat(src *bufio.Reader) (float64, int) {
+ pb := readByte(src)
+ major := pb & maskOutAdditionalType
+ minor := pb & maskOutMajorType
+ if major != majorTypeSimpleAndFloat {
+ panic(fmt.Errorf("Incorrect Major type is: %d in decodeFloat", major))
+ }
+
+ switch minor {
+ case additionalTypeFloat16:
+ panic(fmt.Errorf("float16 is not supported in decodeFloat"))
+
+ case additionalTypeFloat32:
+ pb := readNBytes(src, 4)
+ switch string(pb) {
+ case float32Nan:
+ return math.NaN(), isFloat32
+ case float32PosInfinity:
+ return math.Inf(0), isFloat32
+ case float32NegInfinity:
+ return math.Inf(-1), isFloat32
+ }
+ n := uint32(0)
+ for i := 0; i < 4; i++ {
+ n = n * 256
+ n += uint32(pb[i])
+ }
+ val := math.Float32frombits(n)
+ return float64(val), isFloat32
+ case additionalTypeFloat64:
+ pb := readNBytes(src, 8)
+ switch string(pb) {
+ case float64Nan:
+ return math.NaN(), isFloat64
+ case float64PosInfinity:
+ return math.Inf(0), isFloat64
+ case float64NegInfinity:
+ return math.Inf(-1), isFloat64
+ }
+ n := uint64(0)
+ for i := 0; i < 8; i++ {
+ n = n * 256
+ n += uint64(pb[i])
+ }
+ val := math.Float64frombits(n)
+ return val, isFloat64
+ }
+ panic(fmt.Errorf("Invalid Additional Type: %d in decodeFloat", minor))
+}
+
+func decodeStringComplex(dst []byte, s string, pos uint) []byte {
+ i := int(pos)
+ start := 0
+
+ for i < len(s) {
+ b := s[i]
+ if b >= utf8.RuneSelf {
+ r, size := utf8.DecodeRuneInString(s[i:])
+ if r == utf8.RuneError && size == 1 {
+ // In case of error, first append previous simple characters to
+ // the byte slice if any and append a replacement character code
+ // in place of the invalid sequence.
+ if start < i {
+ dst = append(dst, s[start:i]...)
+ }
+ dst = append(dst, `\ufffd`...)
+ i += size
+ start = i
+ continue
+ }
+ i += size
+ continue
+ }
+ if b >= 0x20 && b <= 0x7e && b != '\\' && b != '"' {
+ i++
+ continue
+ }
+ // We encountered a character that needs to be encoded.
+ // Let's append the previous simple characters to the byte slice
+ // and switch our operation to read and encode the remainder
+ // characters byte-by-byte.
+ if start < i {
+ dst = append(dst, s[start:i]...)
+ }
+ switch b {
+ case '"', '\\':
+ dst = append(dst, '\\', b)
+ case '\b':
+ dst = append(dst, '\\', 'b')
+ case '\f':
+ dst = append(dst, '\\', 'f')
+ case '\n':
+ dst = append(dst, '\\', 'n')
+ case '\r':
+ dst = append(dst, '\\', 'r')
+ case '\t':
+ dst = append(dst, '\\', 't')
+ default:
+ dst = append(dst, '\\', 'u', '0', '0', hexTable[b>>4], hexTable[b&0xF])
+ }
+ i++
+ start = i
+ }
+ if start < len(s) {
+ dst = append(dst, s[start:]...)
+ }
+ return dst
+}
+
+func decodeString(src *bufio.Reader, noQuotes bool) []byte {
+ pb := readByte(src)
+ major := pb & maskOutAdditionalType
+ minor := pb & maskOutMajorType
+ if major != majorTypeByteString {
+ panic(fmt.Errorf("Major type is: %d in decodeString", major))
+ }
+ result := []byte{}
+ if !noQuotes {
+ result = append(result, '"')
+ }
+ length := decodeIntAdditionalType(src, minor)
+ len := int(length)
+ pbs := readNBytes(src, len)
+ result = append(result, pbs...)
+ if noQuotes {
+ return result
+ }
+ return append(result, '"')
+}
+func decodeStringToDataUrl(src *bufio.Reader, mimeType string) []byte {
+ pb := readByte(src)
+ major := pb & maskOutAdditionalType
+ minor := pb & maskOutMajorType
+ if major != majorTypeByteString {
+ panic(fmt.Errorf("Major type is: %d in decodeString", major))
+ }
+ length := decodeIntAdditionalType(src, minor)
+ l := int(length)
+ enc := base64.StdEncoding
+ lEnc := enc.EncodedLen(l)
+ result := make([]byte, len("\"data:;base64,\"")+len(mimeType)+lEnc)
+ dest := result
+ u := copy(dest, "\"data:")
+ dest = dest[u:]
+ u = copy(dest, mimeType)
+ dest = dest[u:]
+ u = copy(dest, ";base64,")
+ dest = dest[u:]
+ pbs := readNBytes(src, l)
+ enc.Encode(dest, pbs)
+ dest = dest[lEnc:]
+ dest[0] = '"'
+ return result
+}
+
+func decodeUTF8String(src *bufio.Reader) []byte {
+ pb := readByte(src)
+ major := pb & maskOutAdditionalType
+ minor := pb & maskOutMajorType
+ if major != majorTypeUtf8String {
+ panic(fmt.Errorf("Major type is: %d in decodeUTF8String", major))
+ }
+ result := []byte{'"'}
+ length := decodeIntAdditionalType(src, minor)
+ len := int(length)
+ pbs := readNBytes(src, len)
+
+ for i := 0; i < len; i++ {
+ // Check if the character needs encoding. Control characters, slashes,
+ // and the double quote need json encoding. Bytes above the ascii
+ // boundary needs utf8 encoding.
+ if pbs[i] < 0x20 || pbs[i] > 0x7e || pbs[i] == '\\' || pbs[i] == '"' {
+ // We encountered a character that needs to be encoded. Switch
+ // to complex version of the algorithm.
+ dst := []byte{'"'}
+ dst = decodeStringComplex(dst, string(pbs), uint(i))
+ return append(dst, '"')
+ }
+ }
+ // The string has no need for encoding and therefore is directly
+ // appended to the byte slice.
+ result = append(result, pbs...)
+ return append(result, '"')
+}
+
+func array2Json(src *bufio.Reader, dst io.Writer) {
+ dst.Write([]byte{'['})
+ pb := readByte(src)
+ major := pb & maskOutAdditionalType
+ minor := pb & maskOutMajorType
+ if major != majorTypeArray {
+ panic(fmt.Errorf("Major type is: %d in array2Json", major))
+ }
+ len := 0
+ unSpecifiedCount := false
+ if minor == additionalTypeInfiniteCount {
+ unSpecifiedCount = true
+ } else {
+ length := decodeIntAdditionalType(src, minor)
+ len = int(length)
+ }
+ for i := 0; unSpecifiedCount || i < len; i++ {
+ if unSpecifiedCount {
+ pb, e := src.Peek(1)
+ if e != nil {
+ panic(e)
+ }
+ if pb[0] == majorTypeSimpleAndFloat|additionalTypeBreak {
+ readByte(src)
+ break
+ }
+ }
+ cbor2JsonOneObject(src, dst)
+ if unSpecifiedCount {
+ pb, e := src.Peek(1)
+ if e != nil {
+ panic(e)
+ }
+ if pb[0] == majorTypeSimpleAndFloat|additionalTypeBreak {
+ readByte(src)
+ break
+ }
+ dst.Write([]byte{','})
+ } else if i+1 < len {
+ dst.Write([]byte{','})
+ }
+ }
+ dst.Write([]byte{']'})
+}
+
+func map2Json(src *bufio.Reader, dst io.Writer) {
+ pb := readByte(src)
+ major := pb & maskOutAdditionalType
+ minor := pb & maskOutMajorType
+ if major != majorTypeMap {
+ panic(fmt.Errorf("Major type is: %d in map2Json", major))
+ }
+ len := 0
+ unSpecifiedCount := false
+ if minor == additionalTypeInfiniteCount {
+ unSpecifiedCount = true
+ } else {
+ length := decodeIntAdditionalType(src, minor)
+ len = int(length)
+ }
+ dst.Write([]byte{'{'})
+ for i := 0; unSpecifiedCount || i < len; i++ {
+ if unSpecifiedCount {
+ pb, e := src.Peek(1)
+ if e != nil {
+ panic(e)
+ }
+ if pb[0] == majorTypeSimpleAndFloat|additionalTypeBreak {
+ readByte(src)
+ break
+ }
+ }
+ cbor2JsonOneObject(src, dst)
+ if i%2 == 0 {
+ // Even position values are keys.
+ dst.Write([]byte{':'})
+ } else {
+ if unSpecifiedCount {
+ pb, e := src.Peek(1)
+ if e != nil {
+ panic(e)
+ }
+ if pb[0] == majorTypeSimpleAndFloat|additionalTypeBreak {
+ readByte(src)
+ break
+ }
+ dst.Write([]byte{','})
+ } else if i+1 < len {
+ dst.Write([]byte{','})
+ }
+ }
+ }
+ dst.Write([]byte{'}'})
+}
+
+func decodeTagData(src *bufio.Reader) []byte {
+ pb := readByte(src)
+ major := pb & maskOutAdditionalType
+ minor := pb & maskOutMajorType
+ if major != majorTypeTags {
+ panic(fmt.Errorf("Major type is: %d in decodeTagData", major))
+ }
+ switch minor {
+ case additionalTypeTimestamp:
+ return decodeTimeStamp(src)
+ case additionalTypeIntUint8:
+ val := decodeIntAdditionalType(src, minor)
+ switch byte(val) {
+ case additionalTypeEmbeddedCBOR:
+ pb := readByte(src)
+ dataMajor := pb & maskOutAdditionalType
+ if dataMajor != majorTypeByteString {
+ panic(fmt.Errorf("Unsupported embedded Type: %d in decodeEmbeddedCBOR", dataMajor))
+ }
+ src.UnreadByte()
+ return decodeStringToDataUrl(src, "application/cbor")
+ default:
+ panic(fmt.Errorf("Unsupported Additional Tag Type: %d in decodeTagData", val))
+ }
+
+ // Tag value is larger than 256 (so uint16).
+ case additionalTypeIntUint16:
+ val := decodeIntAdditionalType(src, minor)
+
+ switch uint16(val) {
+ case additionalTypeEmbeddedJSON:
+ pb := readByte(src)
+ dataMajor := pb & maskOutAdditionalType
+ if dataMajor != majorTypeByteString {
+ panic(fmt.Errorf("Unsupported embedded Type: %d in decodeEmbeddedJSON", dataMajor))
+ }
+ src.UnreadByte()
+ return decodeString(src, true)
+
+ case additionalTypeTagNetworkAddr:
+ octets := decodeString(src, true)
+ ss := []byte{'"'}
+ switch len(octets) {
+ case 6: // MAC address.
+ ha := net.HardwareAddr(octets)
+ ss = append(append(ss, ha.String()...), '"')
+ case 4: // IPv4 address.
+ fallthrough
+ case 16: // IPv6 address.
+ ip := net.IP(octets)
+ ss = append(append(ss, ip.String()...), '"')
+ default:
+ panic(fmt.Errorf("Unexpected Network Address length: %d (expected 4,6,16)", len(octets)))
+ }
+ return ss
+
+ case additionalTypeTagNetworkPrefix:
+ pb := readByte(src)
+ if pb != majorTypeMap|0x1 {
+ panic(fmt.Errorf("IP Prefix is NOT of MAP of 1 elements as expected"))
+ }
+ octets := decodeString(src, true)
+ val := decodeInteger(src)
+ ip := net.IP(octets)
+ var mask net.IPMask
+ pfxLen := int(val)
+ if len(octets) == 4 {
+ mask = net.CIDRMask(pfxLen, 32)
+ } else {
+ mask = net.CIDRMask(pfxLen, 128)
+ }
+ ipPfx := net.IPNet{IP: ip, Mask: mask}
+ ss := []byte{'"'}
+ ss = append(append(ss, ipPfx.String()...), '"')
+ return ss
+
+ case additionalTypeTagHexString:
+ octets := decodeString(src, true)
+ ss := []byte{'"'}
+ for _, v := range octets {
+ ss = append(ss, hexTable[v>>4], hexTable[v&0x0f])
+ }
+ return append(ss, '"')
+
+ default:
+ panic(fmt.Errorf("Unsupported Additional Tag Type: %d in decodeTagData", val))
+ }
+ }
+ panic(fmt.Errorf("Unsupported Additional Type: %d in decodeTagData", minor))
+}
+
+func decodeTimeStamp(src *bufio.Reader) []byte {
+ pb := readByte(src)
+ src.UnreadByte()
+ tsMajor := pb & maskOutAdditionalType
+ if tsMajor == majorTypeUnsignedInt || tsMajor == majorTypeNegativeInt {
+ n := decodeInteger(src)
+ t := time.Unix(n, 0)
+ if decodeTimeZone != nil {
+ t = t.In(decodeTimeZone)
+ } else {
+ t = t.In(time.UTC)
+ }
+ tsb := []byte{}
+ tsb = append(tsb, '"')
+ tsb = t.AppendFormat(tsb, IntegerTimeFieldFormat)
+ tsb = append(tsb, '"')
+ return tsb
+ } else if tsMajor == majorTypeSimpleAndFloat {
+ n, _ := decodeFloat(src)
+ secs := int64(n)
+ n -= float64(secs)
+ n *= float64(1e9)
+ t := time.Unix(secs, int64(n))
+ if decodeTimeZone != nil {
+ t = t.In(decodeTimeZone)
+ } else {
+ t = t.In(time.UTC)
+ }
+ tsb := []byte{}
+ tsb = append(tsb, '"')
+ tsb = t.AppendFormat(tsb, NanoTimeFieldFormat)
+ tsb = append(tsb, '"')
+ return tsb
+ }
+ panic(fmt.Errorf("TS format is neigther int nor float: %d", tsMajor))
+}
+
+func decodeSimpleFloat(src *bufio.Reader) []byte {
+ pb := readByte(src)
+ major := pb & maskOutAdditionalType
+ minor := pb & maskOutMajorType
+ if major != majorTypeSimpleAndFloat {
+ panic(fmt.Errorf("Major type is: %d in decodeSimpleFloat", major))
+ }
+ switch minor {
+ case additionalTypeBoolTrue:
+ return []byte("true")
+ case additionalTypeBoolFalse:
+ return []byte("false")
+ case additionalTypeNull:
+ return []byte("null")
+ case additionalTypeFloat16:
+ fallthrough
+ case additionalTypeFloat32:
+ fallthrough
+ case additionalTypeFloat64:
+ src.UnreadByte()
+ v, bc := decodeFloat(src)
+ ba := []byte{}
+ switch {
+ case math.IsNaN(v):
+ return []byte("\"NaN\"")
+ case math.IsInf(v, 1):
+ return []byte("\"+Inf\"")
+ case math.IsInf(v, -1):
+ return []byte("\"-Inf\"")
+ }
+ if bc == isFloat32 {
+ ba = strconv.AppendFloat(ba, v, 'f', -1, 32)
+ } else if bc == isFloat64 {
+ ba = strconv.AppendFloat(ba, v, 'f', -1, 64)
+ } else {
+ panic(fmt.Errorf("Invalid Float precision from decodeFloat: %d", bc))
+ }
+ return ba
+ default:
+ panic(fmt.Errorf("Invalid Additional Type: %d in decodeSimpleFloat", minor))
+ }
+}
+
+func cbor2JsonOneObject(src *bufio.Reader, dst io.Writer) {
+ pb, e := src.Peek(1)
+ if e != nil {
+ panic(e)
+ }
+ major := (pb[0] & maskOutAdditionalType)
+
+ switch major {
+ case majorTypeUnsignedInt:
+ fallthrough
+ case majorTypeNegativeInt:
+ n := decodeInteger(src)
+ dst.Write([]byte(strconv.Itoa(int(n))))
+
+ case majorTypeByteString:
+ s := decodeString(src, false)
+ dst.Write(s)
+
+ case majorTypeUtf8String:
+ s := decodeUTF8String(src)
+ dst.Write(s)
+
+ case majorTypeArray:
+ array2Json(src, dst)
+
+ case majorTypeMap:
+ map2Json(src, dst)
+
+ case majorTypeTags:
+ s := decodeTagData(src)
+ dst.Write(s)
+
+ case majorTypeSimpleAndFloat:
+ s := decodeSimpleFloat(src)
+ dst.Write(s)
+ }
+}
+
+func moreBytesToRead(src *bufio.Reader) bool {
+ _, e := src.ReadByte()
+ if e == nil {
+ src.UnreadByte()
+ return true
+ }
+ return false
+}
+
+// Cbor2JsonManyObjects decodes all the CBOR Objects read from src
+// reader. It keeps on decoding until reader returns EOF (error when reading).
+// Decoded string is written to the dst. At the end of every CBOR Object
+// newline is written to the output stream.
+//
+// Returns error (if any) that was encountered during decode.
+// The child functions will generate a panic when error is encountered and
+// this function will recover non-runtime Errors and return the reason as error.
+func Cbor2JsonManyObjects(src io.Reader, dst io.Writer) (err error) {
+ defer func() {
+ if r := recover(); r != nil {
+ if _, ok := r.(runtime.Error); ok {
+ panic(r)
+ }
+ err = r.(error)
+ }
+ }()
+ bufRdr := bufio.NewReader(src)
+ for moreBytesToRead(bufRdr) {
+ cbor2JsonOneObject(bufRdr, dst)
+ dst.Write([]byte("\n"))
+ }
+ return nil
+}
+
+// Detect if the bytes to be printed is Binary or not.
+func binaryFmt(p []byte) bool {
+ if len(p) > 0 && p[0] > 0x7F {
+ return true
+ }
+ return false
+}
+
+func getReader(str string) *bufio.Reader {
+ return bufio.NewReader(strings.NewReader(str))
+}
+
+// DecodeIfBinaryToString converts a binary formatted log msg to a
+// JSON formatted String Log message - suitable for printing to Console/Syslog.
+func DecodeIfBinaryToString(in []byte) string {
+ if binaryFmt(in) {
+ var b bytes.Buffer
+ Cbor2JsonManyObjects(strings.NewReader(string(in)), &b)
+ return b.String()
+ }
+ return string(in)
+}
+
+// DecodeObjectToStr checks if the input is a binary format, if so,
+// it will decode a single Object and return the decoded string.
+func DecodeObjectToStr(in []byte) string {
+ if binaryFmt(in) {
+ var b bytes.Buffer
+ cbor2JsonOneObject(getReader(string(in)), &b)
+ return b.String()
+ }
+ return string(in)
+}
+
+// DecodeIfBinaryToBytes checks if the input is a binary format, if so,
+// it will decode all Objects and return the decoded string as byte array.
+func DecodeIfBinaryToBytes(in []byte) []byte {
+ if binaryFmt(in) {
+ var b bytes.Buffer
+ Cbor2JsonManyObjects(bytes.NewReader(in), &b)
+ return b.Bytes()
+ }
+ return in
+}
diff --git a/vendor/github.com/rs/zerolog/internal/cbor/string.go b/vendor/github.com/rs/zerolog/internal/cbor/string.go
new file mode 100644
index 0000000..9fc9a4f
--- /dev/null
+++ b/vendor/github.com/rs/zerolog/internal/cbor/string.go
@@ -0,0 +1,117 @@
+package cbor
+
+import "fmt"
+
+// AppendStrings encodes and adds an array of strings to the dst byte array.
+func (e Encoder) AppendStrings(dst []byte, vals []string) []byte {
+ major := majorTypeArray
+ l := len(vals)
+ if l <= additionalMax {
+ lb := byte(l)
+ dst = append(dst, major|lb)
+ } else {
+ dst = appendCborTypePrefix(dst, major, uint64(l))
+ }
+ for _, v := range vals {
+ dst = e.AppendString(dst, v)
+ }
+ return dst
+}
+
+// AppendString encodes and adds a string to the dst byte array.
+func (Encoder) AppendString(dst []byte, s string) []byte {
+ major := majorTypeUtf8String
+
+ l := len(s)
+ if l <= additionalMax {
+ lb := byte(l)
+ dst = append(dst, major|lb)
+ } else {
+ dst = appendCborTypePrefix(dst, majorTypeUtf8String, uint64(l))
+ }
+ return append(dst, s...)
+}
+
+// AppendStringers encodes and adds an array of Stringer values
+// to the dst byte array.
+func (e Encoder) AppendStringers(dst []byte, vals []fmt.Stringer) []byte {
+ if len(vals) == 0 {
+ return e.AppendArrayEnd(e.AppendArrayStart(dst))
+ }
+ dst = e.AppendArrayStart(dst)
+ dst = e.AppendStringer(dst, vals[0])
+ if len(vals) > 1 {
+ for _, val := range vals[1:] {
+ dst = e.AppendStringer(dst, val)
+ }
+ }
+ return e.AppendArrayEnd(dst)
+}
+
+// AppendStringer encodes and adds the Stringer value to the dst
+// byte array.
+func (e Encoder) AppendStringer(dst []byte, val fmt.Stringer) []byte {
+ if val == nil {
+ return e.AppendNil(dst)
+ }
+ return e.AppendString(dst, val.String())
+}
+
+// AppendBytes encodes and adds an array of bytes to the dst byte array.
+func (Encoder) AppendBytes(dst, s []byte) []byte {
+ major := majorTypeByteString
+
+ l := len(s)
+ if l <= additionalMax {
+ lb := byte(l)
+ dst = append(dst, major|lb)
+ } else {
+ dst = appendCborTypePrefix(dst, major, uint64(l))
+ }
+ return append(dst, s...)
+}
+
+// AppendEmbeddedJSON adds a tag and embeds input JSON as such.
+func AppendEmbeddedJSON(dst, s []byte) []byte {
+ major := majorTypeTags
+ minor := additionalTypeEmbeddedJSON
+
+ // Append the TAG to indicate this is Embedded JSON.
+ dst = append(dst, major|additionalTypeIntUint16)
+ dst = append(dst, byte(minor>>8))
+ dst = append(dst, byte(minor&0xff))
+
+ // Append the JSON Object as Byte String.
+ major = majorTypeByteString
+
+ l := len(s)
+ if l <= additionalMax {
+ lb := byte(l)
+ dst = append(dst, major|lb)
+ } else {
+ dst = appendCborTypePrefix(dst, major, uint64(l))
+ }
+ return append(dst, s...)
+}
+
+// AppendEmbeddedCBOR adds a tag and embeds input CBOR as such.
+func AppendEmbeddedCBOR(dst, s []byte) []byte {
+ major := majorTypeTags
+ minor := additionalTypeEmbeddedCBOR
+
+ // Append the TAG to indicate this is Embedded JSON.
+ dst = append(dst, major|additionalTypeIntUint8)
+ dst = append(dst, minor)
+
+ // Append the CBOR Object as Byte String.
+ major = majorTypeByteString
+
+ l := len(s)
+ if l <= additionalMax {
+ lb := byte(l)
+ dst = append(dst, major|lb)
+ } else {
+ dst = appendCborTypePrefix(dst, major, uint64(l))
+ }
+ return append(dst, s...)
+}
diff --git a/vendor/github.com/rs/zerolog/internal/cbor/time.go b/vendor/github.com/rs/zerolog/internal/cbor/time.go
new file mode 100644
index 0000000..7c0ecce
--- /dev/null
+++ b/vendor/github.com/rs/zerolog/internal/cbor/time.go
@@ -0,0 +1,93 @@
+package cbor
+
+import (
+ "time"
+)
+
+func appendIntegerTimestamp(dst []byte, t time.Time) []byte {
+ major := majorTypeTags
+ minor := additionalTypeTimestamp
+ dst = append(dst, major|minor)
+ secs := t.Unix()
+ var val uint64
+ if secs < 0 {
+ major = majorTypeNegativeInt
+ val = uint64(-secs - 1)
+ } else {
+ major = majorTypeUnsignedInt
+ val = uint64(secs)
+ }
+ dst = appendCborTypePrefix(dst, major, val)
+ return dst
+}
+
+func (e Encoder) appendFloatTimestamp(dst []byte, t time.Time) []byte {
+ major := majorTypeTags
+ minor := additionalTypeTimestamp
+ dst = append(dst, major|minor)
+ secs := t.Unix()
+ nanos := t.Nanosecond()
+ var val float64
+ val = float64(secs)*1.0 + float64(nanos)*1e-9
+ return e.AppendFloat64(dst, val, -1)
+}
+
+// AppendTime encodes and adds a timestamp to the dst byte array.
+func (e Encoder) AppendTime(dst []byte, t time.Time, unused string) []byte {
+ utc := t.UTC()
+ if utc.Nanosecond() == 0 {
+ return appendIntegerTimestamp(dst, utc)
+ }
+ return e.appendFloatTimestamp(dst, utc)
+}
+
+// AppendTimes encodes and adds an array of timestamps to the dst byte array.
+func (e Encoder) AppendTimes(dst []byte, vals []time.Time, unused string) []byte {
+ major := majorTypeArray
+ l := len(vals)
+ if l == 0 {
+ return e.AppendArrayEnd(e.AppendArrayStart(dst))
+ }
+ if l <= additionalMax {
+ lb := byte(l)
+ dst = append(dst, major|lb)
+ } else {
+ dst = appendCborTypePrefix(dst, major, uint64(l))
+ }
+
+ for _, t := range vals {
+ dst = e.AppendTime(dst, t, unused)
+ }
+ return dst
+}
+
+// AppendDuration encodes and adds a duration to the dst byte array.
+// useInt field indicates whether to store the duration as seconds (integer) or
+// as seconds+nanoseconds (float).
+func (e Encoder) AppendDuration(dst []byte, d time.Duration, unit time.Duration, useInt bool, unused int) []byte {
+ if useInt {
+ return e.AppendInt64(dst, int64(d/unit))
+ }
+ return e.AppendFloat64(dst, float64(d)/float64(unit), unused)
+}
+
+// AppendDurations encodes and adds an array of durations to the dst byte array.
+// useInt field indicates whether to store the duration as seconds (integer) or
+// as seconds+nanoseconds (float).
+func (e Encoder) AppendDurations(dst []byte, vals []time.Duration, unit time.Duration, useInt bool, unused int) []byte {
+ major := majorTypeArray
+ l := len(vals)
+ if l == 0 {
+ return e.AppendArrayEnd(e.AppendArrayStart(dst))
+ }
+ if l <= additionalMax {
+ lb := byte(l)
+ dst = append(dst, major|lb)
+ } else {
+ dst = appendCborTypePrefix(dst, major, uint64(l))
+ }
+ for _, d := range vals {
+ dst = e.AppendDuration(dst, d, unit, useInt, unused)
+ }
+ return dst
+}
diff --git a/vendor/github.com/rs/zerolog/internal/cbor/types.go b/vendor/github.com/rs/zerolog/internal/cbor/types.go
new file mode 100644
index 0000000..454d68b
--- /dev/null
+++ b/vendor/github.com/rs/zerolog/internal/cbor/types.go
@@ -0,0 +1,486 @@
+package cbor
+
+import (
+ "fmt"
+ "math"
+ "net"
+ "reflect"
+)
+
+// AppendNil inserts a 'Nil' object into the dst byte array.
+func (Encoder) AppendNil(dst []byte) []byte {
+ return append(dst, majorTypeSimpleAndFloat|additionalTypeNull)
+}
+
+// AppendBeginMarker inserts a map start into the dst byte array.
+func (Encoder) AppendBeginMarker(dst []byte) []byte {
+ return append(dst, majorTypeMap|additionalTypeInfiniteCount)
+}
+
+// AppendEndMarker inserts a map end into the dst byte array.
+func (Encoder) AppendEndMarker(dst []byte) []byte {
+ return append(dst, majorTypeSimpleAndFloat|additionalTypeBreak)
+}
+
+// AppendObjectData takes an object in form of a byte array and appends to dst.
+func (Encoder) AppendObjectData(dst []byte, o []byte) []byte {
+ // BeginMarker is present in the dst, which
+ // should not be copied when appending to existing data.
+ return append(dst, o[1:]...)
+}
+
+// AppendArrayStart adds markers to indicate the start of an array.
+func (Encoder) AppendArrayStart(dst []byte) []byte {
+ return append(dst, majorTypeArray|additionalTypeInfiniteCount)
+}
+
+// AppendArrayEnd adds markers to indicate the end of an array.
+func (Encoder) AppendArrayEnd(dst []byte) []byte {
+ return append(dst, majorTypeSimpleAndFloat|additionalTypeBreak)
+}
+
+// AppendArrayDelim adds markers to indicate end of a particular array element.
+func (Encoder) AppendArrayDelim(dst []byte) []byte {
+ //No delimiters needed in cbor
+ return dst
+}
+
+// AppendLineBreak is a noop that keep API compat with json encoder.
+func (Encoder) AppendLineBreak(dst []byte) []byte {
+ // No line breaks needed in binary format.
+ return dst
+}
+
+// AppendBool encodes and inserts a boolean value into the dst byte array.
+func (Encoder) AppendBool(dst []byte, val bool) []byte {
+ b := additionalTypeBoolFalse
+ if val {
+ b = additionalTypeBoolTrue
+ }
+ return append(dst, majorTypeSimpleAndFloat|b)
+}
+
+// AppendBools encodes and inserts an array of boolean values into the dst byte array.
+func (e Encoder) AppendBools(dst []byte, vals []bool) []byte {
+ major := majorTypeArray
+ l := len(vals)
+ if l == 0 {
+ return e.AppendArrayEnd(e.AppendArrayStart(dst))
+ }
+ if l <= additionalMax {
+ lb := byte(l)
+ dst = append(dst, major|lb)
+ } else {
+ dst = appendCborTypePrefix(dst, major, uint64(l))
+ }
+ for _, v := range vals {
+ dst = e.AppendBool(dst, v)
+ }
+ return dst
+}
+
+// AppendInt encodes and inserts an integer value into the dst byte array.
+func (Encoder) AppendInt(dst []byte, val int) []byte {
+ major := majorTypeUnsignedInt
+ contentVal := val
+ if val < 0 {
+ major = majorTypeNegativeInt
+ contentVal = -val - 1
+ }
+ if contentVal <= additionalMax {
+ lb := byte(contentVal)
+ dst = append(dst, major|lb)
+ } else {
+ dst = appendCborTypePrefix(dst, major, uint64(contentVal))
+ }
+ return dst
+}
+
+// AppendInts encodes and inserts an array of integer values into the dst byte array.
+func (e Encoder) AppendInts(dst []byte, vals []int) []byte {
+ major := majorTypeArray
+ l := len(vals)
+ if l == 0 {
+ return e.AppendArrayEnd(e.AppendArrayStart(dst))
+ }
+ if l <= additionalMax {
+ lb := byte(l)
+ dst = append(dst, major|lb)
+ } else {
+ dst = appendCborTypePrefix(dst, major, uint64(l))
+ }
+ for _, v := range vals {
+ dst = e.AppendInt(dst, v)
+ }
+ return dst
+}
+
+// AppendInt8 encodes and inserts an int8 value into the dst byte array.
+func (e Encoder) AppendInt8(dst []byte, val int8) []byte {
+ return e.AppendInt(dst, int(val))
+}
+
+// AppendInts8 encodes and inserts an array of integer values into the dst byte array.
+func (e Encoder) AppendInts8(dst []byte, vals []int8) []byte {
+ major := majorTypeArray
+ l := len(vals)
+ if l == 0 {
+ return e.AppendArrayEnd(e.AppendArrayStart(dst))
+ }
+ if l <= additionalMax {
+ lb := byte(l)
+ dst = append(dst, major|lb)
+ } else {
+ dst = appendCborTypePrefix(dst, major, uint64(l))
+ }
+ for _, v := range vals {
+ dst = e.AppendInt(dst, int(v))
+ }
+ return dst
+}
+
+// AppendInt16 encodes and inserts a int16 value into the dst byte array.
+func (e Encoder) AppendInt16(dst []byte, val int16) []byte {
+ return e.AppendInt(dst, int(val))
+}
+
+// AppendInts16 encodes and inserts an array of int16 values into the dst byte array.
+func (e Encoder) AppendInts16(dst []byte, vals []int16) []byte {
+ major := majorTypeArray
+ l := len(vals)
+ if l == 0 {
+ return e.AppendArrayEnd(e.AppendArrayStart(dst))
+ }
+ if l <= additionalMax {
+ lb := byte(l)
+ dst = append(dst, major|lb)
+ } else {
+ dst = appendCborTypePrefix(dst, major, uint64(l))
+ }
+ for _, v := range vals {
+ dst = e.AppendInt(dst, int(v))
+ }
+ return dst
+}
+
+// AppendInt32 encodes and inserts a int32 value into the dst byte array.
+func (e Encoder) AppendInt32(dst []byte, val int32) []byte {
+ return e.AppendInt(dst, int(val))
+}
+
+// AppendInts32 encodes and inserts an array of int32 values into the dst byte array.
+func (e Encoder) AppendInts32(dst []byte, vals []int32) []byte {
+ major := majorTypeArray
+ l := len(vals)
+ if l == 0 {
+ return e.AppendArrayEnd(e.AppendArrayStart(dst))
+ }
+ if l <= additionalMax {
+ lb := byte(l)
+ dst = append(dst, major|lb)
+ } else {
+ dst = appendCborTypePrefix(dst, major, uint64(l))
+ }
+ for _, v := range vals {
+ dst = e.AppendInt(dst, int(v))
+ }
+ return dst
+}
+
+// AppendInt64 encodes and inserts a int64 value into the dst byte array.
+func (Encoder) AppendInt64(dst []byte, val int64) []byte {
+ major := majorTypeUnsignedInt
+ contentVal := val
+ if val < 0 {
+ major = majorTypeNegativeInt
+ contentVal = -val - 1
+ }
+ if contentVal <= additionalMax {
+ lb := byte(contentVal)
+ dst = append(dst, major|lb)
+ } else {
+ dst = appendCborTypePrefix(dst, major, uint64(contentVal))
+ }
+ return dst
+}
+
+// AppendInts64 encodes and inserts an array of int64 values into the dst byte array.
+func (e Encoder) AppendInts64(dst []byte, vals []int64) []byte {
+ major := majorTypeArray
+ l := len(vals)
+ if l == 0 {
+ return e.AppendArrayEnd(e.AppendArrayStart(dst))
+ }
+ if l <= additionalMax {
+ lb := byte(l)
+ dst = append(dst, major|lb)
+ } else {
+ dst = appendCborTypePrefix(dst, major, uint64(l))
+ }
+ for _, v := range vals {
+ dst = e.AppendInt64(dst, v)
+ }
+ return dst
+}
+
+// AppendUint encodes and inserts an unsigned integer value into the dst byte array.
+func (e Encoder) AppendUint(dst []byte, val uint) []byte {
+ return e.AppendInt64(dst, int64(val))
+}
+
+// AppendUints encodes and inserts an array of unsigned integer values into the dst byte array.
+func (e Encoder) AppendUints(dst []byte, vals []uint) []byte {
+ major := majorTypeArray
+ l := len(vals)
+ if l == 0 {
+ return e.AppendArrayEnd(e.AppendArrayStart(dst))
+ }
+ if l <= additionalMax {
+ lb := byte(l)
+ dst = append(dst, major|lb)
+ } else {
+ dst = appendCborTypePrefix(dst, major, uint64(l))
+ }
+ for _, v := range vals {
+ dst = e.AppendUint(dst, v)
+ }
+ return dst
+}
+
+// AppendUint8 encodes and inserts a unsigned int8 value into the dst byte array.
+func (e Encoder) AppendUint8(dst []byte, val uint8) []byte {
+ return e.AppendUint(dst, uint(val))
+}
+
+// AppendUints8 encodes and inserts an array of uint8 values into the dst byte array.
+func (e Encoder) AppendUints8(dst []byte, vals []uint8) []byte {
+ major := majorTypeArray
+ l := len(vals)
+ if l == 0 {
+ return e.AppendArrayEnd(e.AppendArrayStart(dst))
+ }
+ if l <= additionalMax {
+ lb := byte(l)
+ dst = append(dst, major|lb)
+ } else {
+ dst = appendCborTypePrefix(dst, major, uint64(l))
+ }
+ for _, v := range vals {
+ dst = e.AppendUint8(dst, v)
+ }
+ return dst
+}
+
+// AppendUint16 encodes and inserts a uint16 value into the dst byte array.
+func (e Encoder) AppendUint16(dst []byte, val uint16) []byte {
+ return e.AppendUint(dst, uint(val))
+}
+
+// AppendUints16 encodes and inserts an array of uint16 values into the dst byte array.
+func (e Encoder) AppendUints16(dst []byte, vals []uint16) []byte {
+ major := majorTypeArray
+ l := len(vals)
+ if l == 0 {
+ return e.AppendArrayEnd(e.AppendArrayStart(dst))
+ }
+ if l <= additionalMax {
+ lb := byte(l)
+ dst = append(dst, major|lb)
+ } else {
+ dst = appendCborTypePrefix(dst, major, uint64(l))
+ }
+ for _, v := range vals {
+ dst = e.AppendUint16(dst, v)
+ }
+ return dst
+}
+
+// AppendUint32 encodes and inserts a uint32 value into the dst byte array.
+func (e Encoder) AppendUint32(dst []byte, val uint32) []byte {
+ return e.AppendUint(dst, uint(val))
+}
+
+// AppendUints32 encodes and inserts an array of uint32 values into the dst byte array.
+func (e Encoder) AppendUints32(dst []byte, vals []uint32) []byte {
+ major := majorTypeArray
+ l := len(vals)
+ if l == 0 {
+ return e.AppendArrayEnd(e.AppendArrayStart(dst))
+ }
+ if l <= additionalMax {
+ lb := byte(l)
+ dst = append(dst, major|lb)
+ } else {
+ dst = appendCborTypePrefix(dst, major, uint64(l))
+ }
+ for _, v := range vals {
+ dst = e.AppendUint32(dst, v)
+ }
+ return dst
+}
+
+// AppendUint64 encodes and inserts a uint64 value into the dst byte array.
+func (Encoder) AppendUint64(dst []byte, val uint64) []byte {
+ major := majorTypeUnsignedInt
+ contentVal := val
+ if contentVal <= additionalMax {
+ lb := byte(contentVal)
+ dst = append(dst, major|lb)
+ } else {
+ dst = appendCborTypePrefix(dst, major, contentVal)
+ }
+ return dst
+}
+
+// AppendUints64 encodes and inserts an array of uint64 values into the dst byte array.
+func (e Encoder) AppendUints64(dst []byte, vals []uint64) []byte {
+ major := majorTypeArray
+ l := len(vals)
+ if l == 0 {
+ return e.AppendArrayEnd(e.AppendArrayStart(dst))
+ }
+ if l <= additionalMax {
+ lb := byte(l)
+ dst = append(dst, major|lb)
+ } else {
+ dst = appendCborTypePrefix(dst, major, uint64(l))
+ }
+ for _, v := range vals {
+ dst = e.AppendUint64(dst, v)
+ }
+ return dst
+}
+
+// AppendFloat32 encodes and inserts a single precision float value into the dst byte array.
+func (Encoder) AppendFloat32(dst []byte, val float32, unused int) []byte {
+ switch {
+ case math.IsNaN(float64(val)):
+ return append(dst, "\xfa\x7f\xc0\x00\x00"...)
+ case math.IsInf(float64(val), 1):
+ return append(dst, "\xfa\x7f\x80\x00\x00"...)
+ case math.IsInf(float64(val), -1):
+ return append(dst, "\xfa\xff\x80\x00\x00"...)
+ }
+ major := majorTypeSimpleAndFloat
+ subType := additionalTypeFloat32
+ n := math.Float32bits(val)
+ var buf [4]byte
+ for i := uint(0); i < 4; i++ {
+ buf[i] = byte(n >> ((3 - i) * 8))
+ }
+ return append(append(dst, major|subType), buf[0], buf[1], buf[2], buf[3])
+}
+
+// AppendFloats32 encodes and inserts an array of single precision float value into the dst byte array.
+func (e Encoder) AppendFloats32(dst []byte, vals []float32, unused int) []byte {
+ major := majorTypeArray
+ l := len(vals)
+ if l == 0 {
+ return e.AppendArrayEnd(e.AppendArrayStart(dst))
+ }
+ if l <= additionalMax {
+ lb := byte(l)
+ dst = append(dst, major|lb)
+ } else {
+ dst = appendCborTypePrefix(dst, major, uint64(l))
+ }
+ for _, v := range vals {
+ dst = e.AppendFloat32(dst, v, unused)
+ }
+ return dst
+}
+
+// AppendFloat64 encodes and inserts a double precision float value into the dst byte array.
+func (Encoder) AppendFloat64(dst []byte, val float64, unused int) []byte {
+ switch {
+ case math.IsNaN(val):
+ return append(dst, "\xfb\x7f\xf8\x00\x00\x00\x00\x00\x00"...)
+ case math.IsInf(val, 1):
+ return append(dst, "\xfb\x7f\xf0\x00\x00\x00\x00\x00\x00"...)
+ case math.IsInf(val, -1):
+ return append(dst, "\xfb\xff\xf0\x00\x00\x00\x00\x00\x00"...)
+ }
+ major := majorTypeSimpleAndFloat
+ subType := additionalTypeFloat64
+ n := math.Float64bits(val)
+ dst = append(dst, major|subType)
+ for i := uint(1); i <= 8; i++ {
+ b := byte(n >> ((8 - i) * 8))
+ dst = append(dst, b)
+ }
+ return dst
+}
+
+// AppendFloats64 encodes and inserts an array of double precision float values into the dst byte array.
+func (e Encoder) AppendFloats64(dst []byte, vals []float64, unused int) []byte {
+ major := majorTypeArray
+ l := len(vals)
+ if l == 0 {
+ return e.AppendArrayEnd(e.AppendArrayStart(dst))
+ }
+ if l <= additionalMax {
+ lb := byte(l)
+ dst = append(dst, major|lb)
+ } else {
+ dst = appendCborTypePrefix(dst, major, uint64(l))
+ }
+ for _, v := range vals {
+ dst = e.AppendFloat64(dst, v, unused)
+ }
+ return dst
+}
+
+// AppendInterface takes an arbitrary object and converts it to JSON and embeds it dst.
+func (e Encoder) AppendInterface(dst []byte, i interface{}) []byte {
+ marshaled, err := JSONMarshalFunc(i)
+ if err != nil {
+ return e.AppendString(dst, fmt.Sprintf("marshaling error: %v", err))
+ }
+ return AppendEmbeddedJSON(dst, marshaled)
+}
+
+// AppendType appends the parameter type (as a string) to the input byte slice.
+func (e Encoder) AppendType(dst []byte, i interface{}) []byte {
+ if i == nil {
+ return e.AppendString(dst, "")
+ }
+ return e.AppendString(dst, reflect.TypeOf(i).String())
+}
+
+// AppendIPAddr encodes and inserts an IP Address (IPv4 or IPv6).
+func (e Encoder) AppendIPAddr(dst []byte, ip net.IP) []byte {
+ dst = append(dst, majorTypeTags|additionalTypeIntUint16)
+ dst = append(dst, byte(additionalTypeTagNetworkAddr>>8))
+ dst = append(dst, byte(additionalTypeTagNetworkAddr&0xff))
+ return e.AppendBytes(dst, ip)
+}
+
+// AppendIPPrefix encodes and inserts an IP Address Prefix (Address + Mask Length).
+func (e Encoder) AppendIPPrefix(dst []byte, pfx net.IPNet) []byte {
+ dst = append(dst, majorTypeTags|additionalTypeIntUint16)
+ dst = append(dst, byte(additionalTypeTagNetworkPrefix>>8))
+ dst = append(dst, byte(additionalTypeTagNetworkPrefix&0xff))
+
+ // Prefix is a tuple (aka MAP of 1 pair of elements) -
+ // first element is prefix, second is mask length.
+ dst = append(dst, majorTypeMap|0x1)
+ dst = e.AppendBytes(dst, pfx.IP)
+ maskLen, _ := pfx.Mask.Size()
+ return e.AppendUint8(dst, uint8(maskLen))
+}
+
+// AppendMACAddr encodes and inserts a Hardware (MAC) address.
+func (e Encoder) AppendMACAddr(dst []byte, ha net.HardwareAddr) []byte {
+ dst = append(dst, majorTypeTags|additionalTypeIntUint16)
+ dst = append(dst, byte(additionalTypeTagNetworkAddr>>8))
+ dst = append(dst, byte(additionalTypeTagNetworkAddr&0xff))
+ return e.AppendBytes(dst, ha)
+}
+
+// AppendHex adds a TAG and inserts a hex bytes as a string.
+func (e Encoder) AppendHex(dst []byte, val []byte) []byte {
+ dst = append(dst, majorTypeTags|additionalTypeIntUint16)
+ dst = append(dst, byte(additionalTypeTagHexString>>8))
+ dst = append(dst, byte(additionalTypeTagHexString&0xff))
+ return e.AppendBytes(dst, val)
+}
diff --git a/vendor/github.com/rs/zerolog/internal/json/base.go b/vendor/github.com/rs/zerolog/internal/json/base.go
new file mode 100644
index 0000000..09ec59f
--- /dev/null
+++ b/vendor/github.com/rs/zerolog/internal/json/base.go
@@ -0,0 +1,19 @@
+package json
+
+// JSONMarshalFunc is used to marshal interface to JSON encoded byte slice.
+// Making it package level instead of embedded in Encoder brings
+// some extra efforts at importing, but avoids value copy when the functions
+// of Encoder being invoked.
+// DO REMEMBER to set this variable at importing, or
+// you might get a nil pointer dereference panic at runtime.
+var JSONMarshalFunc func(v interface{}) ([]byte, error)
+
+type Encoder struct{}
+
+// AppendKey appends a new key to the output JSON.
+func (e Encoder) AppendKey(dst []byte, key string) []byte {
+ if dst[len(dst)-1] != '{' {
+ dst = append(dst, ',')
+ }
+ return append(e.AppendString(dst, key), ':')
+}
diff --git a/vendor/github.com/rs/zerolog/internal/json/bytes.go b/vendor/github.com/rs/zerolog/internal/json/bytes.go
new file mode 100644
index 0000000..de64120
--- /dev/null
+++ b/vendor/github.com/rs/zerolog/internal/json/bytes.go
@@ -0,0 +1,85 @@
+package json
+
+import "unicode/utf8"
+
+// AppendBytes is a mirror of appendString with []byte arg
+func (Encoder) AppendBytes(dst, s []byte) []byte {
+ dst = append(dst, '"')
+ for i := 0; i < len(s); i++ {
+ if !noEscapeTable[s[i]] {
+ dst = appendBytesComplex(dst, s, i)
+ return append(dst, '"')
+ }
+ }
+ dst = append(dst, s...)
+ return append(dst, '"')
+}
+
+// AppendHex encodes the input bytes to a hex string and appends
+// the encoded string to the input byte slice.
+//
+// The operation loops though each byte and encodes it as hex using
+// the hex lookup table.
+func (Encoder) AppendHex(dst, s []byte) []byte {
+ dst = append(dst, '"')
+ for _, v := range s {
+ dst = append(dst, hex[v>>4], hex[v&0x0f])
+ }
+ return append(dst, '"')
+}
+
+// appendBytesComplex is a mirror of the appendStringComplex
+// with []byte arg
+func appendBytesComplex(dst, s []byte, i int) []byte {
+ start := 0
+ for i < len(s) {
+ b := s[i]
+ if b >= utf8.RuneSelf {
+ r, size := utf8.DecodeRune(s[i:])
+ if r == utf8.RuneError && size == 1 {
+ if start < i {
+ dst = append(dst, s[start:i]...)
+ }
+ dst = append(dst, `\ufffd`...)
+ i += size
+ start = i
+ continue
+ }
+ i += size
+ continue
+ }
+ if noEscapeTable[b] {
+ i++
+ continue
+ }
+ // We encountered a character that needs to be encoded.
+ // Let's append the previous simple characters to the byte slice
+ // and switch our operation to read and encode the remainder
+ // characters byte-by-byte.
+ if start < i {
+ dst = append(dst, s[start:i]...)
+ }
+ switch b {
+ case '"', '\\':
+ dst = append(dst, '\\', b)
+ case '\b':
+ dst = append(dst, '\\', 'b')
+ case '\f':
+ dst = append(dst, '\\', 'f')
+ case '\n':
+ dst = append(dst, '\\', 'n')
+ case '\r':
+ dst = append(dst, '\\', 'r')
+ case '\t':
+ dst = append(dst, '\\', 't')
+ default:
+ dst = append(dst, '\\', 'u', '0', '0', hex[b>>4], hex[b&0xF])
+ }
+ i++
+ start = i
+ }
+ if start < len(s) {
+ dst = append(dst, s[start:]...)
+ }
+ return dst
+}
diff --git a/vendor/github.com/rs/zerolog/internal/json/string.go b/vendor/github.com/rs/zerolog/internal/json/string.go
new file mode 100644
index 0000000..fd7770f
--- /dev/null
+++ b/vendor/github.com/rs/zerolog/internal/json/string.go
@@ -0,0 +1,149 @@
+package json
+
+import (
+ "fmt"
+ "unicode/utf8"
+)
+
+const hex = "0123456789abcdef"
+
+var noEscapeTable = [256]bool{}
+
+func init() {
+ for i := 0; i <= 0x7e; i++ {
+ noEscapeTable[i] = i >= 0x20 && i != '\\' && i != '"'
+ }
+}
+
+// AppendStrings encodes the input strings to json and
+// appends the encoded string list to the input byte slice.
+func (e Encoder) AppendStrings(dst []byte, vals []string) []byte {
+ if len(vals) == 0 {
+ return append(dst, '[', ']')
+ }
+ dst = append(dst, '[')
+ dst = e.AppendString(dst, vals[0])
+ if len(vals) > 1 {
+ for _, val := range vals[1:] {
+ dst = e.AppendString(append(dst, ','), val)
+ }
+ }
+ dst = append(dst, ']')
+ return dst
+}
+
+// AppendString encodes the input string to json and appends
+// the encoded string to the input byte slice.
+//
+// The operation loops though each byte in the string looking
+// for characters that need json or utf8 encoding. If the string
+// does not need encoding, then the string is appended in its
+// entirety to the byte slice.
+// If we encounter a byte that does need encoding, switch up
+// the operation and perform a byte-by-byte read-encode-append.
+func (Encoder) AppendString(dst []byte, s string) []byte {
+ // Start with a double quote.
+ dst = append(dst, '"')
+ // Loop through each character in the string.
+ for i := 0; i < len(s); i++ {
+ // Check if the character needs encoding. Control characters, slashes,
+ // and the double quote need json encoding. Bytes above the ascii
+ // boundary needs utf8 encoding.
+ if !noEscapeTable[s[i]] {
+ // We encountered a character that needs to be encoded. Switch
+ // to complex version of the algorithm.
+ dst = appendStringComplex(dst, s, i)
+ return append(dst, '"')
+ }
+ }
+ // The string has no need for encoding and therefore is directly
+ // appended to the byte slice.
+ dst = append(dst, s...)
+ // End with a double quote
+ return append(dst, '"')
+}
+
+// AppendStringers encodes the provided Stringer list to json and
+// appends the encoded Stringer list to the input byte slice.
+func (e Encoder) AppendStringers(dst []byte, vals []fmt.Stringer) []byte {
+ if len(vals) == 0 {
+ return append(dst, '[', ']')
+ }
+ dst = append(dst, '[')
+ dst = e.AppendStringer(dst, vals[0])
+ if len(vals) > 1 {
+ for _, val := range vals[1:] {
+ dst = e.AppendStringer(append(dst, ','), val)
+ }
+ }
+ return append(dst, ']')
+}
+
+// AppendStringer encodes the input Stringer to json and appends the
+// encoded Stringer value to the input byte slice.
+func (e Encoder) AppendStringer(dst []byte, val fmt.Stringer) []byte {
+ if val == nil {
+ return e.AppendInterface(dst, nil)
+ }
+ return e.AppendString(dst, val.String())
+}
+
+//// appendStringComplex is used by appendString to take over an in
+// progress JSON string encoding that encountered a character that needs
+// to be encoded.
+func appendStringComplex(dst []byte, s string, i int) []byte {
+ start := 0
+ for i < len(s) {
+ b := s[i]
+ if b >= utf8.RuneSelf {
+ r, size := utf8.DecodeRuneInString(s[i:])
+ if r == utf8.RuneError && size == 1 {
+ // In case of error, first append previous simple characters to
+ // the byte slice if any and append a replacement character code
+ // in place of the invalid sequence.
+ if start < i {
+ dst = append(dst, s[start:i]...)
+ }
+ dst = append(dst, `\ufffd`...)
+ i += size
+ start = i
+ continue
+ }
+ i += size
+ continue
+ }
+ if noEscapeTable[b] {
+ i++
+ continue
+ }
+ // We encountered a character that needs to be encoded.
+ // Let's append the previous simple characters to the byte slice
+ // and switch our operation to read and encode the remainder
+ // characters byte-by-byte.
+ if start < i {
+ dst = append(dst, s[start:i]...)
+ }
+ switch b {
+ case '"', '\\':
+ dst = append(dst, '\\', b)
+ case '\b':
+ dst = append(dst, '\\', 'b')
+ case '\f':
+ dst = append(dst, '\\', 'f')
+ case '\n':
+ dst = append(dst, '\\', 'n')
+ case '\r':
+ dst = append(dst, '\\', 'r')
+ case '\t':
+ dst = append(dst, '\\', 't')
+ default:
+ dst = append(dst, '\\', 'u', '0', '0', hex[b>>4], hex[b&0xF])
+ }
+ i++
+ start = i
+ }
+ if start < len(s) {
+ dst = append(dst, s[start:]...)
+ }
+ return dst
+}
diff --git a/vendor/github.com/rs/zerolog/internal/json/time.go b/vendor/github.com/rs/zerolog/internal/json/time.go
new file mode 100644
index 0000000..08cbbd9
--- /dev/null
+++ b/vendor/github.com/rs/zerolog/internal/json/time.go
@@ -0,0 +1,113 @@
+package json
+
+import (
+ "strconv"
+ "time"
+)
+
+const (
+ // Import from zerolog/global.go
+ timeFormatUnix = ""
+ timeFormatUnixMs = "UNIXMS"
+ timeFormatUnixMicro = "UNIXMICRO"
+ timeFormatUnixNano = "UNIXNANO"
+)
+
+// AppendTime formats the input time with the given format
+// and appends the encoded string to the input byte slice.
+func (e Encoder) AppendTime(dst []byte, t time.Time, format string) []byte {
+ switch format {
+ case timeFormatUnix:
+ return e.AppendInt64(dst, t.Unix())
+ case timeFormatUnixMs:
+ return e.AppendInt64(dst, t.UnixNano()/1000000)
+ case timeFormatUnixMicro:
+ return e.AppendInt64(dst, t.UnixNano()/1000)
+ case timeFormatUnixNano:
+ return e.AppendInt64(dst, t.UnixNano())
+ }
+ return append(t.AppendFormat(append(dst, '"'), format), '"')
+}
+
+// AppendTimes converts the input times with the given format
+// and appends the encoded string list to the input byte slice.
+func (Encoder) AppendTimes(dst []byte, vals []time.Time, format string) []byte {
+ switch format {
+ case timeFormatUnix:
+ return appendUnixTimes(dst, vals)
+ case timeFormatUnixMs:
+ return appendUnixNanoTimes(dst, vals, 1000000)
+ case timeFormatUnixMicro:
+ return appendUnixNanoTimes(dst, vals, 1000)
+ case timeFormatUnixNano:
+ return appendUnixNanoTimes(dst, vals, 1)
+ }
+ if len(vals) == 0 {
+ return append(dst, '[', ']')
+ }
+ dst = append(dst, '[')
+ dst = append(vals[0].AppendFormat(append(dst, '"'), format), '"')
+ if len(vals) > 1 {
+ for _, t := range vals[1:] {
+ dst = append(t.AppendFormat(append(dst, ',', '"'), format), '"')
+ }
+ }
+ dst = append(dst, ']')
+ return dst
+}
+
+func appendUnixTimes(dst []byte, vals []time.Time) []byte {
+ if len(vals) == 0 {
+ return append(dst, '[', ']')
+ }
+ dst = append(dst, '[')
+ dst = strconv.AppendInt(dst, vals[0].Unix(), 10)
+ if len(vals) > 1 {
+ for _, t := range vals[1:] {
+ dst = strconv.AppendInt(append(dst, ','), t.Unix(), 10)
+ }
+ }
+ dst = append(dst, ']')
+ return dst
+}
+
+func appendUnixNanoTimes(dst []byte, vals []time.Time, div int64) []byte {
+ if len(vals) == 0 {
+ return append(dst, '[', ']')
+ }
+ dst = append(dst, '[')
+ dst = strconv.AppendInt(dst, vals[0].UnixNano()/div, 10)
+ if len(vals) > 1 {
+ for _, t := range vals[1:] {
+ dst = strconv.AppendInt(append(dst, ','), t.UnixNano()/div, 10)
+ }
+ }
+ dst = append(dst, ']')
+ return dst
+}
+
+// AppendDuration formats the input duration with the given unit & format
+// and appends the encoded string to the input byte slice.
+func (e Encoder) AppendDuration(dst []byte, d time.Duration, unit time.Duration, useInt bool, precision int) []byte {
+ if useInt {
+ return strconv.AppendInt(dst, int64(d/unit), 10)
+ }
+ return e.AppendFloat64(dst, float64(d)/float64(unit), precision)
+}
+
+// AppendDurations formats the input durations with the given unit & format
+// and appends the encoded string list to the input byte slice.
+func (e Encoder) AppendDurations(dst []byte, vals []time.Duration, unit time.Duration, useInt bool, precision int) []byte {
+ if len(vals) == 0 {
+ return append(dst, '[', ']')
+ }
+ dst = append(dst, '[')
+ dst = e.AppendDuration(dst, vals[0], unit, useInt, precision)
+ if len(vals) > 1 {
+ for _, d := range vals[1:] {
+ dst = e.AppendDuration(append(dst, ','), d, unit, useInt, precision)
+ }
+ }
+ dst = append(dst, ']')
+ return dst
+}
diff --git a/vendor/github.com/rs/zerolog/internal/json/types.go b/vendor/github.com/rs/zerolog/internal/json/types.go
new file mode 100644
index 0000000..7930491
--- /dev/null
+++ b/vendor/github.com/rs/zerolog/internal/json/types.go
@@ -0,0 +1,435 @@
+package json
+
+import (
+ "fmt"
+ "math"
+ "net"
+ "reflect"
+ "strconv"
+)
+
+// AppendNil inserts a 'Nil' object into the dst byte array.
+func (Encoder) AppendNil(dst []byte) []byte {
+ return append(dst, "null"...)
+}
+
+// AppendBeginMarker inserts a map start into the dst byte array.
+func (Encoder) AppendBeginMarker(dst []byte) []byte {
+ return append(dst, '{')
+}
+
+// AppendEndMarker inserts a map end into the dst byte array.
+func (Encoder) AppendEndMarker(dst []byte) []byte {
+ return append(dst, '}')
+}
+
+// AppendLineBreak appends a line break.
+func (Encoder) AppendLineBreak(dst []byte) []byte {
+ return append(dst, '\n')
+}
+
+// AppendArrayStart adds markers to indicate the start of an array.
+func (Encoder) AppendArrayStart(dst []byte) []byte {
+ return append(dst, '[')
+}
+
+// AppendArrayEnd adds markers to indicate the end of an array.
+func (Encoder) AppendArrayEnd(dst []byte) []byte {
+ return append(dst, ']')
+}
+
+// AppendArrayDelim adds markers to indicate end of a particular array element.
+func (Encoder) AppendArrayDelim(dst []byte) []byte {
+ if len(dst) > 0 {
+ return append(dst, ',')
+ }
+ return dst
+}
+
+// AppendBool converts the input bool to a string and
+// appends the encoded string to the input byte slice.
+func (Encoder) AppendBool(dst []byte, val bool) []byte {
+ return strconv.AppendBool(dst, val)
+}
+
+// AppendBools encodes the input bools to json and
+// appends the encoded string list to the input byte slice.
+func (Encoder) AppendBools(dst []byte, vals []bool) []byte {
+ if len(vals) == 0 {
+ return append(dst, '[', ']')
+ }
+ dst = append(dst, '[')
+ dst = strconv.AppendBool(dst, vals[0])
+ if len(vals) > 1 {
+ for _, val := range vals[1:] {
+ dst = strconv.AppendBool(append(dst, ','), val)
+ }
+ }
+ dst = append(dst, ']')
+ return dst
+}
+
+// AppendInt converts the input int to a string and
+// appends the encoded string to the input byte slice.
+func (Encoder) AppendInt(dst []byte, val int) []byte {
+ return strconv.AppendInt(dst, int64(val), 10)
+}
+
+// AppendInts encodes the input ints to json and
+// appends the encoded string list to the input byte slice.
+func (Encoder) AppendInts(dst []byte, vals []int) []byte {
+ if len(vals) == 0 {
+ return append(dst, '[', ']')
+ }
+ dst = append(dst, '[')
+ dst = strconv.AppendInt(dst, int64(vals[0]), 10)
+ if len(vals) > 1 {
+ for _, val := range vals[1:] {
+ dst = strconv.AppendInt(append(dst, ','), int64(val), 10)
+ }
+ }
+ dst = append(dst, ']')
+ return dst
+}
+
+// AppendInt8 converts the input []int8 to a string and
+// appends the encoded string to the input byte slice.
+func (Encoder) AppendInt8(dst []byte, val int8) []byte {
+ return strconv.AppendInt(dst, int64(val), 10)
+}
+
+// AppendInts8 encodes the input int8s to json and
+// appends the encoded string list to the input byte slice.
+func (Encoder) AppendInts8(dst []byte, vals []int8) []byte {
+ if len(vals) == 0 {
+ return append(dst, '[', ']')
+ }
+ dst = append(dst, '[')
+ dst = strconv.AppendInt(dst, int64(vals[0]), 10)
+ if len(vals) > 1 {
+ for _, val := range vals[1:] {
+ dst = strconv.AppendInt(append(dst, ','), int64(val), 10)
+ }
+ }
+ dst = append(dst, ']')
+ return dst
+}
+
+// AppendInt16 converts the input int16 to a string and
+// appends the encoded string to the input byte slice.
+func (Encoder) AppendInt16(dst []byte, val int16) []byte {
+ return strconv.AppendInt(dst, int64(val), 10)
+}
+
+// AppendInts16 encodes the input int16s to json and
+// appends the encoded string list to the input byte slice.
+func (Encoder) AppendInts16(dst []byte, vals []int16) []byte {
+ if len(vals) == 0 {
+ return append(dst, '[', ']')
+ }
+ dst = append(dst, '[')
+ dst = strconv.AppendInt(dst, int64(vals[0]), 10)
+ if len(vals) > 1 {
+ for _, val := range vals[1:] {
+ dst = strconv.AppendInt(append(dst, ','), int64(val), 10)
+ }
+ }
+ dst = append(dst, ']')
+ return dst
+}
+
+// AppendInt32 converts the input int32 to a string and
+// appends the encoded string to the input byte slice.
+func (Encoder) AppendInt32(dst []byte, val int32) []byte {
+ return strconv.AppendInt(dst, int64(val), 10)
+}
+
+// AppendInts32 encodes the input int32s to json and
+// appends the encoded string list to the input byte slice.
+func (Encoder) AppendInts32(dst []byte, vals []int32) []byte {
+ if len(vals) == 0 {
+ return append(dst, '[', ']')
+ }
+ dst = append(dst, '[')
+ dst = strconv.AppendInt(dst, int64(vals[0]), 10)
+ if len(vals) > 1 {
+ for _, val := range vals[1:] {
+ dst = strconv.AppendInt(append(dst, ','), int64(val), 10)
+ }
+ }
+ dst = append(dst, ']')
+ return dst
+}
+
+// AppendInt64 converts the input int64 to a string and
+// appends the encoded string to the input byte slice.
+func (Encoder) AppendInt64(dst []byte, val int64) []byte {
+ return strconv.AppendInt(dst, val, 10)
+}
+
+// AppendInts64 encodes the input int64s to json and
+// appends the encoded string list to the input byte slice.
+func (Encoder) AppendInts64(dst []byte, vals []int64) []byte {
+ if len(vals) == 0 {
+ return append(dst, '[', ']')
+ }
+ dst = append(dst, '[')
+ dst = strconv.AppendInt(dst, vals[0], 10)
+ if len(vals) > 1 {
+ for _, val := range vals[1:] {
+ dst = strconv.AppendInt(append(dst, ','), val, 10)
+ }
+ }
+ dst = append(dst, ']')
+ return dst
+}
+
+// AppendUint converts the input uint to a string and
+// appends the encoded string to the input byte slice.
+func (Encoder) AppendUint(dst []byte, val uint) []byte {
+ return strconv.AppendUint(dst, uint64(val), 10)
+}
+
+// AppendUints encodes the input uints to json and
+// appends the encoded string list to the input byte slice.
+func (Encoder) AppendUints(dst []byte, vals []uint) []byte {
+ if len(vals) == 0 {
+ return append(dst, '[', ']')
+ }
+ dst = append(dst, '[')
+ dst = strconv.AppendUint(dst, uint64(vals[0]), 10)
+ if len(vals) > 1 {
+ for _, val := range vals[1:] {
+ dst = strconv.AppendUint(append(dst, ','), uint64(val), 10)
+ }
+ }
+ dst = append(dst, ']')
+ return dst
+}
+
+// AppendUint8 converts the input uint8 to a string and
+// appends the encoded string to the input byte slice.
+func (Encoder) AppendUint8(dst []byte, val uint8) []byte {
+ return strconv.AppendUint(dst, uint64(val), 10)
+}
+
+// AppendUints8 encodes the input uint8s to json and
+// appends the encoded string list to the input byte slice.
+func (Encoder) AppendUints8(dst []byte, vals []uint8) []byte {
+ if len(vals) == 0 {
+ return append(dst, '[', ']')
+ }
+ dst = append(dst, '[')
+ dst = strconv.AppendUint(dst, uint64(vals[0]), 10)
+ if len(vals) > 1 {
+ for _, val := range vals[1:] {
+ dst = strconv.AppendUint(append(dst, ','), uint64(val), 10)
+ }
+ }
+ dst = append(dst, ']')
+ return dst
+}
+
+// AppendUint16 converts the input uint16 to a string and
+// appends the encoded string to the input byte slice.
+func (Encoder) AppendUint16(dst []byte, val uint16) []byte {
+ return strconv.AppendUint(dst, uint64(val), 10)
+}
+
+// AppendUints16 encodes the input uint16s to json and
+// appends the encoded string list to the input byte slice.
+func (Encoder) AppendUints16(dst []byte, vals []uint16) []byte {
+ if len(vals) == 0 {
+ return append(dst, '[', ']')
+ }
+ dst = append(dst, '[')
+ dst = strconv.AppendUint(dst, uint64(vals[0]), 10)
+ if len(vals) > 1 {
+ for _, val := range vals[1:] {
+ dst = strconv.AppendUint(append(dst, ','), uint64(val), 10)
+ }
+ }
+ dst = append(dst, ']')
+ return dst
+}
+
+// AppendUint32 converts the input uint32 to a string and
+// appends the encoded string to the input byte slice.
+func (Encoder) AppendUint32(dst []byte, val uint32) []byte {
+ return strconv.AppendUint(dst, uint64(val), 10)
+}
+
+// AppendUints32 encodes the input uint32s to json and
+// appends the encoded string list to the input byte slice.
+func (Encoder) AppendUints32(dst []byte, vals []uint32) []byte {
+ if len(vals) == 0 {
+ return append(dst, '[', ']')
+ }
+ dst = append(dst, '[')
+ dst = strconv.AppendUint(dst, uint64(vals[0]), 10)
+ if len(vals) > 1 {
+ for _, val := range vals[1:] {
+ dst = strconv.AppendUint(append(dst, ','), uint64(val), 10)
+ }
+ }
+ dst = append(dst, ']')
+ return dst
+}
+
+// AppendUint64 converts the input uint64 to a string and
+// appends the encoded string to the input byte slice.
+func (Encoder) AppendUint64(dst []byte, val uint64) []byte {
+ return strconv.AppendUint(dst, val, 10)
+}
+
+// AppendUints64 encodes the input uint64s to json and
+// appends the encoded string list to the input byte slice.
+func (Encoder) AppendUints64(dst []byte, vals []uint64) []byte {
+ if len(vals) == 0 {
+ return append(dst, '[', ']')
+ }
+ dst = append(dst, '[')
+ dst = strconv.AppendUint(dst, vals[0], 10)
+ if len(vals) > 1 {
+ for _, val := range vals[1:] {
+ dst = strconv.AppendUint(append(dst, ','), val, 10)
+ }
+ }
+ dst = append(dst, ']')
+ return dst
+}
+
+func appendFloat(dst []byte, val float64, bitSize, precision int) []byte {
+ // JSON does not permit NaN or Infinity. A typical JSON encoder would fail
+ // with an error, but a logging library wants the data to get through so we
+ // make a tradeoff and store those types as string.
+ switch {
+ case math.IsNaN(val):
+ return append(dst, `"NaN"`...)
+ case math.IsInf(val, 1):
+ return append(dst, `"+Inf"`...)
+ case math.IsInf(val, -1):
+ return append(dst, `"-Inf"`...)
+ }
+ // convert as if by es6 number to string conversion
+ // see also https://cs.opensource.google/go/go/+/refs/tags/go1.20.3:src/encoding/json/encode.go;l=573
+ strFmt := byte('f')
+ // If precision is set to a value other than -1, we always just format the float using that precision.
+ if precision == -1 {
+ // Use float32 comparisons for underlying float32 value to get precise cutoffs right.
+ if abs := math.Abs(val); abs != 0 {
+ if bitSize == 64 && (abs < 1e-6 || abs >= 1e21) || bitSize == 32 && (float32(abs) < 1e-6 || float32(abs) >= 1e21) {
+ strFmt = 'e'
+ }
+ }
+ }
+ dst = strconv.AppendFloat(dst, val, strFmt, precision, bitSize)
+ if strFmt == 'e' {
+ // Clean up e-09 to e-9
+ n := len(dst)
+ if n >= 4 && dst[n-4] == 'e' && dst[n-3] == '-' && dst[n-2] == '0' {
+ dst[n-2] = dst[n-1]
+ dst = dst[:n-1]
+ }
+ }
+ return dst
+}
+
+// AppendFloat32 converts the input float32 to a string and
+// appends the encoded string to the input byte slice.
+func (Encoder) AppendFloat32(dst []byte, val float32, precision int) []byte {
+ return appendFloat(dst, float64(val), 32, precision)
+}
+
+// AppendFloats32 encodes the input float32s to json and
+// appends the encoded string list to the input byte slice.
+func (Encoder) AppendFloats32(dst []byte, vals []float32, precision int) []byte {
+ if len(vals) == 0 {
+ return append(dst, '[', ']')
+ }
+ dst = append(dst, '[')
+ dst = appendFloat(dst, float64(vals[0]), 32, precision)
+ if len(vals) > 1 {
+ for _, val := range vals[1:] {
+ dst = appendFloat(append(dst, ','), float64(val), 32, precision)
+ }
+ }
+ dst = append(dst, ']')
+ return dst
+}
+
+// AppendFloat64 converts the input float64 to a string and
+// appends the encoded string to the input byte slice.
+func (Encoder) AppendFloat64(dst []byte, val float64, precision int) []byte {
+ return appendFloat(dst, val, 64, precision)
+}
+
+// AppendFloats64 encodes the input float64s to json and
+// appends the encoded string list to the input byte slice.
+func (Encoder) AppendFloats64(dst []byte, vals []float64, precision int) []byte {
+ if len(vals) == 0 {
+ return append(dst, '[', ']')
+ }
+ dst = append(dst, '[')
+ dst = appendFloat(dst, vals[0], 64, precision)
+ if len(vals) > 1 {
+ for _, val := range vals[1:] {
+ dst = appendFloat(append(dst, ','), val, 64, precision)
+ }
+ }
+ dst = append(dst, ']')
+ return dst
+}
+
+// AppendInterface marshals the input interface to a string and
+// appends the encoded string to the input byte slice.
+func (e Encoder) AppendInterface(dst []byte, i interface{}) []byte {
+ marshaled, err := JSONMarshalFunc(i)
+ if err != nil {
+ return e.AppendString(dst, fmt.Sprintf("marshaling error: %v", err))
+ }
+ return append(dst, marshaled...)
+}
+
+// AppendType appends the parameter type (as a string) to the input byte slice.
+func (e Encoder) AppendType(dst []byte, i interface{}) []byte {
+ if i == nil {
+ return e.AppendString(dst, "")
+ }
+ return e.AppendString(dst, reflect.TypeOf(i).String())
+}
+
+// AppendObjectData takes in an object that is already in a byte array
+// and adds it to the dst.
+func (Encoder) AppendObjectData(dst []byte, o []byte) []byte {
+ // Three conditions apply here:
+ // 1. new content starts with '{' - which should be dropped OR
+ // 2. new content starts with '{' - which should be replaced with ','
+ // to separate with existing content OR
+ // 3. existing content has already other fields
+ if o[0] == '{' {
+ if len(dst) > 1 {
+ dst = append(dst, ',')
+ }
+ o = o[1:]
+ } else if len(dst) > 1 {
+ dst = append(dst, ',')
+ }
+ return append(dst, o...)
+}
+
+// AppendIPAddr adds IPv4 or IPv6 address to dst.
+func (e Encoder) AppendIPAddr(dst []byte, ip net.IP) []byte {
+ return e.AppendString(dst, ip.String())
+}
+
+// AppendIPPrefix adds IPv4 or IPv6 Prefix (address & mask) to dst.
+func (e Encoder) AppendIPPrefix(dst []byte, pfx net.IPNet) []byte {
+ return e.AppendString(dst, pfx.String())
+
+}
+
+// AppendMACAddr adds MAC address to dst.
+func (e Encoder) AppendMACAddr(dst []byte, ha net.HardwareAddr) []byte {
+ return e.AppendString(dst, ha.String())
+}
diff --git a/vendor/github.com/rs/zerolog/log.go b/vendor/github.com/rs/zerolog/log.go
new file mode 100644
index 0000000..6c1d4ea
--- /dev/null
+++ b/vendor/github.com/rs/zerolog/log.go
@@ -0,0 +1,518 @@
+// Package zerolog provides a lightweight logging library dedicated to JSON logging.
+//
+// A global Logger can be use for simple logging:
+//
+// import "github.com/rs/zerolog/log"
+//
+// log.Info().Msg("hello world")
+// // Output: {"time":1494567715,"level":"info","message":"hello world"}
+//
+// NOTE: To import the global logger, import the "log" subpackage "github.com/rs/zerolog/log".
+//
+// Fields can be added to log messages:
+//
+// log.Info().Str("foo", "bar").Msg("hello world")
+// // Output: {"time":1494567715,"level":"info","message":"hello world","foo":"bar"}
+//
+// Create logger instance to manage different outputs:
+//
+// logger := zerolog.New(os.Stderr).With().Timestamp().Logger()
+// logger.Info().
+// Str("foo", "bar").
+// Msg("hello world")
+// // Output: {"time":1494567715,"level":"info","message":"hello world","foo":"bar"}
+//
+// Sub-loggers let you chain loggers with additional context:
+//
+// sublogger := log.With().Str("component", "foo").Logger()
+// sublogger.Info().Msg("hello world")
+// // Output: {"time":1494567715,"level":"info","message":"hello world","component":"foo"}
+//
+// Level logging
+//
+// zerolog.SetGlobalLevel(zerolog.InfoLevel)
+//
+// log.Debug().Msg("filtered out message")
+// log.Info().Msg("routed message")
+//
+// if e := log.Debug(); e.Enabled() {
+// // Compute log output only if enabled.
+// value := compute()
+// e.Str("foo": value).Msg("some debug message")
+// }
+// // Output: {"level":"info","time":1494567715,"routed message"}
+//
+// Customize automatic field names:
+//
+// log.TimestampFieldName = "t"
+// log.LevelFieldName = "p"
+// log.MessageFieldName = "m"
+//
+// log.Info().Msg("hello world")
+// // Output: {"t":1494567715,"p":"info","m":"hello world"}
+//
+// Log with no level and message:
+//
+// log.Log().Str("foo","bar").Msg("")
+// // Output: {"time":1494567715,"foo":"bar"}
+//
+// Add contextual fields to global Logger:
+//
+// log.Logger = log.With().Str("foo", "bar").Logger()
+//
+// Sample logs:
+//
+// sampled := log.Sample(&zerolog.BasicSampler{N: 10})
+// sampled.Info().Msg("will be logged every 10 messages")
+//
+// Log with contextual hooks:
+//
+// // Create the hook:
+// type SeverityHook struct{}
+//
+// func (h SeverityHook) Run(e *zerolog.Event, level zerolog.Level, msg string) {
+// if level != zerolog.NoLevel {
+// e.Str("severity", level.String())
+// }
+// }
+//
+// // And use it:
+// var h SeverityHook
+// log := zerolog.New(os.Stdout).Hook(h)
+// log.Warn().Msg("")
+// // Output: {"level":"warn","severity":"warn"}
+//
+// # Caveats
+//
+// Field duplication:
+//
+// There is no fields deduplication out-of-the-box.
+// Using the same key multiple times creates new key in final JSON each time.
+//
+// logger := zerolog.New(os.Stderr).With().Timestamp().Logger()
+// logger.Info().
+// Timestamp().
+// Msg("dup")
+// // Output: {"level":"info","time":1494567715,"time":1494567715,"message":"dup"}
+//
+// In this case, many consumers will take the last value,
+// but this is not guaranteed; check yours if in doubt.
+//
+// Concurrency safety:
+//
+// Be careful when calling UpdateContext. It is not concurrency safe. Use the With method to create a child logger:
+//
+// func handler(w http.ResponseWriter, r *http.Request) {
+// // Create a child logger for concurrency safety
+// logger := log.Logger.With().Logger()
+//
+// // Add context fields, for example User-Agent from HTTP headers
+// logger.UpdateContext(func(c zerolog.Context) zerolog.Context {
+// ...
+// })
+// }
+package zerolog
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "io"
+ "os"
+ "strconv"
+ "strings"
+)
+
+// Level defines log levels.
+type Level int8
+
+const (
+ // DebugLevel defines debug log level.
+ DebugLevel Level = iota
+ // InfoLevel defines info log level.
+ InfoLevel
+ // WarnLevel defines warn log level.
+ WarnLevel
+ // ErrorLevel defines error log level.
+ ErrorLevel
+ // FatalLevel defines fatal log level.
+ FatalLevel
+ // PanicLevel defines panic log level.
+ PanicLevel
+ // NoLevel defines an absent log level.
+ NoLevel
+ // Disabled disables the logger.
+ Disabled
+
+ // TraceLevel defines trace log level.
+ TraceLevel Level = -1
+ // Values less than TraceLevel are handled as numbers.
+)
+
+func (l Level) String() string {
+ switch l {
+ case TraceLevel:
+ return LevelTraceValue
+ case DebugLevel:
+ return LevelDebugValue
+ case InfoLevel:
+ return LevelInfoValue
+ case WarnLevel:
+ return LevelWarnValue
+ case ErrorLevel:
+ return LevelErrorValue
+ case FatalLevel:
+ return LevelFatalValue
+ case PanicLevel:
+ return LevelPanicValue
+ case Disabled:
+ return "disabled"
+ case NoLevel:
+ return ""
+ }
+ return strconv.Itoa(int(l))
+}
+
+// ParseLevel converts a level string into a zerolog Level value.
+// returns an error if the input string does not match known values.
+func ParseLevel(levelStr string) (Level, error) {
+ switch {
+ case strings.EqualFold(levelStr, LevelFieldMarshalFunc(TraceLevel)):
+ return TraceLevel, nil
+ case strings.EqualFold(levelStr, LevelFieldMarshalFunc(DebugLevel)):
+ return DebugLevel, nil
+ case strings.EqualFold(levelStr, LevelFieldMarshalFunc(InfoLevel)):
+ return InfoLevel, nil
+ case strings.EqualFold(levelStr, LevelFieldMarshalFunc(WarnLevel)):
+ return WarnLevel, nil
+ case strings.EqualFold(levelStr, LevelFieldMarshalFunc(ErrorLevel)):
+ return ErrorLevel, nil
+ case strings.EqualFold(levelStr, LevelFieldMarshalFunc(FatalLevel)):
+ return FatalLevel, nil
+ case strings.EqualFold(levelStr, LevelFieldMarshalFunc(PanicLevel)):
+ return PanicLevel, nil
+ case strings.EqualFold(levelStr, LevelFieldMarshalFunc(Disabled)):
+ return Disabled, nil
+ case strings.EqualFold(levelStr, LevelFieldMarshalFunc(NoLevel)):
+ return NoLevel, nil
+ }
+ i, err := strconv.Atoi(levelStr)
+ if err != nil {
+ return NoLevel, fmt.Errorf("Unknown Level String: '%s', defaulting to NoLevel", levelStr)
+ }
+ if i > 127 || i < -128 {
+ return NoLevel, fmt.Errorf("Out-Of-Bounds Level: '%d', defaulting to NoLevel", i)
+ }
+ return Level(i), nil
+}
+
+// UnmarshalText implements encoding.TextUnmarshaler to allow for easy reading from toml/yaml/json formats
+func (l *Level) UnmarshalText(text []byte) error {
+ if l == nil {
+ return errors.New("can't unmarshal a nil *Level")
+ }
+ var err error
+ *l, err = ParseLevel(string(text))
+ return err
+}
+
+// MarshalText implements encoding.TextMarshaler to allow for easy writing into toml/yaml/json formats
+func (l Level) MarshalText() ([]byte, error) {
+ return []byte(LevelFieldMarshalFunc(l)), nil
+}
+
+// A Logger represents an active logging object that generates lines
+// of JSON output to an io.Writer. Each logging operation makes a single
+// call to the Writer's Write method. There is no guarantee on access
+// serialization to the Writer. If your Writer is not thread safe,
+// you may consider a sync wrapper.
+type Logger struct {
+ w LevelWriter
+ level Level
+ sampler Sampler
+ context []byte
+ hooks []Hook
+ stack bool
+ ctx context.Context
+}
+
+// New creates a root logger with given output writer. If the output writer implements
+// the LevelWriter interface, the WriteLevel method will be called instead of the Write
+// one.
+//
+// Each logging operation makes a single call to the Writer's Write method. There is no
+// guarantee on access serialization to the Writer. If your Writer is not thread safe,
+// you may consider using sync wrapper.
+func New(w io.Writer) Logger {
+ if w == nil {
+ w = io.Discard
+ }
+ lw, ok := w.(LevelWriter)
+ if !ok {
+ lw = LevelWriterAdapter{w}
+ }
+ return Logger{w: lw, level: TraceLevel}
+}
+
+// Nop returns a disabled logger for which all operation are no-op.
+func Nop() Logger {
+ return New(nil).Level(Disabled)
+}
+
+// Output duplicates the current logger and sets w as its output.
+func (l Logger) Output(w io.Writer) Logger {
+ l2 := New(w)
+ l2.level = l.level
+ l2.sampler = l.sampler
+ l2.stack = l.stack
+ if len(l.hooks) > 0 {
+ l2.hooks = append(l2.hooks, l.hooks...)
+ }
+ if l.context != nil {
+ l2.context = make([]byte, len(l.context), cap(l.context))
+ copy(l2.context, l.context)
+ }
+ return l2
+}
+
+// With creates a child logger with the field added to its context.
+func (l Logger) With() Context {
+ context := l.context
+ l.context = make([]byte, 0, 500)
+ if context != nil {
+ l.context = append(l.context, context...)
+ } else {
+ // This is needed for AppendKey to not check len of input
+ // thus making it inlinable
+ l.context = enc.AppendBeginMarker(l.context)
+ }
+ return Context{l}
+}
+
+// UpdateContext updates the internal logger's context.
+//
+// Caution: This method is not concurrency safe.
+// Use the With method to create a child logger before modifying the context from concurrent goroutines.
+func (l *Logger) UpdateContext(update func(c Context) Context) {
+ if l == disabledLogger {
+ return
+ }
+ if cap(l.context) == 0 {
+ l.context = make([]byte, 0, 500)
+ }
+ if len(l.context) == 0 {
+ l.context = enc.AppendBeginMarker(l.context)
+ }
+ c := update(Context{*l})
+ l.context = c.l.context
+}
+
+// Level creates a child logger with the minimum accepted level set to level.
+func (l Logger) Level(lvl Level) Logger {
+ l.level = lvl
+ return l
+}
+
+// GetLevel returns the current Level of l.
+func (l Logger) GetLevel() Level {
+ return l.level
+}
+
+// Sample returns a logger with the s sampler.
+func (l Logger) Sample(s Sampler) Logger {
+ l.sampler = s
+ return l
+}
+
+// Hook returns a logger with the h Hook.
+func (l Logger) Hook(hooks ...Hook) Logger {
+ if len(hooks) == 0 {
+ return l
+ }
+ newHooks := make([]Hook, len(l.hooks), len(l.hooks)+len(hooks))
+ copy(newHooks, l.hooks)
+ l.hooks = append(newHooks, hooks...)
+ return l
+}
+
+// Trace starts a new message with trace level.
+//
+// You must call Msg on the returned event in order to send the event.
+func (l *Logger) Trace() *Event {
+ return l.newEvent(TraceLevel, nil)
+}
+
+// Debug starts a new message with debug level.
+//
+// You must call Msg on the returned event in order to send the event.
+func (l *Logger) Debug() *Event {
+ return l.newEvent(DebugLevel, nil)
+}
+
+// Info starts a new message with info level.
+//
+// You must call Msg on the returned event in order to send the event.
+func (l *Logger) Info() *Event {
+ return l.newEvent(InfoLevel, nil)
+}
+
+// Warn starts a new message with warn level.
+//
+// You must call Msg on the returned event in order to send the event.
+func (l *Logger) Warn() *Event {
+ return l.newEvent(WarnLevel, nil)
+}
+
+// Error starts a new message with error level.
+//
+// You must call Msg on the returned event in order to send the event.
+func (l *Logger) Error() *Event {
+ return l.newEvent(ErrorLevel, nil)
+}
+
+// Err starts a new message with error level with err as a field if not nil or
+// with info level if err is nil.
+//
+// You must call Msg on the returned event in order to send the event.
+func (l *Logger) Err(err error) *Event {
+ if err != nil {
+ return l.Error().Err(err)
+ }
+
+ return l.Info()
+}
+
+// Fatal starts a new message with fatal level. The os.Exit(1) function
+// is called by the Msg method, which terminates the program immediately.
+//
+// You must call Msg on the returned event in order to send the event.
+func (l *Logger) Fatal() *Event {
+ return l.newEvent(FatalLevel, func(msg string) {
+ if closer, ok := l.w.(io.Closer); ok {
+ // Close the writer to flush any buffered message. Otherwise the message
+ // will be lost as os.Exit() terminates the program immediately.
+ closer.Close()
+ }
+ os.Exit(1)
+ })
+}
+
+// Panic starts a new message with panic level. The panic() function
+// is called by the Msg method, which stops the ordinary flow of a goroutine.
+//
+// You must call Msg on the returned event in order to send the event.
+func (l *Logger) Panic() *Event {
+ return l.newEvent(PanicLevel, func(msg string) { panic(msg) })
+}
+
+// WithLevel starts a new message with level. Unlike Fatal and Panic
+// methods, WithLevel does not terminate the program or stop the ordinary
+// flow of a goroutine when used with their respective levels.
+//
+// You must call Msg on the returned event in order to send the event.
+func (l *Logger) WithLevel(level Level) *Event {
+ switch level {
+ case TraceLevel:
+ return l.Trace()
+ case DebugLevel:
+ return l.Debug()
+ case InfoLevel:
+ return l.Info()
+ case WarnLevel:
+ return l.Warn()
+ case ErrorLevel:
+ return l.Error()
+ case FatalLevel:
+ return l.newEvent(FatalLevel, nil)
+ case PanicLevel:
+ return l.newEvent(PanicLevel, nil)
+ case NoLevel:
+ return l.Log()
+ case Disabled:
+ return nil
+ default:
+ return l.newEvent(level, nil)
+ }
+}
+
+// Log starts a new message with no level. Setting GlobalLevel to Disabled
+// will still disable events produced by this method.
+//
+// You must call Msg on the returned event in order to send the event.
+func (l *Logger) Log() *Event {
+ return l.newEvent(NoLevel, nil)
+}
+
+// Print sends a log event using debug level and no extra field.
+// Arguments are handled in the manner of fmt.Print.
+func (l *Logger) Print(v ...interface{}) {
+ if e := l.Debug(); e.Enabled() {
+ e.CallerSkipFrame(1).Msg(fmt.Sprint(v...))
+ }
+}
+
+// Printf sends a log event using debug level and no extra field.
+// Arguments are handled in the manner of fmt.Printf.
+func (l *Logger) Printf(format string, v ...interface{}) {
+ if e := l.Debug(); e.Enabled() {
+ e.CallerSkipFrame(1).Msg(fmt.Sprintf(format, v...))
+ }
+}
+
+// Println sends a log event using debug level and no extra field.
+// Arguments are handled in the manner of fmt.Println.
+func (l *Logger) Println(v ...interface{}) {
+ if e := l.Debug(); e.Enabled() {
+ e.CallerSkipFrame(1).Msg(fmt.Sprintln(v...))
+ }
+}
+
+// Write implements the io.Writer interface. This is useful to set as a writer
+// for the standard library log.
+func (l Logger) Write(p []byte) (n int, err error) {
+ n = len(p)
+ if n > 0 && p[n-1] == '\n' {
+ // Trim CR added by stdlog.
+ p = p[0 : n-1]
+ }
+ l.Log().CallerSkipFrame(1).Msg(string(p))
+ return
+}
+
+func (l *Logger) newEvent(level Level, done func(string)) *Event {
+ enabled := l.should(level)
+ if !enabled {
+ if done != nil {
+ done("")
+ }
+ return nil
+ }
+ e := newEvent(l.w, level)
+ e.done = done
+ e.ch = l.hooks
+ e.ctx = l.ctx
+ if level != NoLevel && LevelFieldName != "" {
+ e.Str(LevelFieldName, LevelFieldMarshalFunc(level))
+ }
+ if l.context != nil && len(l.context) > 1 {
+ e.buf = enc.AppendObjectData(e.buf, l.context)
+ }
+ if l.stack {
+ e.Stack()
+ }
+ return e
+}
+
+// should returns true if the log event should be logged.
+func (l *Logger) should(lvl Level) bool {
+ if l.w == nil {
+ return false
+ }
+ if lvl < l.level || lvl < GlobalLevel() {
+ return false
+ }
+ if l.sampler != nil && !samplingDisabled() {
+ return l.sampler.Sample(lvl)
+ }
+ return true
+}
diff --git a/vendor/github.com/rs/zerolog/not_go112.go b/vendor/github.com/rs/zerolog/not_go112.go
new file mode 100644
index 0000000..4c43c9e
--- /dev/null
+++ b/vendor/github.com/rs/zerolog/not_go112.go
@@ -0,0 +1,5 @@
+// +build !go1.12
+
+package zerolog
+
+const contextCallerSkipFrameCount = 3
diff --git a/vendor/github.com/rs/zerolog/pretty.png b/vendor/github.com/rs/zerolog/pretty.png
new file mode 100644
index 0000000..1449e45
Binary files /dev/null and b/vendor/github.com/rs/zerolog/pretty.png differ
diff --git a/vendor/github.com/rs/zerolog/sampler.go b/vendor/github.com/rs/zerolog/sampler.go
new file mode 100644
index 0000000..83ce2ed
--- /dev/null
+++ b/vendor/github.com/rs/zerolog/sampler.go
@@ -0,0 +1,134 @@
+package zerolog
+
+import (
+ "math/rand"
+ "sync/atomic"
+ "time"
+)
+
+var (
+ // Often samples log every ~ 10 events.
+ Often = RandomSampler(10)
+ // Sometimes samples log every ~ 100 events.
+ Sometimes = RandomSampler(100)
+ // Rarely samples log every ~ 1000 events.
+ Rarely = RandomSampler(1000)
+)
+
+// Sampler defines an interface to a log sampler.
+type Sampler interface {
+ // Sample returns true if the event should be part of the sample, false if
+ // the event should be dropped.
+ Sample(lvl Level) bool
+}
+
+// RandomSampler use a PRNG to randomly sample an event out of N events,
+// regardless of their level.
+type RandomSampler uint32
+
+// Sample implements the Sampler interface.
+func (s RandomSampler) Sample(lvl Level) bool {
+ if s <= 0 {
+ return false
+ }
+ if rand.Intn(int(s)) != 0 {
+ return false
+ }
+ return true
+}
+
+// BasicSampler is a sampler that will send every Nth events, regardless of
+// their level.
+type BasicSampler struct {
+ N uint32
+ counter uint32
+}
+
+// Sample implements the Sampler interface.
+func (s *BasicSampler) Sample(lvl Level) bool {
+ n := s.N
+ if n == 1 {
+ return true
+ }
+ c := atomic.AddUint32(&s.counter, 1)
+ return c%n == 1
+}
+
+// BurstSampler lets Burst events pass per Period then pass the decision to
+// NextSampler. If Sampler is not set, all subsequent events are rejected.
+type BurstSampler struct {
+ // Burst is the maximum number of event per period allowed before calling
+ // NextSampler.
+ Burst uint32
+ // Period defines the burst period. If 0, NextSampler is always called.
+ Period time.Duration
+ // NextSampler is the sampler used after the burst is reached. If nil,
+ // events are always rejected after the burst.
+ NextSampler Sampler
+
+ counter uint32
+ resetAt int64
+}
+
+// Sample implements the Sampler interface.
+func (s *BurstSampler) Sample(lvl Level) bool {
+ if s.Burst > 0 && s.Period > 0 {
+ if s.inc() <= s.Burst {
+ return true
+ }
+ }
+ if s.NextSampler == nil {
+ return false
+ }
+ return s.NextSampler.Sample(lvl)
+}
+
+func (s *BurstSampler) inc() uint32 {
+ now := TimestampFunc().UnixNano()
+ resetAt := atomic.LoadInt64(&s.resetAt)
+ var c uint32
+ if now > resetAt {
+ c = 1
+ atomic.StoreUint32(&s.counter, c)
+ newResetAt := now + s.Period.Nanoseconds()
+ reset := atomic.CompareAndSwapInt64(&s.resetAt, resetAt, newResetAt)
+ if !reset {
+ // Lost the race with another goroutine trying to reset.
+ c = atomic.AddUint32(&s.counter, 1)
+ }
+ } else {
+ c = atomic.AddUint32(&s.counter, 1)
+ }
+ return c
+}
+
+// LevelSampler applies a different sampler for each level.
+type LevelSampler struct {
+ TraceSampler, DebugSampler, InfoSampler, WarnSampler, ErrorSampler Sampler
+}
+
+func (s LevelSampler) Sample(lvl Level) bool {
+ switch lvl {
+ case TraceLevel:
+ if s.TraceSampler != nil {
+ return s.TraceSampler.Sample(lvl)
+ }
+ case DebugLevel:
+ if s.DebugSampler != nil {
+ return s.DebugSampler.Sample(lvl)
+ }
+ case InfoLevel:
+ if s.InfoSampler != nil {
+ return s.InfoSampler.Sample(lvl)
+ }
+ case WarnLevel:
+ if s.WarnSampler != nil {
+ return s.WarnSampler.Sample(lvl)
+ }
+ case ErrorLevel:
+ if s.ErrorSampler != nil {
+ return s.ErrorSampler.Sample(lvl)
+ }
+ }
+ return true
+}
diff --git a/vendor/github.com/rs/zerolog/syslog.go b/vendor/github.com/rs/zerolog/syslog.go
new file mode 100644
index 0000000..a2b7285
--- /dev/null
+++ b/vendor/github.com/rs/zerolog/syslog.go
@@ -0,0 +1,89 @@
+// +build !windows
+// +build !binary_log
+
+package zerolog
+
+import (
+ "io"
+)
+
+// See http://cee.mitre.org/language/1.0-beta1/clt.html#syslog
+// or https://www.rsyslog.com/json-elasticsearch/
+const ceePrefix = "@cee:"
+
+// SyslogWriter is an interface matching a syslog.Writer struct.
+type SyslogWriter interface {
+ io.Writer
+ Debug(m string) error
+ Info(m string) error
+ Warning(m string) error
+ Err(m string) error
+ Emerg(m string) error
+ Crit(m string) error
+}
+
+type syslogWriter struct {
+ w SyslogWriter
+ prefix string
+}
+
+// SyslogLevelWriter wraps a SyslogWriter and call the right syslog level
+// method matching the zerolog level.
+func SyslogLevelWriter(w SyslogWriter) LevelWriter {
+ return syslogWriter{w, ""}
+}
+
+// SyslogCEEWriter wraps a SyslogWriter with a SyslogLevelWriter that adds a
+// MITRE CEE prefix for JSON syslog entries, compatible with rsyslog
+// and syslog-ng JSON logging support.
+// See https://www.rsyslog.com/json-elasticsearch/
+func SyslogCEEWriter(w SyslogWriter) LevelWriter {
+ return syslogWriter{w, ceePrefix}
+}
+
+func (sw syslogWriter) Write(p []byte) (n int, err error) {
+ var pn int
+ if sw.prefix != "" {
+ pn, err = sw.w.Write([]byte(sw.prefix))
+ if err != nil {
+ return pn, err
+ }
+ }
+ n, err = sw.w.Write(p)
+ return pn + n, err
+}
+
+// WriteLevel implements LevelWriter interface.
+func (sw syslogWriter) WriteLevel(level Level, p []byte) (n int, err error) {
+ switch level {
+ case TraceLevel:
+ case DebugLevel:
+ err = sw.w.Debug(sw.prefix + string(p))
+ case InfoLevel:
+ err = sw.w.Info(sw.prefix + string(p))
+ case WarnLevel:
+ err = sw.w.Warning(sw.prefix + string(p))
+ case ErrorLevel:
+ err = sw.w.Err(sw.prefix + string(p))
+ case FatalLevel:
+ err = sw.w.Emerg(sw.prefix + string(p))
+ case PanicLevel:
+ err = sw.w.Crit(sw.prefix + string(p))
+ case NoLevel:
+ err = sw.w.Info(sw.prefix + string(p))
+ default:
+ panic("invalid level")
+ }
+ // Any CEE prefix is not part of the message, so we don't include its length
+ n = len(p)
+ return
+}
+
+// Call the underlying writer's Close method if it is an io.Closer. Otherwise
+// does nothing.
+func (sw syslogWriter) Close() error {
+ if c, ok := sw.w.(io.Closer); ok {
+ return c.Close()
+ }
+ return nil
+}
diff --git a/vendor/github.com/rs/zerolog/writer.go b/vendor/github.com/rs/zerolog/writer.go
new file mode 100644
index 0000000..41b394d
--- /dev/null
+++ b/vendor/github.com/rs/zerolog/writer.go
@@ -0,0 +1,346 @@
+package zerolog
+
+import (
+ "bytes"
+ "io"
+ "path"
+ "runtime"
+ "strconv"
+ "strings"
+ "sync"
+)
+
+// LevelWriter defines as interface a writer may implement in order
+// to receive level information with payload.
+type LevelWriter interface {
+ io.Writer
+ WriteLevel(level Level, p []byte) (n int, err error)
+}
+
+// LevelWriterAdapter adapts an io.Writer to support the LevelWriter interface.
+type LevelWriterAdapter struct {
+ io.Writer
+}
+
+// WriteLevel simply writes everything to the adapted writer, ignoring the level.
+func (lw LevelWriterAdapter) WriteLevel(l Level, p []byte) (n int, err error) {
+ return lw.Write(p)
+}
+
+// Call the underlying writer's Close method if it is an io.Closer. Otherwise
+// does nothing.
+func (lw LevelWriterAdapter) Close() error {
+ if closer, ok := lw.Writer.(io.Closer); ok {
+ return closer.Close()
+ }
+ return nil
+}
+
+type syncWriter struct {
+ mu sync.Mutex
+ lw LevelWriter
+}
+
+// SyncWriter wraps w so that each call to Write is synchronized with a mutex.
+// This syncer can be used to wrap the call to writer's Write method if it is
+// not thread safe. Note that you do not need this wrapper for os.File Write
+// operations on POSIX and Windows systems as they are already thread-safe.
+func SyncWriter(w io.Writer) io.Writer {
+ if lw, ok := w.(LevelWriter); ok {
+ return &syncWriter{lw: lw}
+ }
+ return &syncWriter{lw: LevelWriterAdapter{w}}
+}
+
+// Write implements the io.Writer interface.
+func (s *syncWriter) Write(p []byte) (n int, err error) {
+ s.mu.Lock()
+ defer s.mu.Unlock()
+ return s.lw.Write(p)
+}
+
+// WriteLevel implements the LevelWriter interface.
+func (s *syncWriter) WriteLevel(l Level, p []byte) (n int, err error) {
+ s.mu.Lock()
+ defer s.mu.Unlock()
+ return s.lw.WriteLevel(l, p)
+}
+
+func (s *syncWriter) Close() error {
+ s.mu.Lock()
+ defer s.mu.Unlock()
+ if closer, ok := s.lw.(io.Closer); ok {
+ return closer.Close()
+ }
+ return nil
+}
+
+type multiLevelWriter struct {
+ writers []LevelWriter
+}
+
+func (t multiLevelWriter) Write(p []byte) (n int, err error) {
+ for _, w := range t.writers {
+ if _n, _err := w.Write(p); err == nil {
+ n = _n
+ if _err != nil {
+ err = _err
+ } else if _n != len(p) {
+ err = io.ErrShortWrite
+ }
+ }
+ }
+ return n, err
+}
+
+func (t multiLevelWriter) WriteLevel(l Level, p []byte) (n int, err error) {
+ for _, w := range t.writers {
+ if _n, _err := w.WriteLevel(l, p); err == nil {
+ n = _n
+ if _err != nil {
+ err = _err
+ } else if _n != len(p) {
+ err = io.ErrShortWrite
+ }
+ }
+ }
+ return n, err
+}
+
+// Calls close on all the underlying writers that are io.Closers. If any of the
+// Close methods return an error, the remainder of the closers are not closed
+// and the error is returned.
+func (t multiLevelWriter) Close() error {
+ for _, w := range t.writers {
+ if closer, ok := w.(io.Closer); ok {
+ if err := closer.Close(); err != nil {
+ return err
+ }
+ }
+ }
+ return nil
+}
+
+// MultiLevelWriter creates a writer that duplicates its writes to all the
+// provided writers, similar to the Unix tee(1) command. If some writers
+// implement LevelWriter, their WriteLevel method will be used instead of Write.
+func MultiLevelWriter(writers ...io.Writer) LevelWriter {
+ lwriters := make([]LevelWriter, 0, len(writers))
+ for _, w := range writers {
+ if lw, ok := w.(LevelWriter); ok {
+ lwriters = append(lwriters, lw)
+ } else {
+ lwriters = append(lwriters, LevelWriterAdapter{w})
+ }
+ }
+ return multiLevelWriter{lwriters}
+}
+
+// TestingLog is the logging interface of testing.TB.
+type TestingLog interface {
+ Log(args ...interface{})
+ Logf(format string, args ...interface{})
+ Helper()
+}
+
+// TestWriter is a writer that writes to testing.TB.
+type TestWriter struct {
+ T TestingLog
+
+ // Frame skips caller frames to capture the original file and line numbers.
+ Frame int
+}
+
+// NewTestWriter creates a writer that logs to the testing.TB.
+func NewTestWriter(t TestingLog) TestWriter {
+ return TestWriter{T: t}
+}
+
+// Write to testing.TB.
+func (t TestWriter) Write(p []byte) (n int, err error) {
+ t.T.Helper()
+
+ n = len(p)
+
+ // Strip trailing newline because t.Log always adds one.
+ p = bytes.TrimRight(p, "\n")
+
+ // Try to correct the log file and line number to the caller.
+ if t.Frame > 0 {
+ _, origFile, origLine, _ := runtime.Caller(1)
+ _, frameFile, frameLine, ok := runtime.Caller(1 + t.Frame)
+ if ok {
+ erase := strings.Repeat("\b", len(path.Base(origFile))+len(strconv.Itoa(origLine))+3)
+ t.T.Logf("%s%s:%d: %s", erase, path.Base(frameFile), frameLine, p)
+ return n, err
+ }
+ }
+ t.T.Log(string(p))
+
+ return n, err
+}
+
+// ConsoleTestWriter creates an option that correctly sets the file frame depth for testing.TB log.
+func ConsoleTestWriter(t TestingLog) func(w *ConsoleWriter) {
+ return func(w *ConsoleWriter) {
+ w.Out = TestWriter{T: t, Frame: 6}
+ }
+}
+
+// FilteredLevelWriter writes only logs at Level or above to Writer.
+//
+// It should be used only in combination with MultiLevelWriter when you
+// want to write to multiple destinations at different levels. Otherwise
+// you should just set the level on the logger and filter events early.
+// When using MultiLevelWriter then you set the level on the logger to
+// the lowest of the levels you use for writers.
+type FilteredLevelWriter struct {
+ Writer LevelWriter
+ Level Level
+}
+
+// Write writes to the underlying Writer.
+func (w *FilteredLevelWriter) Write(p []byte) (int, error) {
+ return w.Writer.Write(p)
+}
+
+// WriteLevel calls WriteLevel of the underlying Writer only if the level is equal
+// or above the Level.
+func (w *FilteredLevelWriter) WriteLevel(level Level, p []byte) (int, error) {
+ if level >= w.Level {
+ return w.Writer.WriteLevel(level, p)
+ }
+ return len(p), nil
+}
+
+var triggerWriterPool = &sync.Pool{
+ New: func() interface{} {
+ return bytes.NewBuffer(make([]byte, 0, 1024))
+ },
+}
+
+// TriggerLevelWriter buffers log lines at the ConditionalLevel or below
+// until a trigger level (or higher) line is emitted. Log lines with level
+// higher than ConditionalLevel are always written out to the destination
+// writer. If trigger never happens, buffered log lines are never written out.
+//
+// It can be used to configure "log level per request".
+type TriggerLevelWriter struct {
+ // Destination writer. If LevelWriter is provided (usually), its WriteLevel is used
+ // instead of Write.
+ io.Writer
+
+ // ConditionalLevel is the level (and below) at which lines are buffered until
+ // a trigger level (or higher) line is emitted. Usually this is set to DebugLevel.
+ ConditionalLevel Level
+
+ // TriggerLevel is the lowest level that triggers the sending of the conditional
+ // level lines. Usually this is set to ErrorLevel.
+ TriggerLevel Level
+
+ buf *bytes.Buffer
+ triggered bool
+ mu sync.Mutex
+}
+
+func (w *TriggerLevelWriter) WriteLevel(l Level, p []byte) (n int, err error) {
+ w.mu.Lock()
+ defer w.mu.Unlock()
+
+ // At first trigger level or above log line, we flush the buffer and change the
+ // trigger state to triggered.
+ if !w.triggered && l >= w.TriggerLevel {
+ err := w.trigger()
+ if err != nil {
+ return 0, err
+ }
+ }
+
+ // Unless triggered, we buffer everything at and below ConditionalLevel.
+ if !w.triggered && l <= w.ConditionalLevel {
+ if w.buf == nil {
+ w.buf = triggerWriterPool.Get().(*bytes.Buffer)
+ }
+
+ // We prefix each log line with a byte with the level.
+ // Hopefully we will never have a level value which equals a newline
+ // (which could interfere with reconstruction of log lines in the trigger method).
+ w.buf.WriteByte(byte(l))
+ w.buf.Write(p)
+ return len(p), nil
+ }
+
+ // Anything above ConditionalLevel is always passed through.
+ // Once triggered, everything is passed through.
+ if lw, ok := w.Writer.(LevelWriter); ok {
+ return lw.WriteLevel(l, p)
+ }
+ return w.Write(p)
+}
+
+// trigger expects lock to be held.
+func (w *TriggerLevelWriter) trigger() error {
+ if w.triggered {
+ return nil
+ }
+ w.triggered = true
+
+ if w.buf == nil {
+ return nil
+ }
+
+ p := w.buf.Bytes()
+ for len(p) > 0 {
+ // We do not use bufio.Scanner here because we already have full buffer
+ // in the memory and we do not want extra copying from the buffer to
+ // scanner's token slice, nor we want to hit scanner's token size limit,
+ // and we also want to preserve newlines.
+ i := bytes.IndexByte(p, '\n')
+ line := p[0 : i+1]
+ p = p[i+1:]
+ // We prefixed each log line with a byte with the level.
+ level := Level(line[0])
+ line = line[1:]
+ var err error
+ if lw, ok := w.Writer.(LevelWriter); ok {
+ _, err = lw.WriteLevel(level, line)
+ } else {
+ _, err = w.Write(line)
+ }
+ if err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
+
+// Trigger forces flushing the buffer and change the trigger state to
+// triggered, if the writer has not already been triggered before.
+func (w *TriggerLevelWriter) Trigger() error {
+ w.mu.Lock()
+ defer w.mu.Unlock()
+
+ return w.trigger()
+}
+
+// Close closes the writer and returns the buffer to the pool.
+func (w *TriggerLevelWriter) Close() error {
+ w.mu.Lock()
+ defer w.mu.Unlock()
+
+ if w.buf == nil {
+ return nil
+ }
+
+ // We return the buffer only if it has not grown above the limit.
+ // This prevents accumulation of large buffers in the pool just
+ // because occasionally a large buffer might be needed.
+ if w.buf.Cap() <= TriggerLevelWriterBufferReuseLimit {
+ w.buf.Reset()
+ triggerWriterPool.Put(w.buf)
+ }
+ w.buf = nil
+
+ return nil
+}
diff --git a/vendor/github.com/savsgio/gotils/LICENSE b/vendor/github.com/savsgio/gotils/LICENSE
new file mode 100644
index 0000000..2b440ab
--- /dev/null
+++ b/vendor/github.com/savsgio/gotils/LICENSE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright 2020-present Sergio Andres Virviescas Santana
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/vendor/github.com/savsgio/gotils/strconv/strconv.go b/vendor/github.com/savsgio/gotils/strconv/strconv.go
new file mode 100644
index 0000000..be60dcc
--- /dev/null
+++ b/vendor/github.com/savsgio/gotils/strconv/strconv.go
@@ -0,0 +1,29 @@
+//go:build !go1.20
+// +build !go1.20
+
+package strconv
+
+import (
+ "reflect"
+ "unsafe"
+)
+
+// B2S converts byte slice to a string without memory allocation.
+// See https://groups.google.com/forum/#!msg/Golang-Nuts/ENgbUzYvCuU/90yGx7GUAgAJ .
+func B2S(b []byte) string {
+ return *(*string)(unsafe.Pointer(&b))
+}
+
+// S2B converts string to a byte slice without memory allocation.
+//
+// Note it may break if string and/or slice header will change
+// in the future go versions.
+func S2B(s string) (b []byte) {
+ sh := (*reflect.StringHeader)(unsafe.Pointer(&s))
+ bh := (*reflect.SliceHeader)(unsafe.Pointer(&b))
+ bh.Data = sh.Data
+ bh.Cap = sh.Len
+ bh.Len = sh.Len
+
+ return b
+}
diff --git a/vendor/github.com/savsgio/gotils/strconv/strconv_120.go b/vendor/github.com/savsgio/gotils/strconv/strconv_120.go
new file mode 100644
index 0000000..a25b6d5
--- /dev/null
+++ b/vendor/github.com/savsgio/gotils/strconv/strconv_120.go
@@ -0,0 +1,17 @@
+//go:build go1.20
+// +build go1.20
+
+package strconv
+
+import "unsafe"
+
+// B2S converts byte slice to a string without memory allocation.
+// See https://groups.google.com/forum/#!msg/Golang-Nuts/ENgbUzYvCuU/90yGx7GUAgAJ .
+func B2S(b []byte) string {
+ return unsafe.String(unsafe.SliceData(b), len(b))
+}
+
+// S2B converts string to a byte slice without memory allocation.
+func S2B(s string) []byte {
+ return unsafe.Slice(unsafe.StringData(s), len(s))
+}
diff --git a/vendor/github.com/tidwall/gjson/LICENSE b/vendor/github.com/tidwall/gjson/LICENSE
new file mode 100644
index 0000000..58f5819
--- /dev/null
+++ b/vendor/github.com/tidwall/gjson/LICENSE
@@ -0,0 +1,20 @@
+The MIT License (MIT)
+
+Copyright (c) 2016 Josh Baker
+
+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/tidwall/gjson/README.md b/vendor/github.com/tidwall/gjson/README.md
new file mode 100644
index 0000000..7701cae
--- /dev/null
+++ b/vendor/github.com/tidwall/gjson/README.md
@@ -0,0 +1,490 @@
+
+
+
+
+
+
+
+
+
+get json values quickly
+
+GJSON is a Go package that provides a [fast](#performance) and [simple](#get-a-value) way to get values from a json document.
+It has features such as [one line retrieval](#get-a-value), [dot notation paths](#path-syntax), [iteration](#iterate-through-an-object-or-array), and [parsing json lines](#json-lines).
+
+Also check out [SJSON](https://github.com/tidwall/sjson) for modifying json, and the [JJ](https://github.com/tidwall/jj) command line tool.
+
+This README is a quick overview of how to use GJSON, for more information check out [GJSON Syntax](SYNTAX.md).
+
+GJSON is also available for [Python](https://github.com/volans-/gjson-py) and [Rust](https://github.com/tidwall/gjson.rs)
+
+Getting Started
+===============
+
+## Installing
+
+To start using GJSON, install Go and run `go get`:
+
+```sh
+$ go get -u github.com/tidwall/gjson
+```
+
+This will retrieve the library.
+
+## Get a value
+Get searches json for the specified path. A path is in dot syntax, such as "name.last" or "age". When the value is found it's returned immediately.
+
+```go
+package main
+
+import "github.com/tidwall/gjson"
+
+const json = `{"name":{"first":"Janet","last":"Prichard"},"age":47}`
+
+func main() {
+ value := gjson.Get(json, "name.last")
+ println(value.String())
+}
+```
+
+This will print:
+
+```
+Prichard
+```
+*There's also the [GetMany](#get-multiple-values-at-once) function to get multiple values at once, and [GetBytes](#working-with-bytes) for working with JSON byte slices.*
+
+## Path Syntax
+
+Below is a quick overview of the path syntax, for more complete information please
+check out [GJSON Syntax](SYNTAX.md).
+
+A path is a series of keys separated by a dot.
+A key may contain special wildcard characters '\*' and '?'.
+To access an array value use the index as the key.
+To get the number of elements in an array or to access a child path, use the '#' character.
+The dot and wildcard characters can be escaped with '\\'.
+
+```json
+{
+ "name": {"first": "Tom", "last": "Anderson"},
+ "age":37,
+ "children": ["Sara","Alex","Jack"],
+ "fav.movie": "Deer Hunter",
+ "friends": [
+ {"first": "Dale", "last": "Murphy", "age": 44, "nets": ["ig", "fb", "tw"]},
+ {"first": "Roger", "last": "Craig", "age": 68, "nets": ["fb", "tw"]},
+ {"first": "Jane", "last": "Murphy", "age": 47, "nets": ["ig", "tw"]}
+ ]
+}
+```
+```
+"name.last" >> "Anderson"
+"age" >> 37
+"children" >> ["Sara","Alex","Jack"]
+"children.#" >> 3
+"children.1" >> "Alex"
+"child*.2" >> "Jack"
+"c?ildren.0" >> "Sara"
+"fav\.movie" >> "Deer Hunter"
+"friends.#.first" >> ["Dale","Roger","Jane"]
+"friends.1.last" >> "Craig"
+```
+
+You can also query an array for the first match by using `#(...)`, or find all
+matches with `#(...)#`. Queries support the `==`, `!=`, `<`, `<=`, `>`, `>=`
+comparison operators and the simple pattern matching `%` (like) and `!%`
+(not like) operators.
+
+```
+friends.#(last=="Murphy").first >> "Dale"
+friends.#(last=="Murphy")#.first >> ["Dale","Jane"]
+friends.#(age>45)#.last >> ["Craig","Murphy"]
+friends.#(first%"D*").last >> "Murphy"
+friends.#(first!%"D*").last >> "Craig"
+friends.#(nets.#(=="fb"))#.first >> ["Dale","Roger"]
+```
+
+*Please note that prior to v1.3.0, queries used the `#[...]` brackets. This was
+changed in v1.3.0 as to avoid confusion with the new
+[multipath](SYNTAX.md#multipaths) syntax. For backwards compatibility,
+`#[...]` will continue to work until the next major release.*
+
+## Result Type
+
+GJSON supports the json types `string`, `number`, `bool`, and `null`.
+Arrays and Objects are returned as their raw json types.
+
+The `Result` type holds one of these:
+
+```
+bool, for JSON booleans
+float64, for JSON numbers
+string, for JSON string literals
+nil, for JSON null
+```
+
+To directly access the value:
+
+```go
+result.Type // can be String, Number, True, False, Null, or JSON
+result.Str // holds the string
+result.Num // holds the float64 number
+result.Raw // holds the raw json
+result.Index // index of raw value in original json, zero means index unknown
+result.Indexes // indexes of all the elements that match on a path containing the '#' query character.
+```
+
+There are a variety of handy functions that work on a result:
+
+```go
+result.Exists() bool
+result.Value() interface{}
+result.Int() int64
+result.Uint() uint64
+result.Float() float64
+result.String() string
+result.Bool() bool
+result.Time() time.Time
+result.Array() []gjson.Result
+result.Map() map[string]gjson.Result
+result.Get(path string) Result
+result.ForEach(iterator func(key, value Result) bool)
+result.Less(token Result, caseSensitive bool) bool
+```
+
+The `result.Value()` function returns an `interface{}` which requires type assertion and is one of the following Go types:
+
+```go
+boolean >> bool
+number >> float64
+string >> string
+null >> nil
+array >> []interface{}
+object >> map[string]interface{}
+```
+
+The `result.Array()` function returns back an array of values.
+If the result represents a non-existent value, then an empty array will be returned.
+If the result is not a JSON array, the return value will be an array containing one result.
+
+### 64-bit integers
+
+The `result.Int()` and `result.Uint()` calls are capable of reading all 64 bits, allowing for large JSON integers.
+
+```go
+result.Int() int64 // -9223372036854775808 to 9223372036854775807
+result.Uint() uint64 // 0 to 18446744073709551615
+```
+
+## Modifiers and path chaining
+
+New in version 1.2 is support for modifier functions and path chaining.
+
+A modifier is a path component that performs custom processing on the
+json.
+
+Multiple paths can be "chained" together using the pipe character.
+This is useful for getting results from a modified query.
+
+For example, using the built-in `@reverse` modifier on the above json document,
+we'll get `children` array and reverse the order:
+
+```
+"children|@reverse" >> ["Jack","Alex","Sara"]
+"children|@reverse|0" >> "Jack"
+```
+
+There are currently the following built-in modifiers:
+
+- `@reverse`: Reverse an array or the members of an object.
+- `@ugly`: Remove all whitespace from a json document.
+- `@pretty`: Make the json document more human readable.
+- `@this`: Returns the current element. It can be used to retrieve the root element.
+- `@valid`: Ensure the json document is valid.
+- `@flatten`: Flattens an array.
+- `@join`: Joins multiple objects into a single object.
+- `@keys`: Returns an array of keys for an object.
+- `@values`: Returns an array of values for an object.
+- `@tostr`: Converts json to a string. Wraps a json string.
+- `@fromstr`: Converts a string from json. Unwraps a json string.
+- `@group`: Groups arrays of objects. See [e4fc67c](https://github.com/tidwall/gjson/commit/e4fc67c92aeebf2089fabc7872f010e340d105db).
+- `@dig`: Search for a value without providing its entire path. See [e8e87f2](https://github.com/tidwall/gjson/commit/e8e87f2a00dc41f3aba5631094e21f59a8cf8cbf).
+
+### Modifier arguments
+
+A modifier may accept an optional argument. The argument can be a valid JSON
+document or just characters.
+
+For example, the `@pretty` modifier takes a json object as its argument.
+
+```
+@pretty:{"sortKeys":true}
+```
+
+Which makes the json pretty and orders all of its keys.
+
+```json
+{
+ "age":37,
+ "children": ["Sara","Alex","Jack"],
+ "fav.movie": "Deer Hunter",
+ "friends": [
+ {"age": 44, "first": "Dale", "last": "Murphy"},
+ {"age": 68, "first": "Roger", "last": "Craig"},
+ {"age": 47, "first": "Jane", "last": "Murphy"}
+ ],
+ "name": {"first": "Tom", "last": "Anderson"}
+}
+```
+
+*The full list of `@pretty` options are `sortKeys`, `indent`, `prefix`, and `width`.
+Please see [Pretty Options](https://github.com/tidwall/pretty#customized-output) for more information.*
+
+### Custom modifiers
+
+You can also add custom modifiers.
+
+For example, here we create a modifier that makes the entire json document upper
+or lower case.
+
+```go
+gjson.AddModifier("case", func(json, arg string) string {
+ if arg == "upper" {
+ return strings.ToUpper(json)
+ }
+ if arg == "lower" {
+ return strings.ToLower(json)
+ }
+ return json
+})
+```
+
+```
+"children|@case:upper" >> ["SARA","ALEX","JACK"]
+"children|@case:lower|@reverse" >> ["jack","alex","sara"]
+```
+
+## JSON Lines
+
+There's support for [JSON Lines](http://jsonlines.org/) using the `..` prefix, which treats a multilined document as an array.
+
+For example:
+
+```
+{"name": "Gilbert", "age": 61}
+{"name": "Alexa", "age": 34}
+{"name": "May", "age": 57}
+{"name": "Deloise", "age": 44}
+```
+
+```
+..# >> 4
+..1 >> {"name": "Alexa", "age": 34}
+..3 >> {"name": "Deloise", "age": 44}
+..#.name >> ["Gilbert","Alexa","May","Deloise"]
+..#(name="May").age >> 57
+```
+
+The `ForEachLines` function will iterate through JSON lines.
+
+```go
+gjson.ForEachLine(json, func(line gjson.Result) bool{
+ println(line.String())
+ return true
+})
+```
+
+## Get nested array values
+
+Suppose you want all the last names from the following json:
+
+```json
+{
+ "programmers": [
+ {
+ "firstName": "Janet",
+ "lastName": "McLaughlin",
+ }, {
+ "firstName": "Elliotte",
+ "lastName": "Hunter",
+ }, {
+ "firstName": "Jason",
+ "lastName": "Harold",
+ }
+ ]
+}
+```
+
+You would use the path "programmers.#.lastName" like such:
+
+```go
+result := gjson.Get(json, "programmers.#.lastName")
+for _, name := range result.Array() {
+ println(name.String())
+}
+```
+
+You can also query an object inside an array:
+
+```go
+name := gjson.Get(json, `programmers.#(lastName="Hunter").firstName`)
+println(name.String()) // prints "Elliotte"
+```
+
+## Iterate through an object or array
+
+The `ForEach` function allows for quickly iterating through an object or array.
+The key and value are passed to the iterator function for objects.
+Only the value is passed for arrays.
+Returning `false` from an iterator will stop iteration.
+
+```go
+result := gjson.Get(json, "programmers")
+result.ForEach(func(key, value gjson.Result) bool {
+ println(value.String())
+ return true // keep iterating
+})
+```
+
+## Simple Parse and Get
+
+There's a `Parse(json)` function that will do a simple parse, and `result.Get(path)` that will search a result.
+
+For example, all of these will return the same result:
+
+```go
+gjson.Parse(json).Get("name").Get("last")
+gjson.Get(json, "name").Get("last")
+gjson.Get(json, "name.last")
+```
+
+## Check for the existence of a value
+
+Sometimes you just want to know if a value exists.
+
+```go
+value := gjson.Get(json, "name.last")
+if !value.Exists() {
+ println("no last name")
+} else {
+ println(value.String())
+}
+
+// Or as one step
+if gjson.Get(json, "name.last").Exists() {
+ println("has a last name")
+}
+```
+
+## Validate JSON
+
+The `Get*` and `Parse*` functions expects that the json is well-formed. Bad json will not panic, but it may return back unexpected results.
+
+If you are consuming JSON from an unpredictable source then you may want to validate prior to using GJSON.
+
+```go
+if !gjson.Valid(json) {
+ return errors.New("invalid json")
+}
+value := gjson.Get(json, "name.last")
+```
+
+## Unmarshal to a map
+
+To unmarshal to a `map[string]interface{}`:
+
+```go
+m, ok := gjson.Parse(json).Value().(map[string]interface{})
+if !ok {
+ // not a map
+}
+```
+
+## Working with Bytes
+
+If your JSON is contained in a `[]byte` slice, there's the [GetBytes](https://godoc.org/github.com/tidwall/gjson#GetBytes) function. This is preferred over `Get(string(data), path)`.
+
+```go
+var json []byte = ...
+result := gjson.GetBytes(json, path)
+```
+
+If you are using the `gjson.GetBytes(json, path)` function and you want to avoid converting `result.Raw` to a `[]byte`, then you can use this pattern:
+
+```go
+var json []byte = ...
+result := gjson.GetBytes(json, path)
+var raw []byte
+if result.Index > 0 {
+ raw = json[result.Index:result.Index+len(result.Raw)]
+} else {
+ raw = []byte(result.Raw)
+}
+```
+
+This is a best-effort no allocation sub slice of the original json. This method utilizes the `result.Index` field, which is the position of the raw data in the original json. It's possible that the value of `result.Index` equals zero, in which case the `result.Raw` is converted to a `[]byte`.
+
+## Performance
+
+Benchmarks of GJSON alongside [encoding/json](https://golang.org/pkg/encoding/json/),
+[ffjson](https://github.com/pquerna/ffjson),
+[EasyJSON](https://github.com/mailru/easyjson),
+[jsonparser](https://github.com/buger/jsonparser),
+and [json-iterator](https://github.com/json-iterator/go)
+
+```
+BenchmarkGJSONGet-16 11644512 311 ns/op 0 B/op 0 allocs/op
+BenchmarkGJSONUnmarshalMap-16 1122678 3094 ns/op 1920 B/op 26 allocs/op
+BenchmarkJSONUnmarshalMap-16 516681 6810 ns/op 2944 B/op 69 allocs/op
+BenchmarkJSONUnmarshalStruct-16 697053 5400 ns/op 928 B/op 13 allocs/op
+BenchmarkJSONDecoder-16 330450 10217 ns/op 3845 B/op 160 allocs/op
+BenchmarkFFJSONLexer-16 1424979 2585 ns/op 880 B/op 8 allocs/op
+BenchmarkEasyJSONLexer-16 3000000 729 ns/op 501 B/op 5 allocs/op
+BenchmarkJSONParserGet-16 3000000 366 ns/op 21 B/op 0 allocs/op
+BenchmarkJSONIterator-16 3000000 869 ns/op 693 B/op 14 allocs/op
+```
+
+JSON document used:
+
+```json
+{
+ "widget": {
+ "debug": "on",
+ "window": {
+ "title": "Sample Konfabulator Widget",
+ "name": "main_window",
+ "width": 500,
+ "height": 500
+ },
+ "image": {
+ "src": "Images/Sun.png",
+ "hOffset": 250,
+ "vOffset": 250,
+ "alignment": "center"
+ },
+ "text": {
+ "data": "Click Here",
+ "size": 36,
+ "style": "bold",
+ "vOffset": 100,
+ "alignment": "center",
+ "onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;"
+ }
+ }
+}
+```
+
+Each operation was rotated through one of the following search paths:
+
+```
+widget.window.name
+widget.image.hOffset
+widget.text.onMouseUp
+```
+
+*These benchmarks were run on a MacBook Pro 16" 2.4 GHz Intel Core i9 using Go 1.17 and can be found [here](https://github.com/tidwall/gjson-benchmarks).*
diff --git a/vendor/github.com/tidwall/gjson/SYNTAX.md b/vendor/github.com/tidwall/gjson/SYNTAX.md
new file mode 100644
index 0000000..a3f0fac
--- /dev/null
+++ b/vendor/github.com/tidwall/gjson/SYNTAX.md
@@ -0,0 +1,360 @@
+# GJSON Path Syntax
+
+A GJSON Path is a text string syntax that describes a search pattern for quickly retrieving values from a JSON payload.
+
+This document is designed to explain the structure of a GJSON Path through examples.
+
+- [Path structure](#path-structure)
+- [Basic](#basic)
+- [Wildcards](#wildcards)
+- [Escape Character](#escape-character)
+- [Arrays](#arrays)
+- [Queries](#queries)
+- [Dot vs Pipe](#dot-vs-pipe)
+- [Modifiers](#modifiers)
+- [Multipaths](#multipaths)
+- [Literals](#literals)
+
+The definitive implementation is [github.com/tidwall/gjson](https://github.com/tidwall/gjson).
+Use the [GJSON Playground](https://gjson.dev) to experiment with the syntax online.
+
+## Path structure
+
+A GJSON Path is intended to be easily expressed as a series of components separated by a `.` character.
+
+Along with `.` character, there are a few more that have special meaning, including `|`, `#`, `@`, `\`, `*`, `!`, and `?`.
+
+## Example
+
+Given this JSON
+
+```json
+{
+ "name": {"first": "Tom", "last": "Anderson"},
+ "age":37,
+ "children": ["Sara","Alex","Jack"],
+ "fav.movie": "Deer Hunter",
+ "friends": [
+ {"first": "Dale", "last": "Murphy", "age": 44, "nets": ["ig", "fb", "tw"]},
+ {"first": "Roger", "last": "Craig", "age": 68, "nets": ["fb", "tw"]},
+ {"first": "Jane", "last": "Murphy", "age": 47, "nets": ["ig", "tw"]}
+ ]
+}
+```
+
+The following GJSON Paths evaluate to the accompanying values.
+
+### Basic
+
+In many cases you'll just want to retrieve values by object name or array index.
+
+```go
+name.last "Anderson"
+name.first "Tom"
+age 37
+children ["Sara","Alex","Jack"]
+children.0 "Sara"
+children.1 "Alex"
+friends.1 {"first": "Roger", "last": "Craig", "age": 68}
+friends.1.first "Roger"
+```
+
+### Wildcards
+
+A key may contain the special wildcard characters `*` and `?`.
+The `*` will match on any zero+ characters, and `?` matches on any one character.
+
+```go
+child*.2 "Jack"
+c?ildren.0 "Sara"
+```
+
+### Escape character
+
+Special purpose characters, such as `.`, `*`, and `?` can be escaped with `\`.
+
+```go
+fav\.movie "Deer Hunter"
+```
+
+You'll also need to make sure that the `\` character is correctly escaped when hardcoding a path in your source code.
+
+```go
+// Go
+val := gjson.Get(json, "fav\\.movie") // must escape the slash
+val := gjson.Get(json, `fav\.movie`) // no need to escape the slash
+```
+
+```rust
+// Rust
+let val = gjson::get(json, "fav\\.movie") // must escape the slash
+let val = gjson::get(json, r#"fav\.movie"#) // no need to escape the slash
+```
+
+
+### Arrays
+
+The `#` character allows for digging into JSON Arrays.
+
+To get the length of an array you'll just use the `#` all by itself.
+
+```go
+friends.# 3
+friends.#.age [44,68,47]
+```
+
+### Queries
+
+You can also query an array for the first match by using `#(...)`, or find all matches with `#(...)#`.
+Queries support the `==`, `!=`, `<`, `<=`, `>`, `>=` comparison operators,
+and the simple pattern matching `%` (like) and `!%` (not like) operators.
+
+```go
+friends.#(last=="Murphy").first "Dale"
+friends.#(last=="Murphy")#.first ["Dale","Jane"]
+friends.#(age>45)#.last ["Craig","Murphy"]
+friends.#(first%"D*").last "Murphy"
+friends.#(first!%"D*").last "Craig"
+```
+
+To query for a non-object value in an array, you can forgo the string to the right of the operator.
+
+```go
+children.#(!%"*a*") "Alex"
+children.#(%"*a*")# ["Sara","Jack"]
+```
+
+Nested queries are allowed.
+
+```go
+friends.#(nets.#(=="fb"))#.first >> ["Dale","Roger"]
+```
+
+*Please note that prior to v1.3.0, queries used the `#[...]` brackets. This was
+changed in v1.3.0 as to avoid confusion with the new [multipath](#multipaths)
+syntax. For backwards compatibility, `#[...]` will continue to work until the
+next major release.*
+
+The `~` (tilde) operator will convert a value to a boolean before comparison.
+
+Supported tilde comparison type are:
+
+```
+~true Converts true-ish values to true
+~false Converts false-ish and non-existent values to true
+~null Converts null and non-existent values to true
+~* Converts any existing value to true
+```
+
+For example, using the following JSON:
+
+```json
+{
+ "vals": [
+ { "a": 1, "b": "data" },
+ { "a": 2, "b": true },
+ { "a": 3, "b": false },
+ { "a": 4, "b": "0" },
+ { "a": 5, "b": 0 },
+ { "a": 6, "b": "1" },
+ { "a": 7, "b": 1 },
+ { "a": 8, "b": "true" },
+ { "a": 9, "b": false },
+ { "a": 10, "b": null },
+ { "a": 11 }
+ ]
+}
+```
+
+To query for all true-ish or false-ish values:
+
+```
+vals.#(b==~true)#.a >> [2,6,7,8]
+vals.#(b==~false)#.a >> [3,4,5,9,10,11]
+```
+
+The last value which was non-existent is treated as `false`
+
+To query for null and explicit value existence:
+
+```
+vals.#(b==~null)#.a >> [10,11]
+vals.#(b==~*)#.a >> [1,2,3,4,5,6,7,8,9,10]
+vals.#(b!=~*)#.a >> [11]
+```
+
+### Dot vs Pipe
+
+The `.` is standard separator, but it's also possible to use a `|`.
+In most cases they both end up returning the same results.
+The cases where`|` differs from `.` is when it's used after the `#` for [Arrays](#arrays) and [Queries](#queries).
+
+Here are some examples
+
+```go
+friends.0.first "Dale"
+friends|0.first "Dale"
+friends.0|first "Dale"
+friends|0|first "Dale"
+friends|# 3
+friends.# 3
+friends.#(last="Murphy")# [{"first": "Dale", "last": "Murphy", "age": 44},{"first": "Jane", "last": "Murphy", "age": 47}]
+friends.#(last="Murphy")#.first ["Dale","Jane"]
+friends.#(last="Murphy")#|first
+friends.#(last="Murphy")#.0 []
+friends.#(last="Murphy")#|0 {"first": "Dale", "last": "Murphy", "age": 44}
+friends.#(last="Murphy")#.# []
+friends.#(last="Murphy")#|# 2
+```
+
+Let's break down a few of these.
+
+The path `friends.#(last="Murphy")#` all by itself results in
+
+```json
+[{"first": "Dale", "last": "Murphy", "age": 44},{"first": "Jane", "last": "Murphy", "age": 47}]
+```
+
+The `.first` suffix will process the `first` path on each array element *before* returning the results. Which becomes
+
+```json
+["Dale","Jane"]
+```
+
+But the `|first` suffix actually processes the `first` path *after* the previous result.
+Since the previous result is an array, not an object, it's not possible to process
+because `first` does not exist.
+
+Yet, `|0` suffix returns
+
+```json
+{"first": "Dale", "last": "Murphy", "age": 44}
+```
+
+Because `0` is the first index of the previous result.
+
+### Modifiers
+
+A modifier is a path component that performs custom processing on the JSON.
+
+For example, using the built-in `@reverse` modifier on the above JSON payload will reverse the `children` array:
+
+```go
+children.@reverse ["Jack","Alex","Sara"]
+children.@reverse.0 "Jack"
+```
+
+There are currently the following built-in modifiers:
+
+- `@reverse`: Reverse an array or the members of an object.
+- `@ugly`: Remove all whitespace from JSON.
+- `@pretty`: Make the JSON more human readable.
+- `@this`: Returns the current element. It can be used to retrieve the root element.
+- `@valid`: Ensure the json document is valid.
+- `@flatten`: Flattens an array.
+- `@join`: Joins multiple objects into a single object.
+- `@keys`: Returns an array of keys for an object.
+- `@values`: Returns an array of values for an object.
+- `@tostr`: Converts json to a string. Wraps a json string.
+- `@fromstr`: Converts a string from json. Unwraps a json string.
+- `@group`: Groups arrays of objects. See [e4fc67c](https://github.com/tidwall/gjson/commit/e4fc67c92aeebf2089fabc7872f010e340d105db).
+- `@dig`: Search for a value without providing its entire path. See [e8e87f2](https://github.com/tidwall/gjson/commit/e8e87f2a00dc41f3aba5631094e21f59a8cf8cbf).
+
+#### Modifier arguments
+
+A modifier may accept an optional argument. The argument can be a valid JSON payload or just characters.
+
+For example, the `@pretty` modifier takes a json object as its argument.
+
+```
+@pretty:{"sortKeys":true}
+```
+
+Which makes the json pretty and orders all of its keys.
+
+```json
+{
+ "age":37,
+ "children": ["Sara","Alex","Jack"],
+ "fav.movie": "Deer Hunter",
+ "friends": [
+ {"age": 44, "first": "Dale", "last": "Murphy"},
+ {"age": 68, "first": "Roger", "last": "Craig"},
+ {"age": 47, "first": "Jane", "last": "Murphy"}
+ ],
+ "name": {"first": "Tom", "last": "Anderson"}
+}
+```
+
+*The full list of `@pretty` options are `sortKeys`, `indent`, `prefix`, and `width`.
+Please see [Pretty Options](https://github.com/tidwall/pretty#customized-output) for more information.*
+
+#### Custom modifiers
+
+You can also add custom modifiers.
+
+For example, here we create a modifier which makes the entire JSON payload upper or lower case.
+
+```go
+gjson.AddModifier("case", func(json, arg string) string {
+ if arg == "upper" {
+ return strings.ToUpper(json)
+ }
+ if arg == "lower" {
+ return strings.ToLower(json)
+ }
+ return json
+})
+"children.@case:upper" ["SARA","ALEX","JACK"]
+"children.@case:lower.@reverse" ["jack","alex","sara"]
+```
+
+*Note: Custom modifiers are not yet available in the Rust version*
+
+### Multipaths
+
+Starting with v1.3.0, GJSON added the ability to join multiple paths together
+to form new documents. Wrapping comma-separated paths between `[...]` or
+`{...}` will result in a new array or object, respectively.
+
+For example, using the given multipath:
+
+```
+{name.first,age,"the_murphys":friends.#(last="Murphy")#.first}
+```
+
+Here we selected the first name, age, and the first name for friends with the
+last name "Murphy".
+
+You'll notice that an optional key can be provided, in this case
+"the_murphys", to force assign a key to a value. Otherwise, the name of the
+actual field will be used, in this case "first". If a name cannot be
+determined, then "_" is used.
+
+This results in
+
+```json
+{"first":"Tom","age":37,"the_murphys":["Dale","Jane"]}
+```
+
+### Literals
+
+Starting with v1.12.0, GJSON added support of json literals, which provides a way for constructing static blocks of json. This is can be particularly useful when constructing a new json document using [multipaths](#multipaths).
+
+A json literal begins with the '!' declaration character.
+
+For example, using the given multipath:
+
+```
+{name.first,age,"company":!"Happysoft","employed":!true}
+```
+
+Here we selected the first name and age. Then add two new fields, "company" and "employed".
+
+This results in
+
+```json
+{"first":"Tom","age":37,"company":"Happysoft","employed":true}
+```
+
+*See issue [#249](https://github.com/tidwall/gjson/issues/249) for additional context on JSON Literals.*
diff --git a/vendor/github.com/tidwall/gjson/gjson.go b/vendor/github.com/tidwall/gjson/gjson.go
new file mode 100644
index 0000000..779fe61
--- /dev/null
+++ b/vendor/github.com/tidwall/gjson/gjson.go
@@ -0,0 +1,3505 @@
+// Package gjson provides searching for json strings.
+package gjson
+
+import (
+ "strconv"
+ "strings"
+ "time"
+ "unicode/utf16"
+ "unicode/utf8"
+ "unsafe"
+
+ "github.com/tidwall/match"
+ "github.com/tidwall/pretty"
+)
+
+// Type is Result type
+type Type int
+
+const (
+ // Null is a null json value
+ Null Type = iota
+ // False is a json false boolean
+ False
+ // Number is json number
+ Number
+ // String is a json string
+ String
+ // True is a json true boolean
+ True
+ // JSON is a raw block of JSON
+ JSON
+)
+
+// String returns a string representation of the type.
+func (t Type) String() string {
+ switch t {
+ default:
+ return ""
+ case Null:
+ return "Null"
+ case False:
+ return "False"
+ case Number:
+ return "Number"
+ case String:
+ return "String"
+ case True:
+ return "True"
+ case JSON:
+ return "JSON"
+ }
+}
+
+// Result represents a json value that is returned from Get().
+type Result struct {
+ // Type is the json type
+ Type Type
+ // Raw is the raw json
+ Raw string
+ // Str is the json string
+ Str string
+ // Num is the json number
+ Num float64
+ // Index of raw value in original json, zero means index unknown
+ Index int
+ // Indexes of all the elements that match on a path containing the '#'
+ // query character.
+ Indexes []int
+}
+
+// String returns a string representation of the value.
+func (t Result) String() string {
+ switch t.Type {
+ default:
+ return ""
+ case False:
+ return "false"
+ case Number:
+ if len(t.Raw) == 0 {
+ // calculated result
+ return strconv.FormatFloat(t.Num, 'f', -1, 64)
+ }
+ var i int
+ if t.Raw[0] == '-' {
+ i++
+ }
+ for ; i < len(t.Raw); i++ {
+ if t.Raw[i] < '0' || t.Raw[i] > '9' {
+ return strconv.FormatFloat(t.Num, 'f', -1, 64)
+ }
+ }
+ return t.Raw
+ case String:
+ return t.Str
+ case JSON:
+ return t.Raw
+ case True:
+ return "true"
+ }
+}
+
+// Bool returns an boolean representation.
+func (t Result) Bool() bool {
+ switch t.Type {
+ default:
+ return false
+ case True:
+ return true
+ case String:
+ b, _ := strconv.ParseBool(strings.ToLower(t.Str))
+ return b
+ case Number:
+ return t.Num != 0
+ }
+}
+
+// Int returns an integer representation.
+func (t Result) Int() int64 {
+ switch t.Type {
+ default:
+ return 0
+ case True:
+ return 1
+ case String:
+ n, _ := parseInt(t.Str)
+ return n
+ case Number:
+ // try to directly convert the float64 to int64
+ i, ok := safeInt(t.Num)
+ if ok {
+ return i
+ }
+ // now try to parse the raw string
+ i, ok = parseInt(t.Raw)
+ if ok {
+ return i
+ }
+ // fallback to a standard conversion
+ return int64(t.Num)
+ }
+}
+
+// Uint returns an unsigned integer representation.
+func (t Result) Uint() uint64 {
+ switch t.Type {
+ default:
+ return 0
+ case True:
+ return 1
+ case String:
+ n, _ := parseUint(t.Str)
+ return n
+ case Number:
+ // try to directly convert the float64 to uint64
+ i, ok := safeInt(t.Num)
+ if ok && i >= 0 {
+ return uint64(i)
+ }
+ // now try to parse the raw string
+ u, ok := parseUint(t.Raw)
+ if ok {
+ return u
+ }
+ // fallback to a standard conversion
+ return uint64(t.Num)
+ }
+}
+
+// Float returns an float64 representation.
+func (t Result) Float() float64 {
+ switch t.Type {
+ default:
+ return 0
+ case True:
+ return 1
+ case String:
+ n, _ := strconv.ParseFloat(t.Str, 64)
+ return n
+ case Number:
+ return t.Num
+ }
+}
+
+// Time returns a time.Time representation.
+func (t Result) Time() time.Time {
+ res, _ := time.Parse(time.RFC3339, t.String())
+ return res
+}
+
+// Array returns back an array of values.
+// If the result represents a null value or is non-existent, then an empty
+// array will be returned.
+// If the result is not a JSON array, the return value will be an
+// array containing one result.
+func (t Result) Array() []Result {
+ if t.Type == Null {
+ return []Result{}
+ }
+ if !t.IsArray() {
+ return []Result{t}
+ }
+ r := t.arrayOrMap('[', false)
+ return r.a
+}
+
+// IsObject returns true if the result value is a JSON object.
+func (t Result) IsObject() bool {
+ return t.Type == JSON && len(t.Raw) > 0 && t.Raw[0] == '{'
+}
+
+// IsArray returns true if the result value is a JSON array.
+func (t Result) IsArray() bool {
+ return t.Type == JSON && len(t.Raw) > 0 && t.Raw[0] == '['
+}
+
+// IsBool returns true if the result value is a JSON boolean.
+func (t Result) IsBool() bool {
+ return t.Type == True || t.Type == False
+}
+
+// ForEach iterates through values.
+// If the result represents a non-existent value, then no values will be
+// iterated. If the result is an Object, the iterator will pass the key and
+// value of each item. If the result is an Array, the iterator will only pass
+// the value of each item. If the result is not a JSON array or object, the
+// iterator will pass back one value equal to the result.
+func (t Result) ForEach(iterator func(key, value Result) bool) {
+ if !t.Exists() {
+ return
+ }
+ if t.Type != JSON {
+ iterator(Result{}, t)
+ return
+ }
+ json := t.Raw
+ var obj bool
+ var i int
+ var key, value Result
+ for ; i < len(json); i++ {
+ if json[i] == '{' {
+ i++
+ key.Type = String
+ obj = true
+ break
+ } else if json[i] == '[' {
+ i++
+ key.Type = Number
+ key.Num = -1
+ break
+ }
+ if json[i] > ' ' {
+ return
+ }
+ }
+ var str string
+ var vesc bool
+ var ok bool
+ var idx int
+ for ; i < len(json); i++ {
+ if obj {
+ if json[i] != '"' {
+ continue
+ }
+ s := i
+ i, str, vesc, ok = parseString(json, i+1)
+ if !ok {
+ return
+ }
+ if vesc {
+ key.Str = unescape(str[1 : len(str)-1])
+ } else {
+ key.Str = str[1 : len(str)-1]
+ }
+ key.Raw = str
+ key.Index = s + t.Index
+ } else {
+ key.Num += 1
+ }
+ for ; i < len(json); i++ {
+ if json[i] <= ' ' || json[i] == ',' || json[i] == ':' {
+ continue
+ }
+ break
+ }
+ s := i
+ i, value, ok = parseAny(json, i, true)
+ if !ok {
+ return
+ }
+ if t.Indexes != nil {
+ if idx < len(t.Indexes) {
+ value.Index = t.Indexes[idx]
+ }
+ } else {
+ value.Index = s + t.Index
+ }
+ if !iterator(key, value) {
+ return
+ }
+ idx++
+ }
+}
+
+// Map returns back a map of values. The result should be a JSON object.
+// If the result is not a JSON object, the return value will be an empty map.
+func (t Result) Map() map[string]Result {
+ if t.Type != JSON {
+ return map[string]Result{}
+ }
+ r := t.arrayOrMap('{', false)
+ return r.o
+}
+
+// Get searches result for the specified path.
+// The result should be a JSON array or object.
+func (t Result) Get(path string) Result {
+ r := Get(t.Raw, path)
+ if r.Indexes != nil {
+ for i := 0; i < len(r.Indexes); i++ {
+ r.Indexes[i] += t.Index
+ }
+ } else {
+ r.Index += t.Index
+ }
+ return r
+}
+
+type arrayOrMapResult struct {
+ a []Result
+ ai []interface{}
+ o map[string]Result
+ oi map[string]interface{}
+ vc byte
+}
+
+func (t Result) arrayOrMap(vc byte, valueize bool) (r arrayOrMapResult) {
+ var json = t.Raw
+ var i int
+ var value Result
+ var count int
+ var key Result
+ if vc == 0 {
+ for ; i < len(json); i++ {
+ if json[i] == '{' || json[i] == '[' {
+ r.vc = json[i]
+ i++
+ break
+ }
+ if json[i] > ' ' {
+ goto end
+ }
+ }
+ } else {
+ for ; i < len(json); i++ {
+ if json[i] == vc {
+ i++
+ break
+ }
+ if json[i] > ' ' {
+ goto end
+ }
+ }
+ r.vc = vc
+ }
+ if r.vc == '{' {
+ if valueize {
+ r.oi = make(map[string]interface{})
+ } else {
+ r.o = make(map[string]Result)
+ }
+ } else {
+ if valueize {
+ r.ai = make([]interface{}, 0)
+ } else {
+ r.a = make([]Result, 0)
+ }
+ }
+ for ; i < len(json); i++ {
+ if json[i] <= ' ' {
+ continue
+ }
+ // get next value
+ if json[i] == ']' || json[i] == '}' {
+ break
+ }
+ switch json[i] {
+ default:
+ if (json[i] >= '0' && json[i] <= '9') || json[i] == '-' {
+ value.Type = Number
+ value.Raw, value.Num = tonum(json[i:])
+ value.Str = ""
+ } else {
+ continue
+ }
+ case '{', '[':
+ value.Type = JSON
+ value.Raw = squash(json[i:])
+ value.Str, value.Num = "", 0
+ case 'n':
+ value.Type = Null
+ value.Raw = tolit(json[i:])
+ value.Str, value.Num = "", 0
+ case 't':
+ value.Type = True
+ value.Raw = tolit(json[i:])
+ value.Str, value.Num = "", 0
+ case 'f':
+ value.Type = False
+ value.Raw = tolit(json[i:])
+ value.Str, value.Num = "", 0
+ case '"':
+ value.Type = String
+ value.Raw, value.Str = tostr(json[i:])
+ value.Num = 0
+ }
+ value.Index = i + t.Index
+
+ i += len(value.Raw) - 1
+
+ if r.vc == '{' {
+ if count%2 == 0 {
+ key = value
+ } else {
+ if valueize {
+ if _, ok := r.oi[key.Str]; !ok {
+ r.oi[key.Str] = value.Value()
+ }
+ } else {
+ if _, ok := r.o[key.Str]; !ok {
+ r.o[key.Str] = value
+ }
+ }
+ }
+ count++
+ } else {
+ if valueize {
+ r.ai = append(r.ai, value.Value())
+ } else {
+ r.a = append(r.a, value)
+ }
+ }
+ }
+end:
+ if t.Indexes != nil {
+ if len(t.Indexes) != len(r.a) {
+ for i := 0; i < len(r.a); i++ {
+ r.a[i].Index = 0
+ }
+ } else {
+ for i := 0; i < len(r.a); i++ {
+ r.a[i].Index = t.Indexes[i]
+ }
+ }
+ }
+ return
+}
+
+// Parse parses the json and returns a result.
+//
+// This function expects that the json is well-formed, and does not validate.
+// Invalid json will not panic, but it may return back unexpected results.
+// If you are consuming JSON from an unpredictable source then you may want to
+// use the Valid function first.
+func Parse(json string) Result {
+ var value Result
+ i := 0
+ for ; i < len(json); i++ {
+ if json[i] == '{' || json[i] == '[' {
+ value.Type = JSON
+ value.Raw = json[i:] // just take the entire raw
+ break
+ }
+ if json[i] <= ' ' {
+ continue
+ }
+ switch json[i] {
+ case '+', '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+ 'i', 'I', 'N':
+ value.Type = Number
+ value.Raw, value.Num = tonum(json[i:])
+ case 'n':
+ if i+1 < len(json) && json[i+1] != 'u' {
+ // nan
+ value.Type = Number
+ value.Raw, value.Num = tonum(json[i:])
+ } else {
+ // null
+ value.Type = Null
+ value.Raw = tolit(json[i:])
+ }
+ case 't':
+ value.Type = True
+ value.Raw = tolit(json[i:])
+ case 'f':
+ value.Type = False
+ value.Raw = tolit(json[i:])
+ case '"':
+ value.Type = String
+ value.Raw, value.Str = tostr(json[i:])
+ default:
+ return Result{}
+ }
+ break
+ }
+ if value.Exists() {
+ value.Index = i
+ }
+ return value
+}
+
+// ParseBytes parses the json and returns a result.
+// If working with bytes, this method preferred over Parse(string(data))
+func ParseBytes(json []byte) Result {
+ return Parse(string(json))
+}
+
+func squash(json string) string {
+ // expects that the lead character is a '[' or '{' or '(' or '"'
+ // squash the value, ignoring all nested arrays and objects.
+ var i, depth int
+ if json[0] != '"' {
+ i, depth = 1, 1
+ }
+ for ; i < len(json); i++ {
+ if json[i] >= '"' && json[i] <= '}' {
+ switch json[i] {
+ case '"':
+ i++
+ s2 := i
+ for ; i < len(json); i++ {
+ if json[i] > '\\' {
+ continue
+ }
+ if json[i] == '"' {
+ // look for an escaped slash
+ if json[i-1] == '\\' {
+ n := 0
+ for j := i - 2; j > s2-1; j-- {
+ if json[j] != '\\' {
+ break
+ }
+ n++
+ }
+ if n%2 == 0 {
+ continue
+ }
+ }
+ break
+ }
+ }
+ if depth == 0 {
+ if i >= len(json) {
+ return json
+ }
+ return json[:i+1]
+ }
+ case '{', '[', '(':
+ depth++
+ case '}', ']', ')':
+ depth--
+ if depth == 0 {
+ return json[:i+1]
+ }
+ }
+ }
+ }
+ return json
+}
+
+func tonum(json string) (raw string, num float64) {
+ for i := 1; i < len(json); i++ {
+ // less than dash might have valid characters
+ if json[i] <= '-' {
+ if json[i] <= ' ' || json[i] == ',' {
+ // break on whitespace and comma
+ raw = json[:i]
+ num, _ = strconv.ParseFloat(raw, 64)
+ return
+ }
+ // could be a '+' or '-'. let's assume so.
+ } else if json[i] == ']' || json[i] == '}' {
+ // break on ']' or '}'
+ raw = json[:i]
+ num, _ = strconv.ParseFloat(raw, 64)
+ return
+ }
+ }
+ raw = json
+ num, _ = strconv.ParseFloat(raw, 64)
+ return
+}
+
+func tolit(json string) (raw string) {
+ for i := 1; i < len(json); i++ {
+ if json[i] < 'a' || json[i] > 'z' {
+ return json[:i]
+ }
+ }
+ return json
+}
+
+func tostr(json string) (raw string, str string) {
+ // expects that the lead character is a '"'
+ for i := 1; i < len(json); i++ {
+ if json[i] > '\\' {
+ continue
+ }
+ if json[i] == '"' {
+ return json[:i+1], json[1:i]
+ }
+ if json[i] == '\\' {
+ i++
+ for ; i < len(json); i++ {
+ if json[i] > '\\' {
+ continue
+ }
+ if json[i] == '"' {
+ // look for an escaped slash
+ if json[i-1] == '\\' {
+ n := 0
+ for j := i - 2; j > 0; j-- {
+ if json[j] != '\\' {
+ break
+ }
+ n++
+ }
+ if n%2 == 0 {
+ continue
+ }
+ }
+ return json[:i+1], unescape(json[1:i])
+ }
+ }
+ var ret string
+ if i+1 < len(json) {
+ ret = json[:i+1]
+ } else {
+ ret = json[:i]
+ }
+ return ret, unescape(json[1:i])
+ }
+ }
+ return json, json[1:]
+}
+
+// Exists returns true if value exists.
+//
+// if gjson.Get(json, "name.last").Exists(){
+// println("value exists")
+// }
+func (t Result) Exists() bool {
+ return t.Type != Null || len(t.Raw) != 0
+}
+
+// Value returns one of these types:
+//
+// bool, for JSON booleans
+// float64, for JSON numbers
+// Number, for JSON numbers
+// string, for JSON string literals
+// nil, for JSON null
+// map[string]interface{}, for JSON objects
+// []interface{}, for JSON arrays
+func (t Result) Value() interface{} {
+ if t.Type == String {
+ return t.Str
+ }
+ switch t.Type {
+ default:
+ return nil
+ case False:
+ return false
+ case Number:
+ return t.Num
+ case JSON:
+ r := t.arrayOrMap(0, true)
+ if r.vc == '{' {
+ return r.oi
+ } else if r.vc == '[' {
+ return r.ai
+ }
+ return nil
+ case True:
+ return true
+ }
+}
+
+func parseString(json string, i int) (int, string, bool, bool) {
+ var s = i
+ for ; i < len(json); i++ {
+ if json[i] > '\\' {
+ continue
+ }
+ if json[i] == '"' {
+ return i + 1, json[s-1 : i+1], false, true
+ }
+ if json[i] == '\\' {
+ i++
+ for ; i < len(json); i++ {
+ if json[i] > '\\' {
+ continue
+ }
+ if json[i] == '"' {
+ // look for an escaped slash
+ if json[i-1] == '\\' {
+ n := 0
+ for j := i - 2; j > 0; j-- {
+ if json[j] != '\\' {
+ break
+ }
+ n++
+ }
+ if n%2 == 0 {
+ continue
+ }
+ }
+ return i + 1, json[s-1 : i+1], true, true
+ }
+ }
+ break
+ }
+ }
+ return i, json[s-1:], false, false
+}
+
+func parseNumber(json string, i int) (int, string) {
+ var s = i
+ i++
+ for ; i < len(json); i++ {
+ if json[i] <= ' ' || json[i] == ',' || json[i] == ']' ||
+ json[i] == '}' {
+ return i, json[s:i]
+ }
+ }
+ return i, json[s:]
+}
+
+func parseLiteral(json string, i int) (int, string) {
+ var s = i
+ i++
+ for ; i < len(json); i++ {
+ if json[i] < 'a' || json[i] > 'z' {
+ return i, json[s:i]
+ }
+ }
+ return i, json[s:]
+}
+
+type arrayPathResult struct {
+ part string
+ path string
+ pipe string
+ piped bool
+ more bool
+ alogok bool
+ arrch bool
+ alogkey string
+ query struct {
+ on bool
+ all bool
+ path string
+ op string
+ value string
+ }
+}
+
+func parseArrayPath(path string) (r arrayPathResult) {
+ for i := 0; i < len(path); i++ {
+ if path[i] == '|' {
+ r.part = path[:i]
+ r.pipe = path[i+1:]
+ r.piped = true
+ return
+ }
+ if path[i] == '.' {
+ r.part = path[:i]
+ if !r.arrch && i < len(path)-1 && isDotPiperChar(path[i+1:]) {
+ r.pipe = path[i+1:]
+ r.piped = true
+ } else {
+ r.path = path[i+1:]
+ r.more = true
+ }
+ return
+ }
+ if path[i] == '#' {
+ r.arrch = true
+ if i == 0 && len(path) > 1 {
+ if path[1] == '.' {
+ r.alogok = true
+ r.alogkey = path[2:]
+ r.path = path[:1]
+ } else if path[1] == '[' || path[1] == '(' {
+ // query
+ r.query.on = true
+ qpath, op, value, _, fi, vesc, ok :=
+ parseQuery(path[i:])
+ if !ok {
+ // bad query, end now
+ break
+ }
+ if len(value) >= 2 && value[0] == '"' &&
+ value[len(value)-1] == '"' {
+ value = value[1 : len(value)-1]
+ if vesc {
+ value = unescape(value)
+ }
+ }
+ r.query.path = qpath
+ r.query.op = op
+ r.query.value = value
+
+ i = fi - 1
+ if i+1 < len(path) && path[i+1] == '#' {
+ r.query.all = true
+ }
+ }
+ }
+ continue
+ }
+ }
+ r.part = path
+ r.path = ""
+ return
+}
+
+// splitQuery takes a query and splits it into three parts:
+//
+// path, op, middle, and right.
+//
+// So for this query:
+//
+// #(first_name=="Murphy").last
+//
+// Becomes
+//
+// first_name # path
+// =="Murphy" # middle
+// .last # right
+//
+// Or,
+//
+// #(service_roles.#(=="one")).cap
+//
+// Becomes
+//
+// service_roles.#(=="one") # path
+// # middle
+// .cap # right
+func parseQuery(query string) (
+ path, op, value, remain string, i int, vesc, ok bool,
+) {
+ if len(query) < 2 || query[0] != '#' ||
+ (query[1] != '(' && query[1] != '[') {
+ return "", "", "", "", i, false, false
+ }
+ i = 2
+ j := 0 // start of value part
+ depth := 1
+ for ; i < len(query); i++ {
+ if depth == 1 && j == 0 {
+ switch query[i] {
+ case '!', '=', '<', '>', '%':
+ // start of the value part
+ j = i
+ continue
+ }
+ }
+ if query[i] == '\\' {
+ i++
+ } else if query[i] == '[' || query[i] == '(' {
+ depth++
+ } else if query[i] == ']' || query[i] == ')' {
+ depth--
+ if depth == 0 {
+ break
+ }
+ } else if query[i] == '"' {
+ // inside selector string, balance quotes
+ i++
+ for ; i < len(query); i++ {
+ if query[i] == '\\' {
+ vesc = true
+ i++
+ } else if query[i] == '"' {
+ break
+ }
+ }
+ }
+ }
+ if depth > 0 {
+ return "", "", "", "", i, false, false
+ }
+ if j > 0 {
+ path = trim(query[2:j])
+ value = trim(query[j:i])
+ remain = query[i+1:]
+ // parse the compare op from the value
+ var opsz int
+ switch {
+ case len(value) == 1:
+ opsz = 1
+ case value[0] == '!' && value[1] == '=':
+ opsz = 2
+ case value[0] == '!' && value[1] == '%':
+ opsz = 2
+ case value[0] == '<' && value[1] == '=':
+ opsz = 2
+ case value[0] == '>' && value[1] == '=':
+ opsz = 2
+ case value[0] == '=' && value[1] == '=':
+ value = value[1:]
+ opsz = 1
+ case value[0] == '<':
+ opsz = 1
+ case value[0] == '>':
+ opsz = 1
+ case value[0] == '=':
+ opsz = 1
+ case value[0] == '%':
+ opsz = 1
+ }
+ op = value[:opsz]
+ value = trim(value[opsz:])
+ } else {
+ path = trim(query[2:i])
+ remain = query[i+1:]
+ }
+ return path, op, value, remain, i + 1, vesc, true
+}
+
+func trim(s string) string {
+left:
+ if len(s) > 0 && s[0] <= ' ' {
+ s = s[1:]
+ goto left
+ }
+right:
+ if len(s) > 0 && s[len(s)-1] <= ' ' {
+ s = s[:len(s)-1]
+ goto right
+ }
+ return s
+}
+
+// peek at the next byte and see if it's a '@', '[', or '{'.
+func isDotPiperChar(s string) bool {
+ if DisableModifiers {
+ return false
+ }
+ c := s[0]
+ if c == '@' {
+ // check that the next component is *not* a modifier.
+ i := 1
+ for ; i < len(s); i++ {
+ if s[i] == '.' || s[i] == '|' || s[i] == ':' {
+ break
+ }
+ }
+ _, ok := modifiers[s[1:i]]
+ return ok
+ }
+ return c == '[' || c == '{'
+}
+
+type objectPathResult struct {
+ part string
+ path string
+ pipe string
+ piped bool
+ wild bool
+ more bool
+}
+
+func parseObjectPath(path string) (r objectPathResult) {
+ for i := 0; i < len(path); i++ {
+ if path[i] == '|' {
+ r.part = path[:i]
+ r.pipe = path[i+1:]
+ r.piped = true
+ return
+ }
+ if path[i] == '.' {
+ r.part = path[:i]
+ if i < len(path)-1 && isDotPiperChar(path[i+1:]) {
+ r.pipe = path[i+1:]
+ r.piped = true
+ } else {
+ r.path = path[i+1:]
+ r.more = true
+ }
+ return
+ }
+ if path[i] == '*' || path[i] == '?' {
+ r.wild = true
+ continue
+ }
+ if path[i] == '\\' {
+ // go into escape mode. this is a slower path that
+ // strips off the escape character from the part.
+ epart := []byte(path[:i])
+ i++
+ if i < len(path) {
+ epart = append(epart, path[i])
+ i++
+ for ; i < len(path); i++ {
+ if path[i] == '\\' {
+ i++
+ if i < len(path) {
+ epart = append(epart, path[i])
+ }
+ continue
+ } else if path[i] == '.' {
+ r.part = string(epart)
+ if i < len(path)-1 && isDotPiperChar(path[i+1:]) {
+ r.pipe = path[i+1:]
+ r.piped = true
+ } else {
+ r.path = path[i+1:]
+ r.more = true
+ }
+ return
+ } else if path[i] == '|' {
+ r.part = string(epart)
+ r.pipe = path[i+1:]
+ r.piped = true
+ return
+ } else if path[i] == '*' || path[i] == '?' {
+ r.wild = true
+ }
+ epart = append(epart, path[i])
+ }
+ }
+ // append the last part
+ r.part = string(epart)
+ return
+ }
+ }
+ r.part = path
+ return
+}
+
+func parseSquash(json string, i int) (int, string) {
+ // expects that the lead character is a '[' or '{' or '('
+ // squash the value, ignoring all nested arrays and objects.
+ // the first '[' or '{' or '(' has already been read
+ s := i
+ i++
+ depth := 1
+ for ; i < len(json); i++ {
+ if json[i] >= '"' && json[i] <= '}' {
+ switch json[i] {
+ case '"':
+ i++
+ s2 := i
+ for ; i < len(json); i++ {
+ if json[i] > '\\' {
+ continue
+ }
+ if json[i] == '"' {
+ // look for an escaped slash
+ if json[i-1] == '\\' {
+ n := 0
+ for j := i - 2; j > s2-1; j-- {
+ if json[j] != '\\' {
+ break
+ }
+ n++
+ }
+ if n%2 == 0 {
+ continue
+ }
+ }
+ break
+ }
+ }
+ case '{', '[', '(':
+ depth++
+ case '}', ']', ')':
+ depth--
+ if depth == 0 {
+ i++
+ return i, json[s:i]
+ }
+ }
+ }
+ }
+ return i, json[s:]
+}
+
+func parseObject(c *parseContext, i int, path string) (int, bool) {
+ var pmatch, kesc, vesc, ok, hit bool
+ var key, val string
+ rp := parseObjectPath(path)
+ if !rp.more && rp.piped {
+ c.pipe = rp.pipe
+ c.piped = true
+ }
+ for i < len(c.json) {
+ for ; i < len(c.json); i++ {
+ if c.json[i] == '"' {
+ // parse_key_string
+ // this is slightly different from getting s string value
+ // because we don't need the outer quotes.
+ i++
+ var s = i
+ for ; i < len(c.json); i++ {
+ if c.json[i] > '\\' {
+ continue
+ }
+ if c.json[i] == '"' {
+ i, key, kesc, ok = i+1, c.json[s:i], false, true
+ goto parse_key_string_done
+ }
+ if c.json[i] == '\\' {
+ i++
+ for ; i < len(c.json); i++ {
+ if c.json[i] > '\\' {
+ continue
+ }
+ if c.json[i] == '"' {
+ // look for an escaped slash
+ if c.json[i-1] == '\\' {
+ n := 0
+ for j := i - 2; j > 0; j-- {
+ if c.json[j] != '\\' {
+ break
+ }
+ n++
+ }
+ if n%2 == 0 {
+ continue
+ }
+ }
+ i, key, kesc, ok = i+1, c.json[s:i], true, true
+ goto parse_key_string_done
+ }
+ }
+ break
+ }
+ }
+ key, kesc, ok = c.json[s:], false, false
+ parse_key_string_done:
+ break
+ }
+ if c.json[i] == '}' {
+ return i + 1, false
+ }
+ }
+ if !ok {
+ return i, false
+ }
+ if rp.wild {
+ if kesc {
+ pmatch = matchLimit(unescape(key), rp.part)
+ } else {
+ pmatch = matchLimit(key, rp.part)
+ }
+ } else {
+ if kesc {
+ pmatch = rp.part == unescape(key)
+ } else {
+ pmatch = rp.part == key
+ }
+ }
+ hit = pmatch && !rp.more
+ for ; i < len(c.json); i++ {
+ var num bool
+ switch c.json[i] {
+ default:
+ continue
+ case '"':
+ i++
+ i, val, vesc, ok = parseString(c.json, i)
+ if !ok {
+ return i, false
+ }
+ if hit {
+ if vesc {
+ c.value.Str = unescape(val[1 : len(val)-1])
+ } else {
+ c.value.Str = val[1 : len(val)-1]
+ }
+ c.value.Raw = val
+ c.value.Type = String
+ return i, true
+ }
+ case '{':
+ if pmatch && !hit {
+ i, hit = parseObject(c, i+1, rp.path)
+ if hit {
+ return i, true
+ }
+ } else {
+ i, val = parseSquash(c.json, i)
+ if hit {
+ c.value.Raw = val
+ c.value.Type = JSON
+ return i, true
+ }
+ }
+ case '[':
+ if pmatch && !hit {
+ i, hit = parseArray(c, i+1, rp.path)
+ if hit {
+ return i, true
+ }
+ } else {
+ i, val = parseSquash(c.json, i)
+ if hit {
+ c.value.Raw = val
+ c.value.Type = JSON
+ return i, true
+ }
+ }
+ case 'n':
+ if i+1 < len(c.json) && c.json[i+1] != 'u' {
+ num = true
+ break
+ }
+ fallthrough
+ case 't', 'f':
+ vc := c.json[i]
+ i, val = parseLiteral(c.json, i)
+ if hit {
+ c.value.Raw = val
+ switch vc {
+ case 't':
+ c.value.Type = True
+ case 'f':
+ c.value.Type = False
+ }
+ return i, true
+ }
+ case '+', '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+ 'i', 'I', 'N':
+ num = true
+ }
+ if num {
+ i, val = parseNumber(c.json, i)
+ if hit {
+ c.value.Raw = val
+ c.value.Type = Number
+ c.value.Num, _ = strconv.ParseFloat(val, 64)
+ return i, true
+ }
+ }
+ break
+ }
+ }
+ return i, false
+}
+
+// matchLimit will limit the complexity of the match operation to avoid ReDos
+// attacks from arbitrary inputs.
+// See the github.com/tidwall/match.MatchLimit function for more information.
+func matchLimit(str, pattern string) bool {
+ matched, _ := match.MatchLimit(str, pattern, 10000)
+ return matched
+}
+
+func falseish(t Result) bool {
+ switch t.Type {
+ case Null:
+ return true
+ case False:
+ return true
+ case String:
+ b, err := strconv.ParseBool(strings.ToLower(t.Str))
+ if err != nil {
+ return false
+ }
+ return !b
+ case Number:
+ return t.Num == 0
+ default:
+ return false
+ }
+}
+
+func trueish(t Result) bool {
+ switch t.Type {
+ case True:
+ return true
+ case String:
+ b, err := strconv.ParseBool(strings.ToLower(t.Str))
+ if err != nil {
+ return false
+ }
+ return b
+ case Number:
+ return t.Num != 0
+ default:
+ return false
+ }
+}
+
+func nullish(t Result) bool {
+ return t.Type == Null
+}
+
+func queryMatches(rp *arrayPathResult, value Result) bool {
+ rpv := rp.query.value
+ if len(rpv) > 0 {
+ if rpv[0] == '~' {
+ // convert to bool
+ rpv = rpv[1:]
+ var ish, ok bool
+ switch rpv {
+ case "*":
+ ish, ok = value.Exists(), true
+ case "null":
+ ish, ok = nullish(value), true
+ case "true":
+ ish, ok = trueish(value), true
+ case "false":
+ ish, ok = falseish(value), true
+ }
+ if ok {
+ rpv = "true"
+ if ish {
+ value = Result{Type: True}
+ } else {
+ value = Result{Type: False}
+ }
+ } else {
+ rpv = ""
+ value = Result{}
+ }
+ }
+ }
+ if !value.Exists() {
+ return false
+ }
+ if rp.query.op == "" {
+ // the query is only looking for existence, such as:
+ // friends.#(name)
+ // which makes sure that the array "friends" has an element of
+ // "name" that exists
+ return true
+ }
+ switch value.Type {
+ case String:
+ switch rp.query.op {
+ case "=":
+ return value.Str == rpv
+ case "!=":
+ return value.Str != rpv
+ case "<":
+ return value.Str < rpv
+ case "<=":
+ return value.Str <= rpv
+ case ">":
+ return value.Str > rpv
+ case ">=":
+ return value.Str >= rpv
+ case "%":
+ return matchLimit(value.Str, rpv)
+ case "!%":
+ return !matchLimit(value.Str, rpv)
+ }
+ case Number:
+ rpvn, _ := strconv.ParseFloat(rpv, 64)
+ switch rp.query.op {
+ case "=":
+ return value.Num == rpvn
+ case "!=":
+ return value.Num != rpvn
+ case "<":
+ return value.Num < rpvn
+ case "<=":
+ return value.Num <= rpvn
+ case ">":
+ return value.Num > rpvn
+ case ">=":
+ return value.Num >= rpvn
+ }
+ case True:
+ switch rp.query.op {
+ case "=":
+ return rpv == "true"
+ case "!=":
+ return rpv != "true"
+ case ">":
+ return rpv == "false"
+ case ">=":
+ return true
+ }
+ case False:
+ switch rp.query.op {
+ case "=":
+ return rpv == "false"
+ case "!=":
+ return rpv != "false"
+ case "<":
+ return rpv == "true"
+ case "<=":
+ return true
+ }
+ }
+ return false
+}
+func parseArray(c *parseContext, i int, path string) (int, bool) {
+ var pmatch, vesc, ok, hit bool
+ var val string
+ var h int
+ var alog []int
+ var partidx int
+ var multires []byte
+ var queryIndexes []int
+ rp := parseArrayPath(path)
+ if !rp.arrch {
+ n, ok := parseUint(rp.part)
+ if !ok {
+ partidx = -1
+ } else {
+ partidx = int(n)
+ }
+ }
+ if !rp.more && rp.piped {
+ c.pipe = rp.pipe
+ c.piped = true
+ }
+
+ procQuery := func(qval Result) bool {
+ if rp.query.all {
+ if len(multires) == 0 {
+ multires = append(multires, '[')
+ }
+ }
+ var tmp parseContext
+ tmp.value = qval
+ fillIndex(c.json, &tmp)
+ parentIndex := tmp.value.Index
+ var res Result
+ if qval.Type == JSON {
+ res = qval.Get(rp.query.path)
+ } else {
+ if rp.query.path != "" {
+ return false
+ }
+ res = qval
+ }
+ if queryMatches(&rp, res) {
+ if rp.more {
+ left, right, ok := splitPossiblePipe(rp.path)
+ if ok {
+ rp.path = left
+ c.pipe = right
+ c.piped = true
+ }
+ res = qval.Get(rp.path)
+ } else {
+ res = qval
+ }
+ if rp.query.all {
+ raw := res.Raw
+ if len(raw) == 0 {
+ raw = res.String()
+ }
+ if raw != "" {
+ if len(multires) > 1 {
+ multires = append(multires, ',')
+ }
+ multires = append(multires, raw...)
+ queryIndexes = append(queryIndexes, res.Index+parentIndex)
+ }
+ } else {
+ c.value = res
+ return true
+ }
+ }
+ return false
+ }
+ for i < len(c.json)+1 {
+ if !rp.arrch {
+ pmatch = partidx == h
+ hit = pmatch && !rp.more
+ }
+ h++
+ if rp.alogok {
+ alog = append(alog, i)
+ }
+ for ; ; i++ {
+ var ch byte
+ if i > len(c.json) {
+ break
+ } else if i == len(c.json) {
+ ch = ']'
+ } else {
+ ch = c.json[i]
+ }
+ var num bool
+ switch ch {
+ default:
+ continue
+ case '"':
+ i++
+ i, val, vesc, ok = parseString(c.json, i)
+ if !ok {
+ return i, false
+ }
+ if rp.query.on {
+ var qval Result
+ if vesc {
+ qval.Str = unescape(val[1 : len(val)-1])
+ } else {
+ qval.Str = val[1 : len(val)-1]
+ }
+ qval.Raw = val
+ qval.Type = String
+ if procQuery(qval) {
+ return i, true
+ }
+ } else if hit {
+ if rp.alogok {
+ break
+ }
+ if vesc {
+ c.value.Str = unescape(val[1 : len(val)-1])
+ } else {
+ c.value.Str = val[1 : len(val)-1]
+ }
+ c.value.Raw = val
+ c.value.Type = String
+ return i, true
+ }
+ case '{':
+ if pmatch && !hit {
+ i, hit = parseObject(c, i+1, rp.path)
+ if hit {
+ if rp.alogok {
+ break
+ }
+ return i, true
+ }
+ } else {
+ i, val = parseSquash(c.json, i)
+ if rp.query.on {
+ if procQuery(Result{Raw: val, Type: JSON}) {
+ return i, true
+ }
+ } else if hit {
+ if rp.alogok {
+ break
+ }
+ c.value.Raw = val
+ c.value.Type = JSON
+ return i, true
+ }
+ }
+ case '[':
+ if pmatch && !hit {
+ i, hit = parseArray(c, i+1, rp.path)
+ if hit {
+ if rp.alogok {
+ break
+ }
+ return i, true
+ }
+ } else {
+ i, val = parseSquash(c.json, i)
+ if rp.query.on {
+ if procQuery(Result{Raw: val, Type: JSON}) {
+ return i, true
+ }
+ } else if hit {
+ if rp.alogok {
+ break
+ }
+ c.value.Raw = val
+ c.value.Type = JSON
+ return i, true
+ }
+ }
+ case 'n':
+ if i+1 < len(c.json) && c.json[i+1] != 'u' {
+ num = true
+ break
+ }
+ fallthrough
+ case 't', 'f':
+ vc := c.json[i]
+ i, val = parseLiteral(c.json, i)
+ if rp.query.on {
+ var qval Result
+ qval.Raw = val
+ switch vc {
+ case 't':
+ qval.Type = True
+ case 'f':
+ qval.Type = False
+ }
+ if procQuery(qval) {
+ return i, true
+ }
+ } else if hit {
+ if rp.alogok {
+ break
+ }
+ c.value.Raw = val
+ switch vc {
+ case 't':
+ c.value.Type = True
+ case 'f':
+ c.value.Type = False
+ }
+ return i, true
+ }
+ case '+', '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+ 'i', 'I', 'N':
+ num = true
+ case ']':
+ if rp.arrch && rp.part == "#" {
+ if rp.alogok {
+ left, right, ok := splitPossiblePipe(rp.alogkey)
+ if ok {
+ rp.alogkey = left
+ c.pipe = right
+ c.piped = true
+ }
+ var indexes = make([]int, 0, 64)
+ var jsons = make([]byte, 0, 64)
+ jsons = append(jsons, '[')
+ for j, k := 0, 0; j < len(alog); j++ {
+ idx := alog[j]
+ for idx < len(c.json) {
+ switch c.json[idx] {
+ case ' ', '\t', '\r', '\n':
+ idx++
+ continue
+ }
+ break
+ }
+ if idx < len(c.json) && c.json[idx] != ']' {
+ _, res, ok := parseAny(c.json, idx, true)
+ if ok {
+ res := res.Get(rp.alogkey)
+ if res.Exists() {
+ if k > 0 {
+ jsons = append(jsons, ',')
+ }
+ raw := res.Raw
+ if len(raw) == 0 {
+ raw = res.String()
+ }
+ jsons = append(jsons, []byte(raw)...)
+ indexes = append(indexes, res.Index)
+ k++
+ }
+ }
+ }
+ }
+ jsons = append(jsons, ']')
+ c.value.Type = JSON
+ c.value.Raw = string(jsons)
+ c.value.Indexes = indexes
+ return i + 1, true
+ }
+ if rp.alogok {
+ break
+ }
+
+ c.value.Type = Number
+ c.value.Num = float64(h - 1)
+ c.value.Raw = strconv.Itoa(h - 1)
+ c.calcd = true
+ return i + 1, true
+ }
+ if !c.value.Exists() {
+ if len(multires) > 0 {
+ c.value = Result{
+ Raw: string(append(multires, ']')),
+ Type: JSON,
+ Indexes: queryIndexes,
+ }
+ } else if rp.query.all {
+ c.value = Result{
+ Raw: "[]",
+ Type: JSON,
+ }
+ }
+ }
+ return i + 1, false
+ }
+ if num {
+ i, val = parseNumber(c.json, i)
+ if rp.query.on {
+ var qval Result
+ qval.Raw = val
+ qval.Type = Number
+ qval.Num, _ = strconv.ParseFloat(val, 64)
+ if procQuery(qval) {
+ return i, true
+ }
+ } else if hit {
+ if rp.alogok {
+ break
+ }
+ c.value.Raw = val
+ c.value.Type = Number
+ c.value.Num, _ = strconv.ParseFloat(val, 64)
+ return i, true
+ }
+ }
+ break
+ }
+ }
+ return i, false
+}
+
+func splitPossiblePipe(path string) (left, right string, ok bool) {
+ // take a quick peek for the pipe character. If found we'll split the piped
+ // part of the path into the c.pipe field and shorten the rp.
+ var possible bool
+ for i := 0; i < len(path); i++ {
+ if path[i] == '|' {
+ possible = true
+ break
+ }
+ }
+ if !possible {
+ return
+ }
+
+ if len(path) > 0 && path[0] == '{' {
+ squashed := squash(path[1:])
+ if len(squashed) < len(path)-1 {
+ squashed = path[:len(squashed)+1]
+ remain := path[len(squashed):]
+ if remain[0] == '|' {
+ return squashed, remain[1:], true
+ }
+ }
+ return
+ }
+
+ // split the left and right side of the path with the pipe character as
+ // the delimiter. This is a little tricky because we'll need to basically
+ // parse the entire path.
+ for i := 0; i < len(path); i++ {
+ if path[i] == '\\' {
+ i++
+ } else if path[i] == '.' {
+ if i == len(path)-1 {
+ return
+ }
+ if path[i+1] == '#' {
+ i += 2
+ if i == len(path) {
+ return
+ }
+ if path[i] == '[' || path[i] == '(' {
+ var start, end byte
+ if path[i] == '[' {
+ start, end = '[', ']'
+ } else {
+ start, end = '(', ')'
+ }
+ // inside selector, balance brackets
+ i++
+ depth := 1
+ for ; i < len(path); i++ {
+ if path[i] == '\\' {
+ i++
+ } else if path[i] == start {
+ depth++
+ } else if path[i] == end {
+ depth--
+ if depth == 0 {
+ break
+ }
+ } else if path[i] == '"' {
+ // inside selector string, balance quotes
+ i++
+ for ; i < len(path); i++ {
+ if path[i] == '\\' {
+ i++
+ } else if path[i] == '"' {
+ break
+ }
+ }
+ }
+ }
+ }
+ }
+ } else if path[i] == '|' {
+ return path[:i], path[i+1:], true
+ }
+ }
+ return
+}
+
+// ForEachLine iterates through lines of JSON as specified by the JSON Lines
+// format (http://jsonlines.org/).
+// Each line is returned as a GJSON Result.
+func ForEachLine(json string, iterator func(line Result) bool) {
+ var res Result
+ var i int
+ for {
+ i, res, _ = parseAny(json, i, true)
+ if !res.Exists() {
+ break
+ }
+ if !iterator(res) {
+ return
+ }
+ }
+}
+
+type subSelector struct {
+ name string
+ path string
+}
+
+// parseSubSelectors returns the subselectors belonging to a '[path1,path2]' or
+// '{"field1":path1,"field2":path2}' type subSelection. It's expected that the
+// first character in path is either '[' or '{', and has already been checked
+// prior to calling this function.
+func parseSubSelectors(path string) (sels []subSelector, out string, ok bool) {
+ modifier := 0
+ depth := 1
+ colon := 0
+ start := 1
+ i := 1
+ pushSel := func() {
+ var sel subSelector
+ if colon == 0 {
+ sel.path = path[start:i]
+ } else {
+ sel.name = path[start:colon]
+ sel.path = path[colon+1 : i]
+ }
+ sels = append(sels, sel)
+ colon = 0
+ modifier = 0
+ start = i + 1
+ }
+ for ; i < len(path); i++ {
+ switch path[i] {
+ case '\\':
+ i++
+ case '@':
+ if modifier == 0 && i > 0 && (path[i-1] == '.' || path[i-1] == '|') {
+ modifier = i
+ }
+ case ':':
+ if modifier == 0 && colon == 0 && depth == 1 {
+ colon = i
+ }
+ case ',':
+ if depth == 1 {
+ pushSel()
+ }
+ case '"':
+ i++
+ loop:
+ for ; i < len(path); i++ {
+ switch path[i] {
+ case '\\':
+ i++
+ case '"':
+ break loop
+ }
+ }
+ case '[', '(', '{':
+ depth++
+ case ']', ')', '}':
+ depth--
+ if depth == 0 {
+ pushSel()
+ path = path[i+1:]
+ return sels, path, true
+ }
+ }
+ }
+ return
+}
+
+// nameOfLast returns the name of the last component
+func nameOfLast(path string) string {
+ for i := len(path) - 1; i >= 0; i-- {
+ if path[i] == '|' || path[i] == '.' {
+ if i > 0 {
+ if path[i-1] == '\\' {
+ continue
+ }
+ }
+ return path[i+1:]
+ }
+ }
+ return path
+}
+
+func isSimpleName(component string) bool {
+ for i := 0; i < len(component); i++ {
+ if component[i] < ' ' {
+ return false
+ }
+ switch component[i] {
+ case '[', ']', '{', '}', '(', ')', '#', '|', '!':
+ return false
+ }
+ }
+ return true
+}
+
+var hexchars = [...]byte{
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+ 'a', 'b', 'c', 'd', 'e', 'f',
+}
+
+func appendHex16(dst []byte, x uint16) []byte {
+ return append(dst,
+ hexchars[x>>12&0xF], hexchars[x>>8&0xF],
+ hexchars[x>>4&0xF], hexchars[x>>0&0xF],
+ )
+}
+
+// DisableEscapeHTML will disable the automatic escaping of certain
+// "problamatic" HTML characters when encoding to JSON.
+// These character include '>', '<' and '&', which get escaped to \u003e,
+// \u0026, and \u003c respectively.
+//
+// This is a global flag and will affect all further gjson operations.
+// Ideally, if used, it should be set one time before other gjson functions
+// are called.
+var DisableEscapeHTML = false
+
+// AppendJSONString is a convenience function that converts the provided string
+// to a valid JSON string and appends it to dst.
+func AppendJSONString(dst []byte, s string) []byte {
+ dst = append(dst, make([]byte, len(s)+2)...)
+ dst = append(dst[:len(dst)-len(s)-2], '"')
+ for i := 0; i < len(s); i++ {
+ if s[i] < ' ' {
+ dst = append(dst, '\\')
+ switch s[i] {
+ case '\b':
+ dst = append(dst, 'b')
+ case '\f':
+ dst = append(dst, 'f')
+ case '\n':
+ dst = append(dst, 'n')
+ case '\r':
+ dst = append(dst, 'r')
+ case '\t':
+ dst = append(dst, 't')
+ default:
+ dst = append(dst, 'u')
+ dst = appendHex16(dst, uint16(s[i]))
+ }
+ } else if !DisableEscapeHTML &&
+ (s[i] == '>' || s[i] == '<' || s[i] == '&') {
+ dst = append(dst, '\\', 'u')
+ dst = appendHex16(dst, uint16(s[i]))
+ } else if s[i] == '\\' {
+ dst = append(dst, '\\', '\\')
+ } else if s[i] == '"' {
+ dst = append(dst, '\\', '"')
+ } else if s[i] > 127 {
+ // read utf8 character
+ r, n := utf8.DecodeRuneInString(s[i:])
+ if n == 0 {
+ break
+ }
+ if r == utf8.RuneError && n == 1 {
+ dst = append(dst, `\ufffd`...)
+ } else if r == '\u2028' || r == '\u2029' {
+ dst = append(dst, `\u202`...)
+ dst = append(dst, hexchars[r&0xF])
+ } else {
+ dst = append(dst, s[i:i+n]...)
+ }
+ i = i + n - 1
+ } else {
+ dst = append(dst, s[i])
+ }
+ }
+ return append(dst, '"')
+}
+
+type parseContext struct {
+ json string
+ value Result
+ pipe string
+ piped bool
+ calcd bool
+ lines bool
+}
+
+// Get searches json for the specified path.
+// A path is in dot syntax, such as "name.last" or "age".
+// When the value is found it's returned immediately.
+//
+// A path is a series of keys separated by a dot.
+// A key may contain special wildcard characters '*' and '?'.
+// To access an array value use the index as the key.
+// To get the number of elements in an array or to access a child path, use
+// the '#' character.
+// The dot and wildcard character can be escaped with '\'.
+//
+// {
+// "name": {"first": "Tom", "last": "Anderson"},
+// "age":37,
+// "children": ["Sara","Alex","Jack"],
+// "friends": [
+// {"first": "James", "last": "Murphy"},
+// {"first": "Roger", "last": "Craig"}
+// ]
+// }
+// "name.last" >> "Anderson"
+// "age" >> 37
+// "children" >> ["Sara","Alex","Jack"]
+// "children.#" >> 3
+// "children.1" >> "Alex"
+// "child*.2" >> "Jack"
+// "c?ildren.0" >> "Sara"
+// "friends.#.first" >> ["James","Roger"]
+//
+// This function expects that the json is well-formed, and does not validate.
+// Invalid json will not panic, but it may return back unexpected results.
+// If you are consuming JSON from an unpredictable source then you may want to
+// use the Valid function first.
+func Get(json, path string) Result {
+ if len(path) > 1 {
+ if (path[0] == '@' && !DisableModifiers) || path[0] == '!' {
+ // possible modifier
+ var ok bool
+ var npath string
+ var rjson string
+ if path[0] == '@' && !DisableModifiers {
+ npath, rjson, ok = execModifier(json, path)
+ } else if path[0] == '!' {
+ npath, rjson, ok = execStatic(json, path)
+ }
+ if ok {
+ path = npath
+ if len(path) > 0 && (path[0] == '|' || path[0] == '.') {
+ res := Get(rjson, path[1:])
+ res.Index = 0
+ res.Indexes = nil
+ return res
+ }
+ return Parse(rjson)
+ }
+ }
+ if path[0] == '[' || path[0] == '{' {
+ // using a subselector path
+ kind := path[0]
+ var ok bool
+ var subs []subSelector
+ subs, path, ok = parseSubSelectors(path)
+ if ok {
+ if len(path) == 0 || (path[0] == '|' || path[0] == '.') {
+ var b []byte
+ b = append(b, kind)
+ var i int
+ for _, sub := range subs {
+ res := Get(json, sub.path)
+ if res.Exists() {
+ if i > 0 {
+ b = append(b, ',')
+ }
+ if kind == '{' {
+ if len(sub.name) > 0 {
+ if sub.name[0] == '"' && Valid(sub.name) {
+ b = append(b, sub.name...)
+ } else {
+ b = AppendJSONString(b, sub.name)
+ }
+ } else {
+ last := nameOfLast(sub.path)
+ if isSimpleName(last) {
+ b = AppendJSONString(b, last)
+ } else {
+ b = AppendJSONString(b, "_")
+ }
+ }
+ b = append(b, ':')
+ }
+ var raw string
+ if len(res.Raw) == 0 {
+ raw = res.String()
+ if len(raw) == 0 {
+ raw = "null"
+ }
+ } else {
+ raw = res.Raw
+ }
+ b = append(b, raw...)
+ i++
+ }
+ }
+ b = append(b, kind+2)
+ var res Result
+ res.Raw = string(b)
+ res.Type = JSON
+ if len(path) > 0 {
+ res = res.Get(path[1:])
+ }
+ res.Index = 0
+ return res
+ }
+ }
+ }
+ }
+ var i int
+ var c = &parseContext{json: json}
+ if len(path) >= 2 && path[0] == '.' && path[1] == '.' {
+ c.lines = true
+ parseArray(c, 0, path[2:])
+ } else {
+ for ; i < len(c.json); i++ {
+ if c.json[i] == '{' {
+ i++
+ parseObject(c, i, path)
+ break
+ }
+ if c.json[i] == '[' {
+ i++
+ parseArray(c, i, path)
+ break
+ }
+ }
+ }
+ if c.piped {
+ res := c.value.Get(c.pipe)
+ res.Index = 0
+ return res
+ }
+ fillIndex(json, c)
+ return c.value
+}
+
+// GetBytes searches json for the specified path.
+// If working with bytes, this method preferred over Get(string(data), path)
+func GetBytes(json []byte, path string) Result {
+ return getBytes(json, path)
+}
+
+// runeit returns the rune from the the \uXXXX
+func runeit(json string) rune {
+ n, _ := strconv.ParseUint(json[:4], 16, 64)
+ return rune(n)
+}
+
+// unescape unescapes a string
+func unescape(json string) string {
+ var str = make([]byte, 0, len(json))
+ for i := 0; i < len(json); i++ {
+ switch {
+ default:
+ str = append(str, json[i])
+ case json[i] < ' ':
+ return string(str)
+ case json[i] == '\\':
+ i++
+ if i >= len(json) {
+ return string(str)
+ }
+ switch json[i] {
+ default:
+ return string(str)
+ case '\\':
+ str = append(str, '\\')
+ case '/':
+ str = append(str, '/')
+ case 'b':
+ str = append(str, '\b')
+ case 'f':
+ str = append(str, '\f')
+ case 'n':
+ str = append(str, '\n')
+ case 'r':
+ str = append(str, '\r')
+ case 't':
+ str = append(str, '\t')
+ case '"':
+ str = append(str, '"')
+ case 'u':
+ if i+5 > len(json) {
+ return string(str)
+ }
+ r := runeit(json[i+1:])
+ i += 5
+ if utf16.IsSurrogate(r) {
+ // need another code
+ if len(json[i:]) >= 6 && json[i] == '\\' &&
+ json[i+1] == 'u' {
+ // we expect it to be correct so just consume it
+ r = utf16.DecodeRune(r, runeit(json[i+2:]))
+ i += 6
+ }
+ }
+ // provide enough space to encode the largest utf8 possible
+ str = append(str, 0, 0, 0, 0, 0, 0, 0, 0)
+ n := utf8.EncodeRune(str[len(str)-8:], r)
+ str = str[:len(str)-8+n]
+ i-- // backtrack index by one
+ }
+ }
+ }
+ return string(str)
+}
+
+// Less return true if a token is less than another token.
+// The caseSensitive parameter is used when the tokens are Strings.
+// The order when comparing two different type is:
+//
+// Null < False < Number < String < True < JSON
+func (t Result) Less(token Result, caseSensitive bool) bool {
+ if t.Type < token.Type {
+ return true
+ }
+ if t.Type > token.Type {
+ return false
+ }
+ if t.Type == String {
+ if caseSensitive {
+ return t.Str < token.Str
+ }
+ return stringLessInsensitive(t.Str, token.Str)
+ }
+ if t.Type == Number {
+ return t.Num < token.Num
+ }
+ return t.Raw < token.Raw
+}
+
+func stringLessInsensitive(a, b string) bool {
+ for i := 0; i < len(a) && i < len(b); i++ {
+ if a[i] >= 'A' && a[i] <= 'Z' {
+ if b[i] >= 'A' && b[i] <= 'Z' {
+ // both are uppercase, do nothing
+ if a[i] < b[i] {
+ return true
+ } else if a[i] > b[i] {
+ return false
+ }
+ } else {
+ // a is uppercase, convert a to lowercase
+ if a[i]+32 < b[i] {
+ return true
+ } else if a[i]+32 > b[i] {
+ return false
+ }
+ }
+ } else if b[i] >= 'A' && b[i] <= 'Z' {
+ // b is uppercase, convert b to lowercase
+ if a[i] < b[i]+32 {
+ return true
+ } else if a[i] > b[i]+32 {
+ return false
+ }
+ } else {
+ // neither are uppercase
+ if a[i] < b[i] {
+ return true
+ } else if a[i] > b[i] {
+ return false
+ }
+ }
+ }
+ return len(a) < len(b)
+}
+
+// parseAny parses the next value from a json string.
+// A Result is returned when the hit param is set.
+// The return values are (i int, res Result, ok bool)
+func parseAny(json string, i int, hit bool) (int, Result, bool) {
+ var res Result
+ var val string
+ for ; i < len(json); i++ {
+ if json[i] == '{' || json[i] == '[' {
+ i, val = parseSquash(json, i)
+ if hit {
+ res.Raw = val
+ res.Type = JSON
+ }
+ var tmp parseContext
+ tmp.value = res
+ fillIndex(json, &tmp)
+ return i, tmp.value, true
+ }
+ if json[i] <= ' ' {
+ continue
+ }
+ var num bool
+ switch json[i] {
+ case '"':
+ i++
+ var vesc bool
+ var ok bool
+ i, val, vesc, ok = parseString(json, i)
+ if !ok {
+ return i, res, false
+ }
+ if hit {
+ res.Type = String
+ res.Raw = val
+ if vesc {
+ res.Str = unescape(val[1 : len(val)-1])
+ } else {
+ res.Str = val[1 : len(val)-1]
+ }
+ }
+ return i, res, true
+ case 'n':
+ if i+1 < len(json) && json[i+1] != 'u' {
+ num = true
+ break
+ }
+ fallthrough
+ case 't', 'f':
+ vc := json[i]
+ i, val = parseLiteral(json, i)
+ if hit {
+ res.Raw = val
+ switch vc {
+ case 't':
+ res.Type = True
+ case 'f':
+ res.Type = False
+ }
+ return i, res, true
+ }
+ case '+', '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+ 'i', 'I', 'N':
+ num = true
+ }
+ if num {
+ i, val = parseNumber(json, i)
+ if hit {
+ res.Raw = val
+ res.Type = Number
+ res.Num, _ = strconv.ParseFloat(val, 64)
+ }
+ return i, res, true
+ }
+
+ }
+ return i, res, false
+}
+
+// GetMany searches json for the multiple paths.
+// The return value is a Result array where the number of items
+// will be equal to the number of input paths.
+func GetMany(json string, path ...string) []Result {
+ res := make([]Result, len(path))
+ for i, path := range path {
+ res[i] = Get(json, path)
+ }
+ return res
+}
+
+// GetManyBytes searches json for the multiple paths.
+// The return value is a Result array where the number of items
+// will be equal to the number of input paths.
+func GetManyBytes(json []byte, path ...string) []Result {
+ res := make([]Result, len(path))
+ for i, path := range path {
+ res[i] = GetBytes(json, path)
+ }
+ return res
+}
+
+func validpayload(data []byte, i int) (outi int, ok bool) {
+ for ; i < len(data); i++ {
+ switch data[i] {
+ default:
+ i, ok = validany(data, i)
+ if !ok {
+ return i, false
+ }
+ for ; i < len(data); i++ {
+ switch data[i] {
+ default:
+ return i, false
+ case ' ', '\t', '\n', '\r':
+ continue
+ }
+ }
+ return i, true
+ case ' ', '\t', '\n', '\r':
+ continue
+ }
+ }
+ return i, false
+}
+func validany(data []byte, i int) (outi int, ok bool) {
+ for ; i < len(data); i++ {
+ switch data[i] {
+ default:
+ return i, false
+ case ' ', '\t', '\n', '\r':
+ continue
+ case '{':
+ return validobject(data, i+1)
+ case '[':
+ return validarray(data, i+1)
+ case '"':
+ return validstring(data, i+1)
+ case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
+ return validnumber(data, i+1)
+ case 't':
+ return validtrue(data, i+1)
+ case 'f':
+ return validfalse(data, i+1)
+ case 'n':
+ return validnull(data, i+1)
+ }
+ }
+ return i, false
+}
+func validobject(data []byte, i int) (outi int, ok bool) {
+ for ; i < len(data); i++ {
+ switch data[i] {
+ default:
+ return i, false
+ case ' ', '\t', '\n', '\r':
+ continue
+ case '}':
+ return i + 1, true
+ case '"':
+ key:
+ if i, ok = validstring(data, i+1); !ok {
+ return i, false
+ }
+ if i, ok = validcolon(data, i); !ok {
+ return i, false
+ }
+ if i, ok = validany(data, i); !ok {
+ return i, false
+ }
+ if i, ok = validcomma(data, i, '}'); !ok {
+ return i, false
+ }
+ if data[i] == '}' {
+ return i + 1, true
+ }
+ i++
+ for ; i < len(data); i++ {
+ switch data[i] {
+ default:
+ return i, false
+ case ' ', '\t', '\n', '\r':
+ continue
+ case '"':
+ goto key
+ }
+ }
+ return i, false
+ }
+ }
+ return i, false
+}
+func validcolon(data []byte, i int) (outi int, ok bool) {
+ for ; i < len(data); i++ {
+ switch data[i] {
+ default:
+ return i, false
+ case ' ', '\t', '\n', '\r':
+ continue
+ case ':':
+ return i + 1, true
+ }
+ }
+ return i, false
+}
+func validcomma(data []byte, i int, end byte) (outi int, ok bool) {
+ for ; i < len(data); i++ {
+ switch data[i] {
+ default:
+ return i, false
+ case ' ', '\t', '\n', '\r':
+ continue
+ case ',':
+ return i, true
+ case end:
+ return i, true
+ }
+ }
+ return i, false
+}
+func validarray(data []byte, i int) (outi int, ok bool) {
+ for ; i < len(data); i++ {
+ switch data[i] {
+ default:
+ for ; i < len(data); i++ {
+ if i, ok = validany(data, i); !ok {
+ return i, false
+ }
+ if i, ok = validcomma(data, i, ']'); !ok {
+ return i, false
+ }
+ if data[i] == ']' {
+ return i + 1, true
+ }
+ }
+ case ' ', '\t', '\n', '\r':
+ continue
+ case ']':
+ return i + 1, true
+ }
+ }
+ return i, false
+}
+func validstring(data []byte, i int) (outi int, ok bool) {
+ for ; i < len(data); i++ {
+ if data[i] < ' ' {
+ return i, false
+ } else if data[i] == '\\' {
+ i++
+ if i == len(data) {
+ return i, false
+ }
+ switch data[i] {
+ default:
+ return i, false
+ case '"', '\\', '/', 'b', 'f', 'n', 'r', 't':
+ case 'u':
+ for j := 0; j < 4; j++ {
+ i++
+ if i >= len(data) {
+ return i, false
+ }
+ if !((data[i] >= '0' && data[i] <= '9') ||
+ (data[i] >= 'a' && data[i] <= 'f') ||
+ (data[i] >= 'A' && data[i] <= 'F')) {
+ return i, false
+ }
+ }
+ }
+ } else if data[i] == '"' {
+ return i + 1, true
+ }
+ }
+ return i, false
+}
+func validnumber(data []byte, i int) (outi int, ok bool) {
+ i--
+ // sign
+ if data[i] == '-' {
+ i++
+ if i == len(data) {
+ return i, false
+ }
+ if data[i] < '0' || data[i] > '9' {
+ return i, false
+ }
+ }
+ // int
+ if i == len(data) {
+ return i, false
+ }
+ if data[i] == '0' {
+ i++
+ } else {
+ for ; i < len(data); i++ {
+ if data[i] >= '0' && data[i] <= '9' {
+ continue
+ }
+ break
+ }
+ }
+ // frac
+ if i == len(data) {
+ return i, true
+ }
+ if data[i] == '.' {
+ i++
+ if i == len(data) {
+ return i, false
+ }
+ if data[i] < '0' || data[i] > '9' {
+ return i, false
+ }
+ i++
+ for ; i < len(data); i++ {
+ if data[i] >= '0' && data[i] <= '9' {
+ continue
+ }
+ break
+ }
+ }
+ // exp
+ if i == len(data) {
+ return i, true
+ }
+ if data[i] == 'e' || data[i] == 'E' {
+ i++
+ if i == len(data) {
+ return i, false
+ }
+ if data[i] == '+' || data[i] == '-' {
+ i++
+ }
+ if i == len(data) {
+ return i, false
+ }
+ if data[i] < '0' || data[i] > '9' {
+ return i, false
+ }
+ i++
+ for ; i < len(data); i++ {
+ if data[i] >= '0' && data[i] <= '9' {
+ continue
+ }
+ break
+ }
+ }
+ return i, true
+}
+
+func validtrue(data []byte, i int) (outi int, ok bool) {
+ if i+3 <= len(data) && data[i] == 'r' && data[i+1] == 'u' &&
+ data[i+2] == 'e' {
+ return i + 3, true
+ }
+ return i, false
+}
+func validfalse(data []byte, i int) (outi int, ok bool) {
+ if i+4 <= len(data) && data[i] == 'a' && data[i+1] == 'l' &&
+ data[i+2] == 's' && data[i+3] == 'e' {
+ return i + 4, true
+ }
+ return i, false
+}
+func validnull(data []byte, i int) (outi int, ok bool) {
+ if i+3 <= len(data) && data[i] == 'u' && data[i+1] == 'l' &&
+ data[i+2] == 'l' {
+ return i + 3, true
+ }
+ return i, false
+}
+
+// Valid returns true if the input is valid json.
+//
+// if !gjson.Valid(json) {
+// return errors.New("invalid json")
+// }
+// value := gjson.Get(json, "name.last")
+func Valid(json string) bool {
+ _, ok := validpayload(stringBytes(json), 0)
+ return ok
+}
+
+// ValidBytes returns true if the input is valid json.
+//
+// if !gjson.Valid(json) {
+// return errors.New("invalid json")
+// }
+// value := gjson.Get(json, "name.last")
+//
+// If working with bytes, this method preferred over ValidBytes(string(data))
+func ValidBytes(json []byte) bool {
+ _, ok := validpayload(json, 0)
+ return ok
+}
+
+func parseUint(s string) (n uint64, ok bool) {
+ var i int
+ if i == len(s) {
+ return 0, false
+ }
+ for ; i < len(s); i++ {
+ if s[i] >= '0' && s[i] <= '9' {
+ n = n*10 + uint64(s[i]-'0')
+ } else {
+ return 0, false
+ }
+ }
+ return n, true
+}
+
+func parseInt(s string) (n int64, ok bool) {
+ var i int
+ var sign bool
+ if len(s) > 0 && s[0] == '-' {
+ sign = true
+ i++
+ }
+ if i == len(s) {
+ return 0, false
+ }
+ for ; i < len(s); i++ {
+ if s[i] >= '0' && s[i] <= '9' {
+ n = n*10 + int64(s[i]-'0')
+ } else {
+ return 0, false
+ }
+ }
+ if sign {
+ return n * -1, true
+ }
+ return n, true
+}
+
+// safeInt validates a given JSON number
+// ensures it lies within the minimum and maximum representable JSON numbers
+func safeInt(f float64) (n int64, ok bool) {
+ // https://tc39.es/ecma262/#sec-number.min_safe_integer
+ // https://tc39.es/ecma262/#sec-number.max_safe_integer
+ if f < -9007199254740991 || f > 9007199254740991 {
+ return 0, false
+ }
+ return int64(f), true
+}
+
+// execStatic parses the path to find a static value.
+// The input expects that the path already starts with a '!'
+func execStatic(json, path string) (pathOut, res string, ok bool) {
+ name := path[1:]
+ if len(name) > 0 {
+ switch name[0] {
+ case '{', '[', '"', '+', '-', '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9':
+ _, res = parseSquash(name, 0)
+ pathOut = name[len(res):]
+ return pathOut, res, true
+ }
+ }
+ for i := 1; i < len(path); i++ {
+ if path[i] == '|' {
+ pathOut = path[i:]
+ name = path[1:i]
+ break
+ }
+ if path[i] == '.' {
+ pathOut = path[i:]
+ name = path[1:i]
+ break
+ }
+ }
+ switch strings.ToLower(name) {
+ case "true", "false", "null", "nan", "inf":
+ return pathOut, name, true
+ }
+ return pathOut, res, false
+}
+
+// execModifier parses the path to find a matching modifier function.
+// The input expects that the path already starts with a '@'
+func execModifier(json, path string) (pathOut, res string, ok bool) {
+ name := path[1:]
+ var hasArgs bool
+ for i := 1; i < len(path); i++ {
+ if path[i] == ':' {
+ pathOut = path[i+1:]
+ name = path[1:i]
+ hasArgs = len(pathOut) > 0
+ break
+ }
+ if path[i] == '|' {
+ pathOut = path[i:]
+ name = path[1:i]
+ break
+ }
+ if path[i] == '.' {
+ pathOut = path[i:]
+ name = path[1:i]
+ break
+ }
+ }
+ if fn, ok := modifiers[name]; ok {
+ var args string
+ if hasArgs {
+ var parsedArgs bool
+ switch pathOut[0] {
+ case '{', '[', '"':
+ // json arg
+ res := Parse(pathOut)
+ if res.Exists() {
+ args = squash(pathOut)
+ pathOut = pathOut[len(args):]
+ parsedArgs = true
+ }
+ }
+ if !parsedArgs {
+ // simple arg
+ i := 0
+ for ; i < len(pathOut); i++ {
+ if pathOut[i] == '|' {
+ break
+ }
+ switch pathOut[i] {
+ case '{', '[', '"', '(':
+ s := squash(pathOut[i:])
+ i += len(s) - 1
+ }
+ }
+ args = pathOut[:i]
+ pathOut = pathOut[i:]
+ }
+ }
+ return pathOut, fn(json, args), true
+ }
+ return pathOut, res, false
+}
+
+// unwrap removes the '[]' or '{}' characters around json
+func unwrap(json string) string {
+ json = trim(json)
+ if len(json) >= 2 && (json[0] == '[' || json[0] == '{') {
+ json = json[1 : len(json)-1]
+ }
+ return json
+}
+
+// DisableModifiers will disable the modifier syntax
+var DisableModifiers = false
+
+var modifiers map[string]func(json, arg string) string
+
+func init() {
+ modifiers = map[string]func(json, arg string) string{
+ "pretty": modPretty,
+ "ugly": modUgly,
+ "reverse": modReverse,
+ "this": modThis,
+ "flatten": modFlatten,
+ "join": modJoin,
+ "valid": modValid,
+ "keys": modKeys,
+ "values": modValues,
+ "tostr": modToStr,
+ "fromstr": modFromStr,
+ "group": modGroup,
+ "dig": modDig,
+ }
+}
+
+// AddModifier binds a custom modifier command to the GJSON syntax.
+// This operation is not thread safe and should be executed prior to
+// using all other gjson function.
+func AddModifier(name string, fn func(json, arg string) string) {
+ modifiers[name] = fn
+}
+
+// ModifierExists returns true when the specified modifier exists.
+func ModifierExists(name string, fn func(json, arg string) string) bool {
+ _, ok := modifiers[name]
+ return ok
+}
+
+// cleanWS remove any non-whitespace from string
+func cleanWS(s string) string {
+ for i := 0; i < len(s); i++ {
+ switch s[i] {
+ case ' ', '\t', '\n', '\r':
+ continue
+ default:
+ var s2 []byte
+ for i := 0; i < len(s); i++ {
+ switch s[i] {
+ case ' ', '\t', '\n', '\r':
+ s2 = append(s2, s[i])
+ }
+ }
+ return string(s2)
+ }
+ }
+ return s
+}
+
+// @pretty modifier makes the json look nice.
+func modPretty(json, arg string) string {
+ if len(arg) > 0 {
+ opts := *pretty.DefaultOptions
+ Parse(arg).ForEach(func(key, value Result) bool {
+ switch key.String() {
+ case "sortKeys":
+ opts.SortKeys = value.Bool()
+ case "indent":
+ opts.Indent = cleanWS(value.String())
+ case "prefix":
+ opts.Prefix = cleanWS(value.String())
+ case "width":
+ opts.Width = int(value.Int())
+ }
+ return true
+ })
+ return bytesString(pretty.PrettyOptions(stringBytes(json), &opts))
+ }
+ return bytesString(pretty.Pretty(stringBytes(json)))
+}
+
+// @this returns the current element. Can be used to retrieve the root element.
+func modThis(json, arg string) string {
+ return json
+}
+
+// @ugly modifier removes all whitespace.
+func modUgly(json, arg string) string {
+ return bytesString(pretty.Ugly(stringBytes(json)))
+}
+
+// @reverse reverses array elements or root object members.
+func modReverse(json, arg string) string {
+ res := Parse(json)
+ if res.IsArray() {
+ var values []Result
+ res.ForEach(func(_, value Result) bool {
+ values = append(values, value)
+ return true
+ })
+ out := make([]byte, 0, len(json))
+ out = append(out, '[')
+ for i, j := len(values)-1, 0; i >= 0; i, j = i-1, j+1 {
+ if j > 0 {
+ out = append(out, ',')
+ }
+ out = append(out, values[i].Raw...)
+ }
+ out = append(out, ']')
+ return bytesString(out)
+ }
+ if res.IsObject() {
+ var keyValues []Result
+ res.ForEach(func(key, value Result) bool {
+ keyValues = append(keyValues, key, value)
+ return true
+ })
+ out := make([]byte, 0, len(json))
+ out = append(out, '{')
+ for i, j := len(keyValues)-2, 0; i >= 0; i, j = i-2, j+1 {
+ if j > 0 {
+ out = append(out, ',')
+ }
+ out = append(out, keyValues[i+0].Raw...)
+ out = append(out, ':')
+ out = append(out, keyValues[i+1].Raw...)
+ }
+ out = append(out, '}')
+ return bytesString(out)
+ }
+ return json
+}
+
+// @flatten an array with child arrays.
+//
+// [1,[2],[3,4],[5,[6,7]]] -> [1,2,3,4,5,[6,7]]
+//
+// The {"deep":true} arg can be provide for deep flattening.
+//
+// [1,[2],[3,4],[5,[6,7]]] -> [1,2,3,4,5,6,7]
+//
+// The original json is returned when the json is not an array.
+func modFlatten(json, arg string) string {
+ res := Parse(json)
+ if !res.IsArray() {
+ return json
+ }
+ var deep bool
+ if arg != "" {
+ Parse(arg).ForEach(func(key, value Result) bool {
+ if key.String() == "deep" {
+ deep = value.Bool()
+ }
+ return true
+ })
+ }
+ var out []byte
+ out = append(out, '[')
+ var idx int
+ res.ForEach(func(_, value Result) bool {
+ var raw string
+ if value.IsArray() {
+ if deep {
+ raw = unwrap(modFlatten(value.Raw, arg))
+ } else {
+ raw = unwrap(value.Raw)
+ }
+ } else {
+ raw = value.Raw
+ }
+ raw = strings.TrimSpace(raw)
+ if len(raw) > 0 {
+ if idx > 0 {
+ out = append(out, ',')
+ }
+ out = append(out, raw...)
+ idx++
+ }
+ return true
+ })
+ out = append(out, ']')
+ return bytesString(out)
+}
+
+// @keys extracts the keys from an object.
+//
+// {"first":"Tom","last":"Smith"} -> ["first","last"]
+func modKeys(json, arg string) string {
+ v := Parse(json)
+ if !v.Exists() {
+ return "[]"
+ }
+ obj := v.IsObject()
+ var out strings.Builder
+ out.WriteByte('[')
+ var i int
+ v.ForEach(func(key, _ Result) bool {
+ if i > 0 {
+ out.WriteByte(',')
+ }
+ if obj {
+ out.WriteString(key.Raw)
+ } else {
+ out.WriteString("null")
+ }
+ i++
+ return true
+ })
+ out.WriteByte(']')
+ return out.String()
+}
+
+// @values extracts the values from an object.
+//
+// {"first":"Tom","last":"Smith"} -> ["Tom","Smith"]
+func modValues(json, arg string) string {
+ v := Parse(json)
+ if !v.Exists() {
+ return "[]"
+ }
+ if v.IsArray() {
+ return json
+ }
+ var out strings.Builder
+ out.WriteByte('[')
+ var i int
+ v.ForEach(func(_, value Result) bool {
+ if i > 0 {
+ out.WriteByte(',')
+ }
+ out.WriteString(value.Raw)
+ i++
+ return true
+ })
+ out.WriteByte(']')
+ return out.String()
+}
+
+// @join multiple objects into a single object.
+//
+// [{"first":"Tom"},{"last":"Smith"}] -> {"first","Tom","last":"Smith"}
+//
+// The arg can be "true" to specify that duplicate keys should be preserved.
+//
+// [{"first":"Tom","age":37},{"age":41}] -> {"first","Tom","age":37,"age":41}
+//
+// Without preserved keys:
+//
+// [{"first":"Tom","age":37},{"age":41}] -> {"first","Tom","age":41}
+//
+// The original json is returned when the json is not an object.
+func modJoin(json, arg string) string {
+ res := Parse(json)
+ if !res.IsArray() {
+ return json
+ }
+ var preserve bool
+ if arg != "" {
+ Parse(arg).ForEach(func(key, value Result) bool {
+ if key.String() == "preserve" {
+ preserve = value.Bool()
+ }
+ return true
+ })
+ }
+ var out []byte
+ out = append(out, '{')
+ if preserve {
+ // Preserve duplicate keys.
+ var idx int
+ res.ForEach(func(_, value Result) bool {
+ if !value.IsObject() {
+ return true
+ }
+ if idx > 0 {
+ out = append(out, ',')
+ }
+ out = append(out, unwrap(value.Raw)...)
+ idx++
+ return true
+ })
+ } else {
+ // Deduplicate keys and generate an object with stable ordering.
+ var keys []Result
+ kvals := make(map[string]Result)
+ res.ForEach(func(_, value Result) bool {
+ if !value.IsObject() {
+ return true
+ }
+ value.ForEach(func(key, value Result) bool {
+ k := key.String()
+ if _, ok := kvals[k]; !ok {
+ keys = append(keys, key)
+ }
+ kvals[k] = value
+ return true
+ })
+ return true
+ })
+ for i := 0; i < len(keys); i++ {
+ if i > 0 {
+ out = append(out, ',')
+ }
+ out = append(out, keys[i].Raw...)
+ out = append(out, ':')
+ out = append(out, kvals[keys[i].String()].Raw...)
+ }
+ }
+ out = append(out, '}')
+ return bytesString(out)
+}
+
+// @valid ensures that the json is valid before moving on. An empty string is
+// returned when the json is not valid, otherwise it returns the original json.
+func modValid(json, arg string) string {
+ if !Valid(json) {
+ return ""
+ }
+ return json
+}
+
+// @fromstr converts a string to json
+//
+// "{\"id\":1023,\"name\":\"alert\"}" -> {"id":1023,"name":"alert"}
+func modFromStr(json, arg string) string {
+ if !Valid(json) {
+ return ""
+ }
+ return Parse(json).String()
+}
+
+// @tostr converts a string to json
+//
+// {"id":1023,"name":"alert"} -> "{\"id\":1023,\"name\":\"alert\"}"
+func modToStr(str, arg string) string {
+ return string(AppendJSONString(nil, str))
+}
+
+func modGroup(json, arg string) string {
+ res := Parse(json)
+ if !res.IsObject() {
+ return ""
+ }
+ var all [][]byte
+ res.ForEach(func(key, value Result) bool {
+ if !value.IsArray() {
+ return true
+ }
+ var idx int
+ value.ForEach(func(_, value Result) bool {
+ if idx == len(all) {
+ all = append(all, []byte{})
+ }
+ all[idx] = append(all[idx], ("," + key.Raw + ":" + value.Raw)...)
+ idx++
+ return true
+ })
+ return true
+ })
+ var data []byte
+ data = append(data, '[')
+ for i, item := range all {
+ if i > 0 {
+ data = append(data, ',')
+ }
+ data = append(data, '{')
+ data = append(data, item[1:]...)
+ data = append(data, '}')
+ }
+ data = append(data, ']')
+ return string(data)
+}
+
+// stringHeader instead of reflect.StringHeader
+type stringHeader struct {
+ data unsafe.Pointer
+ len int
+}
+
+// sliceHeader instead of reflect.SliceHeader
+type sliceHeader struct {
+ data unsafe.Pointer
+ len int
+ cap int
+}
+
+// getBytes casts the input json bytes to a string and safely returns the
+// results as uniquely allocated data. This operation is intended to minimize
+// copies and allocations for the large json string->[]byte.
+func getBytes(json []byte, path string) Result {
+ var result Result
+ if json != nil {
+ // unsafe cast to string
+ result = Get(*(*string)(unsafe.Pointer(&json)), path)
+ // safely get the string headers
+ rawhi := *(*stringHeader)(unsafe.Pointer(&result.Raw))
+ strhi := *(*stringHeader)(unsafe.Pointer(&result.Str))
+ // create byte slice headers
+ rawh := sliceHeader{data: rawhi.data, len: rawhi.len, cap: rawhi.len}
+ strh := sliceHeader{data: strhi.data, len: strhi.len, cap: rawhi.len}
+ if strh.data == nil {
+ // str is nil
+ if rawh.data == nil {
+ // raw is nil
+ result.Raw = ""
+ } else {
+ // raw has data, safely copy the slice header to a string
+ result.Raw = string(*(*[]byte)(unsafe.Pointer(&rawh)))
+ }
+ result.Str = ""
+ } else if rawh.data == nil {
+ // raw is nil
+ result.Raw = ""
+ // str has data, safely copy the slice header to a string
+ result.Str = string(*(*[]byte)(unsafe.Pointer(&strh)))
+ } else if uintptr(strh.data) >= uintptr(rawh.data) &&
+ uintptr(strh.data)+uintptr(strh.len) <=
+ uintptr(rawh.data)+uintptr(rawh.len) {
+ // Str is a substring of Raw.
+ start := uintptr(strh.data) - uintptr(rawh.data)
+ // safely copy the raw slice header
+ result.Raw = string(*(*[]byte)(unsafe.Pointer(&rawh)))
+ // substring the raw
+ result.Str = result.Raw[start : start+uintptr(strh.len)]
+ } else {
+ // safely copy both the raw and str slice headers to strings
+ result.Raw = string(*(*[]byte)(unsafe.Pointer(&rawh)))
+ result.Str = string(*(*[]byte)(unsafe.Pointer(&strh)))
+ }
+ }
+ return result
+}
+
+// fillIndex finds the position of Raw data and assigns it to the Index field
+// of the resulting value. If the position cannot be found then Index zero is
+// used instead.
+func fillIndex(json string, c *parseContext) {
+ if len(c.value.Raw) > 0 && !c.calcd {
+ jhdr := *(*stringHeader)(unsafe.Pointer(&json))
+ rhdr := *(*stringHeader)(unsafe.Pointer(&(c.value.Raw)))
+ c.value.Index = int(uintptr(rhdr.data) - uintptr(jhdr.data))
+ if c.value.Index < 0 || c.value.Index >= len(json) {
+ c.value.Index = 0
+ }
+ }
+}
+
+func stringBytes(s string) []byte {
+ return *(*[]byte)(unsafe.Pointer(&sliceHeader{
+ data: (*stringHeader)(unsafe.Pointer(&s)).data,
+ len: len(s),
+ cap: len(s),
+ }))
+}
+
+func bytesString(b []byte) string {
+ return *(*string)(unsafe.Pointer(&b))
+}
+
+func revSquash(json string) string {
+ // reverse squash
+ // expects that the tail character is a ']' or '}' or ')' or '"'
+ // squash the value, ignoring all nested arrays and objects.
+ i := len(json) - 1
+ var depth int
+ if json[i] != '"' {
+ depth++
+ }
+ if json[i] == '}' || json[i] == ']' || json[i] == ')' {
+ i--
+ }
+ for ; i >= 0; i-- {
+ switch json[i] {
+ case '"':
+ i--
+ for ; i >= 0; i-- {
+ if json[i] == '"' {
+ esc := 0
+ for i > 0 && json[i-1] == '\\' {
+ i--
+ esc++
+ }
+ if esc%2 == 1 {
+ continue
+ }
+ i += esc
+ break
+ }
+ }
+ if depth == 0 {
+ if i < 0 {
+ i = 0
+ }
+ return json[i:]
+ }
+ case '}', ']', ')':
+ depth++
+ case '{', '[', '(':
+ depth--
+ if depth == 0 {
+ return json[i:]
+ }
+ }
+ }
+ return json
+}
+
+// Paths returns the original GJSON paths for a Result where the Result came
+// from a simple query path that returns an array, like:
+//
+// gjson.Get(json, "friends.#.first")
+//
+// The returned value will be in the form of a JSON array:
+//
+// ["friends.0.first","friends.1.first","friends.2.first"]
+//
+// The param 'json' must be the original JSON used when calling Get.
+//
+// Returns an empty string if the paths cannot be determined, which can happen
+// when the Result came from a path that contained a multipath, modifier,
+// or a nested query.
+func (t Result) Paths(json string) []string {
+ if t.Indexes == nil {
+ return nil
+ }
+ paths := make([]string, 0, len(t.Indexes))
+ t.ForEach(func(_, value Result) bool {
+ paths = append(paths, value.Path(json))
+ return true
+ })
+ if len(paths) != len(t.Indexes) {
+ return nil
+ }
+ return paths
+}
+
+// Path returns the original GJSON path for a Result where the Result came
+// from a simple path that returns a single value, like:
+//
+// gjson.Get(json, "friends.#(last=Murphy)")
+//
+// The returned value will be in the form of a JSON string:
+//
+// "friends.0"
+//
+// The param 'json' must be the original JSON used when calling Get.
+//
+// Returns an empty string if the paths cannot be determined, which can happen
+// when the Result came from a path that contained a multipath, modifier,
+// or a nested query.
+func (t Result) Path(json string) string {
+ var path []byte
+ var comps []string // raw components
+ i := t.Index - 1
+ if t.Index+len(t.Raw) > len(json) {
+ // JSON cannot safely contain Result.
+ goto fail
+ }
+ if !strings.HasPrefix(json[t.Index:], t.Raw) {
+ // Result is not at the JSON index as expected.
+ goto fail
+ }
+ for ; i >= 0; i-- {
+ if json[i] <= ' ' {
+ continue
+ }
+ if json[i] == ':' {
+ // inside of object, get the key
+ for ; i >= 0; i-- {
+ if json[i] != '"' {
+ continue
+ }
+ break
+ }
+ raw := revSquash(json[:i+1])
+ i = i - len(raw)
+ comps = append(comps, raw)
+ // key gotten, now squash the rest
+ raw = revSquash(json[:i+1])
+ i = i - len(raw)
+ i++ // increment the index for next loop step
+ } else if json[i] == '{' {
+ // Encountered an open object. The original result was probably an
+ // object key.
+ goto fail
+ } else if json[i] == ',' || json[i] == '[' {
+ // inside of an array, count the position
+ var arrIdx int
+ if json[i] == ',' {
+ arrIdx++
+ i--
+ }
+ for ; i >= 0; i-- {
+ if json[i] == ':' {
+ // Encountered an unexpected colon. The original result was
+ // probably an object key.
+ goto fail
+ } else if json[i] == ',' {
+ arrIdx++
+ } else if json[i] == '[' {
+ comps = append(comps, strconv.Itoa(arrIdx))
+ break
+ } else if json[i] == ']' || json[i] == '}' || json[i] == '"' {
+ raw := revSquash(json[:i+1])
+ i = i - len(raw) + 1
+ }
+ }
+ }
+ }
+ if len(comps) == 0 {
+ if DisableModifiers {
+ goto fail
+ }
+ return "@this"
+ }
+ for i := len(comps) - 1; i >= 0; i-- {
+ rcomp := Parse(comps[i])
+ if !rcomp.Exists() {
+ goto fail
+ }
+ comp := Escape(rcomp.String())
+ path = append(path, '.')
+ path = append(path, comp...)
+ }
+ if len(path) > 0 {
+ path = path[1:]
+ }
+ return string(path)
+fail:
+ return ""
+}
+
+// isSafePathKeyChar returns true if the input character is safe for not
+// needing escaping.
+func isSafePathKeyChar(c byte) bool {
+ return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
+ (c >= '0' && c <= '9') || c <= ' ' || c > '~' || c == '_' ||
+ c == '-' || c == ':'
+}
+
+// Escape returns an escaped path component.
+//
+// json := `{
+// "user":{
+// "first.name": "Janet",
+// "last.name": "Prichard"
+// }
+// }`
+// user := gjson.Get(json, "user")
+// println(user.Get(gjson.Escape("first.name"))
+// println(user.Get(gjson.Escape("last.name"))
+// // Output:
+// // Janet
+// // Prichard
+func Escape(comp string) string {
+ for i := 0; i < len(comp); i++ {
+ if !isSafePathKeyChar(comp[i]) {
+ ncomp := make([]byte, len(comp)+1)
+ copy(ncomp, comp[:i])
+ ncomp = ncomp[:i]
+ for ; i < len(comp); i++ {
+ if !isSafePathKeyChar(comp[i]) {
+ ncomp = append(ncomp, '\\')
+ }
+ ncomp = append(ncomp, comp[i])
+ }
+ return string(ncomp)
+ }
+ }
+ return comp
+}
+
+func parseRecursiveDescent(all []Result, parent Result, path string) []Result {
+ if res := parent.Get(path); res.Exists() {
+ all = append(all, res)
+ }
+ if parent.IsArray() || parent.IsObject() {
+ parent.ForEach(func(_, val Result) bool {
+ all = parseRecursiveDescent(all, val, path)
+ return true
+ })
+ }
+ return all
+}
+
+func modDig(json, arg string) string {
+ all := parseRecursiveDescent(nil, Parse(json), arg)
+ var out []byte
+ out = append(out, '[')
+ for i, res := range all {
+ if i > 0 {
+ out = append(out, ',')
+ }
+ out = append(out, res.Raw...)
+ }
+ out = append(out, ']')
+ return string(out)
+}
diff --git a/vendor/github.com/tidwall/match/LICENSE b/vendor/github.com/tidwall/match/LICENSE
new file mode 100644
index 0000000..58f5819
--- /dev/null
+++ b/vendor/github.com/tidwall/match/LICENSE
@@ -0,0 +1,20 @@
+The MIT License (MIT)
+
+Copyright (c) 2016 Josh Baker
+
+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/tidwall/match/README.md b/vendor/github.com/tidwall/match/README.md
new file mode 100644
index 0000000..5fdd4cf
--- /dev/null
+++ b/vendor/github.com/tidwall/match/README.md
@@ -0,0 +1,29 @@
+# Match
+
+[![GoDoc](https://godoc.org/github.com/tidwall/match?status.svg)](https://godoc.org/github.com/tidwall/match)
+
+Match is a very simple pattern matcher where '*' matches on any
+number characters and '?' matches on any one character.
+
+## Installing
+
+```
+go get -u github.com/tidwall/match
+```
+
+## Example
+
+```go
+match.Match("hello", "*llo")
+match.Match("jello", "?ello")
+match.Match("hello", "h*o")
+```
+
+
+## Contact
+
+Josh Baker [@tidwall](http://twitter.com/tidwall)
+
+## License
+
+Redcon source code is available under the MIT [License](/LICENSE).
diff --git a/vendor/github.com/tidwall/match/match.go b/vendor/github.com/tidwall/match/match.go
new file mode 100644
index 0000000..11da28f
--- /dev/null
+++ b/vendor/github.com/tidwall/match/match.go
@@ -0,0 +1,237 @@
+// Package match provides a simple pattern matcher with unicode support.
+package match
+
+import (
+ "unicode/utf8"
+)
+
+// Match returns true if str matches pattern. This is a very
+// simple wildcard match where '*' matches on any number characters
+// and '?' matches on any one character.
+//
+// pattern:
+// { term }
+// term:
+// '*' matches any sequence of non-Separator characters
+// '?' matches any single non-Separator character
+// c matches character c (c != '*', '?', '\\')
+// '\\' c matches character c
+//
+func Match(str, pattern string) bool {
+ if pattern == "*" {
+ return true
+ }
+ return match(str, pattern, 0, nil, -1) == rMatch
+}
+
+// MatchLimit is the same as Match but will limit the complexity of the match
+// operation. This is to avoid long running matches, specifically to avoid ReDos
+// attacks from arbritary inputs.
+//
+// How it works:
+// The underlying match routine is recursive and may call itself when it
+// encounters a sandwiched wildcard pattern, such as: `user:*:name`.
+// Everytime it calls itself a counter is incremented.
+// The operation is stopped when counter > maxcomp*len(str).
+func MatchLimit(str, pattern string, maxcomp int) (matched, stopped bool) {
+ if pattern == "*" {
+ return true, false
+ }
+ counter := 0
+ r := match(str, pattern, len(str), &counter, maxcomp)
+ if r == rStop {
+ return false, true
+ }
+ return r == rMatch, false
+}
+
+type result int
+
+const (
+ rNoMatch result = iota
+ rMatch
+ rStop
+)
+
+func match(str, pat string, slen int, counter *int, maxcomp int) result {
+ // check complexity limit
+ if maxcomp > -1 {
+ if *counter > slen*maxcomp {
+ return rStop
+ }
+ *counter++
+ }
+
+ for len(pat) > 0 {
+ var wild bool
+ pc, ps := rune(pat[0]), 1
+ if pc > 0x7f {
+ pc, ps = utf8.DecodeRuneInString(pat)
+ }
+ var sc rune
+ var ss int
+ if len(str) > 0 {
+ sc, ss = rune(str[0]), 1
+ if sc > 0x7f {
+ sc, ss = utf8.DecodeRuneInString(str)
+ }
+ }
+ switch pc {
+ case '?':
+ if ss == 0 {
+ return rNoMatch
+ }
+ case '*':
+ // Ignore repeating stars.
+ for len(pat) > 1 && pat[1] == '*' {
+ pat = pat[1:]
+ }
+
+ // If this star is the last character then it must be a match.
+ if len(pat) == 1 {
+ return rMatch
+ }
+
+ // Match and trim any non-wildcard suffix characters.
+ var ok bool
+ str, pat, ok = matchTrimSuffix(str, pat)
+ if !ok {
+ return rNoMatch
+ }
+
+ // Check for single star again.
+ if len(pat) == 1 {
+ return rMatch
+ }
+
+ // Perform recursive wildcard search.
+ r := match(str, pat[1:], slen, counter, maxcomp)
+ if r != rNoMatch {
+ return r
+ }
+ if len(str) == 0 {
+ return rNoMatch
+ }
+ wild = true
+ default:
+ if ss == 0 {
+ return rNoMatch
+ }
+ if pc == '\\' {
+ pat = pat[ps:]
+ pc, ps = utf8.DecodeRuneInString(pat)
+ if ps == 0 {
+ return rNoMatch
+ }
+ }
+ if sc != pc {
+ return rNoMatch
+ }
+ }
+ str = str[ss:]
+ if !wild {
+ pat = pat[ps:]
+ }
+ }
+ if len(str) == 0 {
+ return rMatch
+ }
+ return rNoMatch
+}
+
+// matchTrimSuffix matches and trims any non-wildcard suffix characters.
+// Returns the trimed string and pattern.
+//
+// This is called because the pattern contains extra data after the wildcard
+// star. Here we compare any suffix characters in the pattern to the suffix of
+// the target string. Basically a reverse match that stops when a wildcard
+// character is reached. This is a little trickier than a forward match because
+// we need to evaluate an escaped character in reverse.
+//
+// Any matched characters will be trimmed from both the target
+// string and the pattern.
+func matchTrimSuffix(str, pat string) (string, string, bool) {
+ // It's expected that the pattern has at least two bytes and the first byte
+ // is a wildcard star '*'
+ match := true
+ for len(str) > 0 && len(pat) > 1 {
+ pc, ps := utf8.DecodeLastRuneInString(pat)
+ var esc bool
+ for i := 0; ; i++ {
+ if pat[len(pat)-ps-i-1] != '\\' {
+ if i&1 == 1 {
+ esc = true
+ ps++
+ }
+ break
+ }
+ }
+ if pc == '*' && !esc {
+ match = true
+ break
+ }
+ sc, ss := utf8.DecodeLastRuneInString(str)
+ if !((pc == '?' && !esc) || pc == sc) {
+ match = false
+ break
+ }
+ str = str[:len(str)-ss]
+ pat = pat[:len(pat)-ps]
+ }
+ return str, pat, match
+}
+
+var maxRuneBytes = [...]byte{244, 143, 191, 191}
+
+// Allowable parses the pattern and determines the minimum and maximum allowable
+// values that the pattern can represent.
+// When the max cannot be determined, 'true' will be returned
+// for infinite.
+func Allowable(pattern string) (min, max string) {
+ if pattern == "" || pattern[0] == '*' {
+ return "", ""
+ }
+
+ minb := make([]byte, 0, len(pattern))
+ maxb := make([]byte, 0, len(pattern))
+ var wild bool
+ for i := 0; i < len(pattern); i++ {
+ if pattern[i] == '*' {
+ wild = true
+ break
+ }
+ if pattern[i] == '?' {
+ minb = append(minb, 0)
+ maxb = append(maxb, maxRuneBytes[:]...)
+ } else {
+ minb = append(minb, pattern[i])
+ maxb = append(maxb, pattern[i])
+ }
+ }
+ if wild {
+ r, n := utf8.DecodeLastRune(maxb)
+ if r != utf8.RuneError {
+ if r < utf8.MaxRune {
+ r++
+ if r > 0x7f {
+ b := make([]byte, 4)
+ nn := utf8.EncodeRune(b, r)
+ maxb = append(maxb[:len(maxb)-n], b[:nn]...)
+ } else {
+ maxb = append(maxb[:len(maxb)-n], byte(r))
+ }
+ }
+ }
+ }
+ return string(minb), string(maxb)
+}
+
+// IsPattern returns true if the string is a pattern.
+func IsPattern(str string) bool {
+ for i := 0; i < len(str); i++ {
+ if str[i] == '*' || str[i] == '?' {
+ return true
+ }
+ }
+ return false
+}
diff --git a/vendor/github.com/tidwall/pretty/LICENSE b/vendor/github.com/tidwall/pretty/LICENSE
new file mode 100644
index 0000000..993b83f
--- /dev/null
+++ b/vendor/github.com/tidwall/pretty/LICENSE
@@ -0,0 +1,20 @@
+The MIT License (MIT)
+
+Copyright (c) 2017 Josh Baker
+
+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/tidwall/pretty/README.md b/vendor/github.com/tidwall/pretty/README.md
new file mode 100644
index 0000000..76c06a5
--- /dev/null
+++ b/vendor/github.com/tidwall/pretty/README.md
@@ -0,0 +1,122 @@
+# Pretty
+
+[![GoDoc](https://img.shields.io/badge/api-reference-blue.svg?style=flat-square)](https://pkg.go.dev/github.com/tidwall/pretty)
+
+Pretty is a Go package that provides [fast](#performance) methods for formatting JSON for human readability, or to compact JSON for smaller payloads.
+
+Getting Started
+===============
+
+## Installing
+
+To start using Pretty, install Go and run `go get`:
+
+```sh
+$ go get -u github.com/tidwall/pretty
+```
+
+This will retrieve the library.
+
+## Pretty
+
+Using this example:
+
+```json
+{"name": {"first":"Tom","last":"Anderson"}, "age":37,
+"children": ["Sara","Alex","Jack"],
+"fav.movie": "Deer Hunter", "friends": [
+ {"first": "Janet", "last": "Murphy", "age": 44}
+ ]}
+```
+
+The following code:
+```go
+result = pretty.Pretty(example)
+```
+
+Will format the json to:
+
+```json
+{
+ "name": {
+ "first": "Tom",
+ "last": "Anderson"
+ },
+ "age": 37,
+ "children": ["Sara", "Alex", "Jack"],
+ "fav.movie": "Deer Hunter",
+ "friends": [
+ {
+ "first": "Janet",
+ "last": "Murphy",
+ "age": 44
+ }
+ ]
+}
+```
+
+## Color
+
+Color will colorize the json for outputing to the screen.
+
+```go
+result = pretty.Color(json, nil)
+```
+
+Will add color to the result for printing to the terminal.
+The second param is used for a customizing the style, and passing nil will use the default `pretty.TerminalStyle`.
+
+## Ugly
+
+The following code:
+```go
+result = pretty.Ugly(example)
+```
+
+Will format the json to:
+
+```json
+{"name":{"first":"Tom","last":"Anderson"},"age":37,"children":["Sara","Alex","Jack"],"fav.movie":"Deer Hunter","friends":[{"first":"Janet","last":"Murphy","age":44}]}```
+```
+
+## Customized output
+
+There's a `PrettyOptions(json, opts)` function which allows for customizing the output with the following options:
+
+```go
+type Options struct {
+ // Width is an max column width for single line arrays
+ // Default is 80
+ Width int
+ // Prefix is a prefix for all lines
+ // Default is an empty string
+ Prefix string
+ // Indent is the nested indentation
+ // Default is two spaces
+ Indent string
+ // SortKeys will sort the keys alphabetically
+ // Default is false
+ SortKeys bool
+}
+```
+## Performance
+
+Benchmarks of Pretty alongside the builtin `encoding/json` Indent/Compact methods.
+```
+BenchmarkPretty-16 1000000 1034 ns/op 720 B/op 2 allocs/op
+BenchmarkPrettySortKeys-16 586797 1983 ns/op 2848 B/op 14 allocs/op
+BenchmarkUgly-16 4652365 254 ns/op 240 B/op 1 allocs/op
+BenchmarkUglyInPlace-16 6481233 183 ns/op 0 B/op 0 allocs/op
+BenchmarkJSONIndent-16 450654 2687 ns/op 1221 B/op 0 allocs/op
+BenchmarkJSONCompact-16 685111 1699 ns/op 442 B/op 0 allocs/op
+```
+
+*These benchmarks were run on a MacBook Pro 2.4 GHz 8-Core Intel Core i9.*
+
+## Contact
+Josh Baker [@tidwall](http://twitter.com/tidwall)
+
+## License
+
+Pretty source code is available under the MIT [License](/LICENSE).
+
diff --git a/vendor/github.com/tidwall/pretty/pretty.go b/vendor/github.com/tidwall/pretty/pretty.go
new file mode 100644
index 0000000..d705f9c
--- /dev/null
+++ b/vendor/github.com/tidwall/pretty/pretty.go
@@ -0,0 +1,682 @@
+package pretty
+
+import (
+ "bytes"
+ "encoding/json"
+ "sort"
+ "strconv"
+)
+
+// Options is Pretty options
+type Options struct {
+ // Width is an max column width for single line arrays
+ // Default is 80
+ Width int
+ // Prefix is a prefix for all lines
+ // Default is an empty string
+ Prefix string
+ // Indent is the nested indentation
+ // Default is two spaces
+ Indent string
+ // SortKeys will sort the keys alphabetically
+ // Default is false
+ SortKeys bool
+}
+
+// DefaultOptions is the default options for pretty formats.
+var DefaultOptions = &Options{Width: 80, Prefix: "", Indent: " ", SortKeys: false}
+
+// Pretty converts the input json into a more human readable format where each
+// element is on it's own line with clear indentation.
+func Pretty(json []byte) []byte { return PrettyOptions(json, nil) }
+
+// PrettyOptions is like Pretty but with customized options.
+func PrettyOptions(json []byte, opts *Options) []byte {
+ if opts == nil {
+ opts = DefaultOptions
+ }
+ buf := make([]byte, 0, len(json))
+ if len(opts.Prefix) != 0 {
+ buf = append(buf, opts.Prefix...)
+ }
+ buf, _, _, _ = appendPrettyAny(buf, json, 0, true,
+ opts.Width, opts.Prefix, opts.Indent, opts.SortKeys,
+ 0, 0, -1)
+ if len(buf) > 0 {
+ buf = append(buf, '\n')
+ }
+ return buf
+}
+
+// Ugly removes insignificant space characters from the input json byte slice
+// and returns the compacted result.
+func Ugly(json []byte) []byte {
+ buf := make([]byte, 0, len(json))
+ return ugly(buf, json)
+}
+
+// UglyInPlace removes insignificant space characters from the input json
+// byte slice and returns the compacted result. This method reuses the
+// input json buffer to avoid allocations. Do not use the original bytes
+// slice upon return.
+func UglyInPlace(json []byte) []byte { return ugly(json, json) }
+
+func ugly(dst, src []byte) []byte {
+ dst = dst[:0]
+ for i := 0; i < len(src); i++ {
+ if src[i] > ' ' {
+ dst = append(dst, src[i])
+ if src[i] == '"' {
+ for i = i + 1; i < len(src); i++ {
+ dst = append(dst, src[i])
+ if src[i] == '"' {
+ j := i - 1
+ for ; ; j-- {
+ if src[j] != '\\' {
+ break
+ }
+ }
+ if (j-i)%2 != 0 {
+ break
+ }
+ }
+ }
+ }
+ }
+ }
+ return dst
+}
+
+func isNaNOrInf(src []byte) bool {
+ return src[0] == 'i' || //Inf
+ src[0] == 'I' || // inf
+ src[0] == '+' || // +Inf
+ src[0] == 'N' || // Nan
+ (src[0] == 'n' && len(src) > 1 && src[1] != 'u') // nan
+}
+
+func appendPrettyAny(buf, json []byte, i int, pretty bool, width int, prefix, indent string, sortkeys bool, tabs, nl, max int) ([]byte, int, int, bool) {
+ for ; i < len(json); i++ {
+ if json[i] <= ' ' {
+ continue
+ }
+ if json[i] == '"' {
+ return appendPrettyString(buf, json, i, nl)
+ }
+
+ if (json[i] >= '0' && json[i] <= '9') || json[i] == '-' || isNaNOrInf(json[i:]) {
+ return appendPrettyNumber(buf, json, i, nl)
+ }
+ if json[i] == '{' {
+ return appendPrettyObject(buf, json, i, '{', '}', pretty, width, prefix, indent, sortkeys, tabs, nl, max)
+ }
+ if json[i] == '[' {
+ return appendPrettyObject(buf, json, i, '[', ']', pretty, width, prefix, indent, sortkeys, tabs, nl, max)
+ }
+ switch json[i] {
+ case 't':
+ return append(buf, 't', 'r', 'u', 'e'), i + 4, nl, true
+ case 'f':
+ return append(buf, 'f', 'a', 'l', 's', 'e'), i + 5, nl, true
+ case 'n':
+ return append(buf, 'n', 'u', 'l', 'l'), i + 4, nl, true
+ }
+ }
+ return buf, i, nl, true
+}
+
+type pair struct {
+ kstart, kend int
+ vstart, vend int
+}
+
+type byKeyVal struct {
+ sorted bool
+ json []byte
+ buf []byte
+ pairs []pair
+}
+
+func (arr *byKeyVal) Len() int {
+ return len(arr.pairs)
+}
+func (arr *byKeyVal) Less(i, j int) bool {
+ if arr.isLess(i, j, byKey) {
+ return true
+ }
+ if arr.isLess(j, i, byKey) {
+ return false
+ }
+ return arr.isLess(i, j, byVal)
+}
+func (arr *byKeyVal) Swap(i, j int) {
+ arr.pairs[i], arr.pairs[j] = arr.pairs[j], arr.pairs[i]
+ arr.sorted = true
+}
+
+type byKind int
+
+const (
+ byKey byKind = 0
+ byVal byKind = 1
+)
+
+type jtype int
+
+const (
+ jnull jtype = iota
+ jfalse
+ jnumber
+ jstring
+ jtrue
+ jjson
+)
+
+func getjtype(v []byte) jtype {
+ if len(v) == 0 {
+ return jnull
+ }
+ switch v[0] {
+ case '"':
+ return jstring
+ case 'f':
+ return jfalse
+ case 't':
+ return jtrue
+ case 'n':
+ return jnull
+ case '[', '{':
+ return jjson
+ default:
+ return jnumber
+ }
+}
+
+func (arr *byKeyVal) isLess(i, j int, kind byKind) bool {
+ k1 := arr.json[arr.pairs[i].kstart:arr.pairs[i].kend]
+ k2 := arr.json[arr.pairs[j].kstart:arr.pairs[j].kend]
+ var v1, v2 []byte
+ if kind == byKey {
+ v1 = k1
+ v2 = k2
+ } else {
+ v1 = bytes.TrimSpace(arr.buf[arr.pairs[i].vstart:arr.pairs[i].vend])
+ v2 = bytes.TrimSpace(arr.buf[arr.pairs[j].vstart:arr.pairs[j].vend])
+ if len(v1) >= len(k1)+1 {
+ v1 = bytes.TrimSpace(v1[len(k1)+1:])
+ }
+ if len(v2) >= len(k2)+1 {
+ v2 = bytes.TrimSpace(v2[len(k2)+1:])
+ }
+ }
+ t1 := getjtype(v1)
+ t2 := getjtype(v2)
+ if t1 < t2 {
+ return true
+ }
+ if t1 > t2 {
+ return false
+ }
+ if t1 == jstring {
+ s1 := parsestr(v1)
+ s2 := parsestr(v2)
+ return string(s1) < string(s2)
+ }
+ if t1 == jnumber {
+ n1, _ := strconv.ParseFloat(string(v1), 64)
+ n2, _ := strconv.ParseFloat(string(v2), 64)
+ return n1 < n2
+ }
+ return string(v1) < string(v2)
+
+}
+
+func parsestr(s []byte) []byte {
+ for i := 1; i < len(s); i++ {
+ if s[i] == '\\' {
+ var str string
+ json.Unmarshal(s, &str)
+ return []byte(str)
+ }
+ if s[i] == '"' {
+ return s[1:i]
+ }
+ }
+ return nil
+}
+
+func appendPrettyObject(buf, json []byte, i int, open, close byte, pretty bool, width int, prefix, indent string, sortkeys bool, tabs, nl, max int) ([]byte, int, int, bool) {
+ var ok bool
+ if width > 0 {
+ if pretty && open == '[' && max == -1 {
+ // here we try to create a single line array
+ max := width - (len(buf) - nl)
+ if max > 3 {
+ s1, s2 := len(buf), i
+ buf, i, _, ok = appendPrettyObject(buf, json, i, '[', ']', false, width, prefix, "", sortkeys, 0, 0, max)
+ if ok && len(buf)-s1 <= max {
+ return buf, i, nl, true
+ }
+ buf = buf[:s1]
+ i = s2
+ }
+ } else if max != -1 && open == '{' {
+ return buf, i, nl, false
+ }
+ }
+ buf = append(buf, open)
+ i++
+ var pairs []pair
+ if open == '{' && sortkeys {
+ pairs = make([]pair, 0, 8)
+ }
+ var n int
+ for ; i < len(json); i++ {
+ if json[i] <= ' ' {
+ continue
+ }
+ if json[i] == close {
+ if pretty {
+ if open == '{' && sortkeys {
+ buf = sortPairs(json, buf, pairs)
+ }
+ if n > 0 {
+ nl = len(buf)
+ if buf[nl-1] == ' ' {
+ buf[nl-1] = '\n'
+ } else {
+ buf = append(buf, '\n')
+ }
+ }
+ if buf[len(buf)-1] != open {
+ buf = appendTabs(buf, prefix, indent, tabs)
+ }
+ }
+ buf = append(buf, close)
+ return buf, i + 1, nl, open != '{'
+ }
+ if open == '[' || json[i] == '"' {
+ if n > 0 {
+ buf = append(buf, ',')
+ if width != -1 && open == '[' {
+ buf = append(buf, ' ')
+ }
+ }
+ var p pair
+ if pretty {
+ nl = len(buf)
+ if buf[nl-1] == ' ' {
+ buf[nl-1] = '\n'
+ } else {
+ buf = append(buf, '\n')
+ }
+ if open == '{' && sortkeys {
+ p.kstart = i
+ p.vstart = len(buf)
+ }
+ buf = appendTabs(buf, prefix, indent, tabs+1)
+ }
+ if open == '{' {
+ buf, i, nl, _ = appendPrettyString(buf, json, i, nl)
+ if sortkeys {
+ p.kend = i
+ }
+ buf = append(buf, ':')
+ if pretty {
+ buf = append(buf, ' ')
+ }
+ }
+ buf, i, nl, ok = appendPrettyAny(buf, json, i, pretty, width, prefix, indent, sortkeys, tabs+1, nl, max)
+ if max != -1 && !ok {
+ return buf, i, nl, false
+ }
+ if pretty && open == '{' && sortkeys {
+ p.vend = len(buf)
+ if p.kstart > p.kend || p.vstart > p.vend {
+ // bad data. disable sorting
+ sortkeys = false
+ } else {
+ pairs = append(pairs, p)
+ }
+ }
+ i--
+ n++
+ }
+ }
+ return buf, i, nl, open != '{'
+}
+func sortPairs(json, buf []byte, pairs []pair) []byte {
+ if len(pairs) == 0 {
+ return buf
+ }
+ vstart := pairs[0].vstart
+ vend := pairs[len(pairs)-1].vend
+ arr := byKeyVal{false, json, buf, pairs}
+ sort.Stable(&arr)
+ if !arr.sorted {
+ return buf
+ }
+ nbuf := make([]byte, 0, vend-vstart)
+ for i, p := range pairs {
+ nbuf = append(nbuf, buf[p.vstart:p.vend]...)
+ if i < len(pairs)-1 {
+ nbuf = append(nbuf, ',')
+ nbuf = append(nbuf, '\n')
+ }
+ }
+ return append(buf[:vstart], nbuf...)
+}
+
+func appendPrettyString(buf, json []byte, i, nl int) ([]byte, int, int, bool) {
+ s := i
+ i++
+ for ; i < len(json); i++ {
+ if json[i] == '"' {
+ var sc int
+ for j := i - 1; j > s; j-- {
+ if json[j] == '\\' {
+ sc++
+ } else {
+ break
+ }
+ }
+ if sc%2 == 1 {
+ continue
+ }
+ i++
+ break
+ }
+ }
+ return append(buf, json[s:i]...), i, nl, true
+}
+
+func appendPrettyNumber(buf, json []byte, i, nl int) ([]byte, int, int, bool) {
+ s := i
+ i++
+ for ; i < len(json); i++ {
+ if json[i] <= ' ' || json[i] == ',' || json[i] == ':' || json[i] == ']' || json[i] == '}' {
+ break
+ }
+ }
+ return append(buf, json[s:i]...), i, nl, true
+}
+
+func appendTabs(buf []byte, prefix, indent string, tabs int) []byte {
+ if len(prefix) != 0 {
+ buf = append(buf, prefix...)
+ }
+ if len(indent) == 2 && indent[0] == ' ' && indent[1] == ' ' {
+ for i := 0; i < tabs; i++ {
+ buf = append(buf, ' ', ' ')
+ }
+ } else {
+ for i := 0; i < tabs; i++ {
+ buf = append(buf, indent...)
+ }
+ }
+ return buf
+}
+
+// Style is the color style
+type Style struct {
+ Key, String, Number [2]string
+ True, False, Null [2]string
+ Escape [2]string
+ Brackets [2]string
+ Append func(dst []byte, c byte) []byte
+}
+
+func hexp(p byte) byte {
+ switch {
+ case p < 10:
+ return p + '0'
+ default:
+ return (p - 10) + 'a'
+ }
+}
+
+// TerminalStyle is for terminals
+var TerminalStyle *Style
+
+func init() {
+ TerminalStyle = &Style{
+ Key: [2]string{"\x1B[1m\x1B[94m", "\x1B[0m"},
+ String: [2]string{"\x1B[32m", "\x1B[0m"},
+ Number: [2]string{"\x1B[33m", "\x1B[0m"},
+ True: [2]string{"\x1B[36m", "\x1B[0m"},
+ False: [2]string{"\x1B[36m", "\x1B[0m"},
+ Null: [2]string{"\x1B[2m", "\x1B[0m"},
+ Escape: [2]string{"\x1B[35m", "\x1B[0m"},
+ Brackets: [2]string{"\x1B[1m", "\x1B[0m"},
+ Append: func(dst []byte, c byte) []byte {
+ if c < ' ' && (c != '\r' && c != '\n' && c != '\t' && c != '\v') {
+ dst = append(dst, "\\u00"...)
+ dst = append(dst, hexp((c>>4)&0xF))
+ return append(dst, hexp((c)&0xF))
+ }
+ return append(dst, c)
+ },
+ }
+}
+
+// Color will colorize the json. The style parma is used for customizing
+// the colors. Passing nil to the style param will use the default
+// TerminalStyle.
+func Color(src []byte, style *Style) []byte {
+ if style == nil {
+ style = TerminalStyle
+ }
+ apnd := style.Append
+ if apnd == nil {
+ apnd = func(dst []byte, c byte) []byte {
+ return append(dst, c)
+ }
+ }
+ type stackt struct {
+ kind byte
+ key bool
+ }
+ var dst []byte
+ var stack []stackt
+ for i := 0; i < len(src); i++ {
+ if src[i] == '"' {
+ key := len(stack) > 0 && stack[len(stack)-1].key
+ if key {
+ dst = append(dst, style.Key[0]...)
+ } else {
+ dst = append(dst, style.String[0]...)
+ }
+ dst = apnd(dst, '"')
+ esc := false
+ uesc := 0
+ for i = i + 1; i < len(src); i++ {
+ if src[i] == '\\' {
+ if key {
+ dst = append(dst, style.Key[1]...)
+ } else {
+ dst = append(dst, style.String[1]...)
+ }
+ dst = append(dst, style.Escape[0]...)
+ dst = apnd(dst, src[i])
+ esc = true
+ if i+1 < len(src) && src[i+1] == 'u' {
+ uesc = 5
+ } else {
+ uesc = 1
+ }
+ } else if esc {
+ dst = apnd(dst, src[i])
+ if uesc == 1 {
+ esc = false
+ dst = append(dst, style.Escape[1]...)
+ if key {
+ dst = append(dst, style.Key[0]...)
+ } else {
+ dst = append(dst, style.String[0]...)
+ }
+ } else {
+ uesc--
+ }
+ } else {
+ dst = apnd(dst, src[i])
+ }
+ if src[i] == '"' {
+ j := i - 1
+ for ; ; j-- {
+ if src[j] != '\\' {
+ break
+ }
+ }
+ if (j-i)%2 != 0 {
+ break
+ }
+ }
+ }
+ if esc {
+ dst = append(dst, style.Escape[1]...)
+ } else if key {
+ dst = append(dst, style.Key[1]...)
+ } else {
+ dst = append(dst, style.String[1]...)
+ }
+ } else if src[i] == '{' || src[i] == '[' {
+ stack = append(stack, stackt{src[i], src[i] == '{'})
+ dst = append(dst, style.Brackets[0]...)
+ dst = apnd(dst, src[i])
+ dst = append(dst, style.Brackets[1]...)
+ } else if (src[i] == '}' || src[i] == ']') && len(stack) > 0 {
+ stack = stack[:len(stack)-1]
+ dst = append(dst, style.Brackets[0]...)
+ dst = apnd(dst, src[i])
+ dst = append(dst, style.Brackets[1]...)
+ } else if (src[i] == ':' || src[i] == ',') && len(stack) > 0 && stack[len(stack)-1].kind == '{' {
+ stack[len(stack)-1].key = !stack[len(stack)-1].key
+ dst = append(dst, style.Brackets[0]...)
+ dst = apnd(dst, src[i])
+ dst = append(dst, style.Brackets[1]...)
+ } else {
+ var kind byte
+ if (src[i] >= '0' && src[i] <= '9') || src[i] == '-' || isNaNOrInf(src[i:]) {
+ kind = '0'
+ dst = append(dst, style.Number[0]...)
+ } else if src[i] == 't' {
+ kind = 't'
+ dst = append(dst, style.True[0]...)
+ } else if src[i] == 'f' {
+ kind = 'f'
+ dst = append(dst, style.False[0]...)
+ } else if src[i] == 'n' {
+ kind = 'n'
+ dst = append(dst, style.Null[0]...)
+ } else {
+ dst = apnd(dst, src[i])
+ }
+ if kind != 0 {
+ for ; i < len(src); i++ {
+ if src[i] <= ' ' || src[i] == ',' || src[i] == ':' || src[i] == ']' || src[i] == '}' {
+ i--
+ break
+ }
+ dst = apnd(dst, src[i])
+ }
+ if kind == '0' {
+ dst = append(dst, style.Number[1]...)
+ } else if kind == 't' {
+ dst = append(dst, style.True[1]...)
+ } else if kind == 'f' {
+ dst = append(dst, style.False[1]...)
+ } else if kind == 'n' {
+ dst = append(dst, style.Null[1]...)
+ }
+ }
+ }
+ }
+ return dst
+}
+
+// Spec strips out comments and trailing commas and convert the input to a
+// valid JSON per the official spec: https://tools.ietf.org/html/rfc8259
+//
+// The resulting JSON will always be the same length as the input and it will
+// include all of the same line breaks at matching offsets. This is to ensure
+// the result can be later processed by a external parser and that that
+// parser will report messages or errors with the correct offsets.
+func Spec(src []byte) []byte {
+ return spec(src, nil)
+}
+
+// SpecInPlace is the same as Spec, but this method reuses the input json
+// buffer to avoid allocations. Do not use the original bytes slice upon return.
+func SpecInPlace(src []byte) []byte {
+ return spec(src, src)
+}
+
+func spec(src, dst []byte) []byte {
+ dst = dst[:0]
+ for i := 0; i < len(src); i++ {
+ if src[i] == '/' {
+ if i < len(src)-1 {
+ if src[i+1] == '/' {
+ dst = append(dst, ' ', ' ')
+ i += 2
+ for ; i < len(src); i++ {
+ if src[i] == '\n' {
+ dst = append(dst, '\n')
+ break
+ } else if src[i] == '\t' || src[i] == '\r' {
+ dst = append(dst, src[i])
+ } else {
+ dst = append(dst, ' ')
+ }
+ }
+ continue
+ }
+ if src[i+1] == '*' {
+ dst = append(dst, ' ', ' ')
+ i += 2
+ for ; i < len(src)-1; i++ {
+ if src[i] == '*' && src[i+1] == '/' {
+ dst = append(dst, ' ', ' ')
+ i++
+ break
+ } else if src[i] == '\n' || src[i] == '\t' ||
+ src[i] == '\r' {
+ dst = append(dst, src[i])
+ } else {
+ dst = append(dst, ' ')
+ }
+ }
+ continue
+ }
+ }
+ }
+ dst = append(dst, src[i])
+ if src[i] == '"' {
+ for i = i + 1; i < len(src); i++ {
+ dst = append(dst, src[i])
+ if src[i] == '"' {
+ j := i - 1
+ for ; ; j-- {
+ if src[j] != '\\' {
+ break
+ }
+ }
+ if (j-i)%2 != 0 {
+ break
+ }
+ }
+ }
+ } else if src[i] == '}' || src[i] == ']' {
+ for j := len(dst) - 2; j >= 0; j-- {
+ if dst[j] <= ' ' {
+ continue
+ }
+ if dst[j] == ',' {
+ dst[j] = ' '
+ }
+ break
+ }
+ }
+ }
+ return dst
+}
diff --git a/vendor/github.com/valyala/bytebufferpool/.travis.yml b/vendor/github.com/valyala/bytebufferpool/.travis.yml
new file mode 100644
index 0000000..6a6ec2e
--- /dev/null
+++ b/vendor/github.com/valyala/bytebufferpool/.travis.yml
@@ -0,0 +1,15 @@
+language: go
+
+go:
+ - 1.6
+
+script:
+ # build test for supported platforms
+ - GOOS=linux go build
+ - GOOS=darwin go build
+ - GOOS=freebsd go build
+ - GOOS=windows go build
+ - GOARCH=386 go build
+
+ # run tests on a standard platform
+ - go test -v ./...
diff --git a/vendor/github.com/valyala/bytebufferpool/LICENSE b/vendor/github.com/valyala/bytebufferpool/LICENSE
new file mode 100644
index 0000000..f7c935c
--- /dev/null
+++ b/vendor/github.com/valyala/bytebufferpool/LICENSE
@@ -0,0 +1,22 @@
+The MIT License (MIT)
+
+Copyright (c) 2016 Aliaksandr Valialkin, VertaMedia
+
+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/valyala/bytebufferpool/README.md b/vendor/github.com/valyala/bytebufferpool/README.md
new file mode 100644
index 0000000..061357e
--- /dev/null
+++ b/vendor/github.com/valyala/bytebufferpool/README.md
@@ -0,0 +1,21 @@
+[![Build Status](https://travis-ci.org/valyala/bytebufferpool.svg)](https://travis-ci.org/valyala/bytebufferpool)
+[![GoDoc](https://godoc.org/github.com/valyala/bytebufferpool?status.svg)](http://godoc.org/github.com/valyala/bytebufferpool)
+[![Go Report](http://goreportcard.com/badge/valyala/bytebufferpool)](http://goreportcard.com/report/valyala/bytebufferpool)
+
+# bytebufferpool
+
+An implementation of a pool of byte buffers with anti-memory-waste protection.
+
+The pool may waste limited amount of memory due to fragmentation.
+This amount equals to the maximum total size of the byte buffers
+in concurrent use.
+
+# Benchmark results
+Currently bytebufferpool is fastest and most effective buffer pool written in Go.
+
+You can find results [here](https://omgnull.github.io/go-benchmark/buffer/).
+
+# bytebufferpool users
+
+* [fasthttp](https://github.com/valyala/fasthttp)
+* [quicktemplate](https://github.com/valyala/quicktemplate)
diff --git a/vendor/github.com/valyala/bytebufferpool/bytebuffer.go b/vendor/github.com/valyala/bytebufferpool/bytebuffer.go
new file mode 100644
index 0000000..07a055a
--- /dev/null
+++ b/vendor/github.com/valyala/bytebufferpool/bytebuffer.go
@@ -0,0 +1,111 @@
+package bytebufferpool
+
+import "io"
+
+// ByteBuffer provides byte buffer, which can be used for minimizing
+// memory allocations.
+//
+// ByteBuffer may be used with functions appending data to the given []byte
+// slice. See example code for details.
+//
+// Use Get for obtaining an empty byte buffer.
+type ByteBuffer struct {
+
+ // B is a byte buffer to use in append-like workloads.
+ // See example code for details.
+ B []byte
+}
+
+// Len returns the size of the byte buffer.
+func (b *ByteBuffer) Len() int {
+ return len(b.B)
+}
+
+// ReadFrom implements io.ReaderFrom.
+//
+// The function appends all the data read from r to b.
+func (b *ByteBuffer) ReadFrom(r io.Reader) (int64, error) {
+ p := b.B
+ nStart := int64(len(p))
+ nMax := int64(cap(p))
+ n := nStart
+ if nMax == 0 {
+ nMax = 64
+ p = make([]byte, nMax)
+ } else {
+ p = p[:nMax]
+ }
+ for {
+ if n == nMax {
+ nMax *= 2
+ bNew := make([]byte, nMax)
+ copy(bNew, p)
+ p = bNew
+ }
+ nn, err := r.Read(p[n:])
+ n += int64(nn)
+ if err != nil {
+ b.B = p[:n]
+ n -= nStart
+ if err == io.EOF {
+ return n, nil
+ }
+ return n, err
+ }
+ }
+}
+
+// WriteTo implements io.WriterTo.
+func (b *ByteBuffer) WriteTo(w io.Writer) (int64, error) {
+ n, err := w.Write(b.B)
+ return int64(n), err
+}
+
+// Bytes returns b.B, i.e. all the bytes accumulated in the buffer.
+//
+// The purpose of this function is bytes.Buffer compatibility.
+func (b *ByteBuffer) Bytes() []byte {
+ return b.B
+}
+
+// Write implements io.Writer - it appends p to ByteBuffer.B
+func (b *ByteBuffer) Write(p []byte) (int, error) {
+ b.B = append(b.B, p...)
+ return len(p), nil
+}
+
+// WriteByte appends the byte c to the buffer.
+//
+// The purpose of this function is bytes.Buffer compatibility.
+//
+// The function always returns nil.
+func (b *ByteBuffer) WriteByte(c byte) error {
+ b.B = append(b.B, c)
+ return nil
+}
+
+// WriteString appends s to ByteBuffer.B.
+func (b *ByteBuffer) WriteString(s string) (int, error) {
+ b.B = append(b.B, s...)
+ return len(s), nil
+}
+
+// Set sets ByteBuffer.B to p.
+func (b *ByteBuffer) Set(p []byte) {
+ b.B = append(b.B[:0], p...)
+}
+
+// SetString sets ByteBuffer.B to s.
+func (b *ByteBuffer) SetString(s string) {
+ b.B = append(b.B[:0], s...)
+}
+
+// String returns string representation of ByteBuffer.B.
+func (b *ByteBuffer) String() string {
+ return string(b.B)
+}
+
+// Reset makes ByteBuffer.B empty.
+func (b *ByteBuffer) Reset() {
+ b.B = b.B[:0]
+}
diff --git a/vendor/github.com/valyala/bytebufferpool/doc.go b/vendor/github.com/valyala/bytebufferpool/doc.go
new file mode 100644
index 0000000..e511b7c
--- /dev/null
+++ b/vendor/github.com/valyala/bytebufferpool/doc.go
@@ -0,0 +1,7 @@
+// Package bytebufferpool implements a pool of byte buffers
+// with anti-fragmentation protection.
+//
+// The pool may waste limited amount of memory due to fragmentation.
+// This amount equals to the maximum total size of the byte buffers
+// in concurrent use.
+package bytebufferpool
diff --git a/vendor/github.com/valyala/bytebufferpool/pool.go b/vendor/github.com/valyala/bytebufferpool/pool.go
new file mode 100644
index 0000000..8bb4134
--- /dev/null
+++ b/vendor/github.com/valyala/bytebufferpool/pool.go
@@ -0,0 +1,151 @@
+package bytebufferpool
+
+import (
+ "sort"
+ "sync"
+ "sync/atomic"
+)
+
+const (
+ minBitSize = 6 // 2**6=64 is a CPU cache line size
+ steps = 20
+
+ minSize = 1 << minBitSize
+ maxSize = 1 << (minBitSize + steps - 1)
+
+ calibrateCallsThreshold = 42000
+ maxPercentile = 0.95
+)
+
+// Pool represents byte buffer pool.
+//
+// Distinct pools may be used for distinct types of byte buffers.
+// Properly determined byte buffer types with their own pools may help reducing
+// memory waste.
+type Pool struct {
+ calls [steps]uint64
+ calibrating uint64
+
+ defaultSize uint64
+ maxSize uint64
+
+ pool sync.Pool
+}
+
+var defaultPool Pool
+
+// Get returns an empty byte buffer from the pool.
+//
+// Got byte buffer may be returned to the pool via Put call.
+// This reduces the number of memory allocations required for byte buffer
+// management.
+func Get() *ByteBuffer { return defaultPool.Get() }
+
+// Get returns new byte buffer with zero length.
+//
+// The byte buffer may be returned to the pool via Put after the use
+// in order to minimize GC overhead.
+func (p *Pool) Get() *ByteBuffer {
+ v := p.pool.Get()
+ if v != nil {
+ return v.(*ByteBuffer)
+ }
+ return &ByteBuffer{
+ B: make([]byte, 0, atomic.LoadUint64(&p.defaultSize)),
+ }
+}
+
+// Put returns byte buffer to the pool.
+//
+// ByteBuffer.B mustn't be touched after returning it to the pool.
+// Otherwise data races will occur.
+func Put(b *ByteBuffer) { defaultPool.Put(b) }
+
+// Put releases byte buffer obtained via Get to the pool.
+//
+// The buffer mustn't be accessed after returning to the pool.
+func (p *Pool) Put(b *ByteBuffer) {
+ idx := index(len(b.B))
+
+ if atomic.AddUint64(&p.calls[idx], 1) > calibrateCallsThreshold {
+ p.calibrate()
+ }
+
+ maxSize := int(atomic.LoadUint64(&p.maxSize))
+ if maxSize == 0 || cap(b.B) <= maxSize {
+ b.Reset()
+ p.pool.Put(b)
+ }
+}
+
+func (p *Pool) calibrate() {
+ if !atomic.CompareAndSwapUint64(&p.calibrating, 0, 1) {
+ return
+ }
+
+ a := make(callSizes, 0, steps)
+ var callsSum uint64
+ for i := uint64(0); i < steps; i++ {
+ calls := atomic.SwapUint64(&p.calls[i], 0)
+ callsSum += calls
+ a = append(a, callSize{
+ calls: calls,
+ size: minSize << i,
+ })
+ }
+ sort.Sort(a)
+
+ defaultSize := a[0].size
+ maxSize := defaultSize
+
+ maxSum := uint64(float64(callsSum) * maxPercentile)
+ callsSum = 0
+ for i := 0; i < steps; i++ {
+ if callsSum > maxSum {
+ break
+ }
+ callsSum += a[i].calls
+ size := a[i].size
+ if size > maxSize {
+ maxSize = size
+ }
+ }
+
+ atomic.StoreUint64(&p.defaultSize, defaultSize)
+ atomic.StoreUint64(&p.maxSize, maxSize)
+
+ atomic.StoreUint64(&p.calibrating, 0)
+}
+
+type callSize struct {
+ calls uint64
+ size uint64
+}
+
+type callSizes []callSize
+
+func (ci callSizes) Len() int {
+ return len(ci)
+}
+
+func (ci callSizes) Less(i, j int) bool {
+ return ci[i].calls > ci[j].calls
+}
+
+func (ci callSizes) Swap(i, j int) {
+ ci[i], ci[j] = ci[j], ci[i]
+}
+
+func index(n int) int {
+ n--
+ n >>= minBitSize
+ idx := 0
+ for n > 0 {
+ n >>= 1
+ idx++
+ }
+ if idx >= steps {
+ idx = steps - 1
+ }
+ return idx
+}
diff --git a/vendor/github.com/valyala/fasthttp/.gitignore b/vendor/github.com/valyala/fasthttp/.gitignore
new file mode 100644
index 0000000..035e302
--- /dev/null
+++ b/vendor/github.com/valyala/fasthttp/.gitignore
@@ -0,0 +1,8 @@
+tags
+*.pprof
+*.fasthttp.gz
+*.fasthttp.br
+.idea
+.vscode
+.DS_Store
+vendor/
diff --git a/vendor/github.com/valyala/fasthttp/.golangci.yml b/vendor/github.com/valyala/fasthttp/.golangci.yml
new file mode 100644
index 0000000..ad75ddf
--- /dev/null
+++ b/vendor/github.com/valyala/fasthttp/.golangci.yml
@@ -0,0 +1,70 @@
+# This file contains configuration options for golangci-lint.
+# https://github.com/golangci/golangci-lint/blob/master/.golangci.reference.yml
+
+run:
+ # Timeout for analysis.
+ timeout: 5m
+
+linters:
+ enable-all: true
+ disable:
+ - cyclop
+ - depguard
+ - dupl
+ - errname
+ - errorlint
+ - exhaustive
+ - exhaustruct
+ - forcetypeassert
+ - funlen
+ - gochecknoglobals
+ - gocognit
+ - goconst
+ - gocyclo
+ - godot
+ - goerr113
+ - gomnd
+ - gosec
+ - inamedparam
+ - ireturn
+ - lll
+ - maintidx
+ - nakedret
+ - nestif
+ - nlreturn
+ - noctx
+ - nonamedreturns
+ - paralleltest
+ - perfsprint
+ - revive
+ - stylecheck
+ - testableexamples
+ - testpackage
+ - thelper
+ - tparallel
+ - unparam
+ - usestdlibvars
+ - varnamelen
+ - wastedassign
+ - whitespace
+ - wrapcheck
+ - wsl
+
+ # Deprecated linters
+ - deadcode
+ - exhaustivestruct
+ - golint
+ - ifshort
+ - interfacer
+ - maligned
+ - nosnakecase
+ - scopelint
+ - structcheck
+ - varcheck
+
+linters-settings:
+ # Show all issues from a linter.
+ max-issues-per-linter: 0
+
+ # Show all issues with the same text.
+ max-same-issues: 0
diff --git a/vendor/github.com/valyala/fasthttp/LICENSE b/vendor/github.com/valyala/fasthttp/LICENSE
new file mode 100644
index 0000000..24a5046
--- /dev/null
+++ b/vendor/github.com/valyala/fasthttp/LICENSE
@@ -0,0 +1,9 @@
+The MIT License (MIT)
+
+Copyright (c) 2015-present Aliaksandr Valialkin, VertaMedia, Kirill Danshin, Erik Dubbelboer, FastHTTP Authors
+
+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/valyala/fasthttp/README.md b/vendor/github.com/valyala/fasthttp/README.md
new file mode 100644
index 0000000..eab9b64
--- /dev/null
+++ b/vendor/github.com/valyala/fasthttp/README.md
@@ -0,0 +1,638 @@
+# fasthttp [![GoDoc](https://pkg.go.dev/badge/github.com/valyala/fasthttp)](https://pkg.go.dev/github.com/valyala/fasthttp) [![Go Report](https://goreportcard.com/badge/github.com/valyala/fasthttp)](https://goreportcard.com/report/github.com/valyala/fasthttp)
+
+![FastHTTP – Fastest and reliable HTTP implementation in Go](https://github.com/fasthttp/docs-assets/raw/master/banner@0.5.png)
+
+Fast HTTP implementation for Go.
+
+# fasthttp might not be for you!
+fasthttp was designed for some high performance edge cases. **Unless** your server/client needs to handle **thousands of small to medium requests per second** and needs a consistent low millisecond response time fasthttp might not be for you. **For most cases `net/http` is much better** as it's easier to use and can handle more cases. For most cases you won't even notice the performance difference.
+
+
+## General info and links
+
+Currently fasthttp is successfully used by [VertaMedia](https://vertamedia.com/)
+in a production serving up to 200K rps from more than 1.5M concurrent keep-alive
+connections per physical server.
+
+[TechEmpower Benchmark round 19 results](https://www.techempower.com/benchmarks/#section=data-r19&hw=ph&test=plaintext)
+
+[Server Benchmarks](#http-server-performance-comparison-with-nethttp)
+
+[Client Benchmarks](#http-client-comparison-with-nethttp)
+
+[Install](#install)
+
+[Documentation](https://pkg.go.dev/github.com/valyala/fasthttp)
+
+[Examples from docs](https://pkg.go.dev/github.com/valyala/fasthttp#pkg-examples)
+
+[Code examples](examples)
+
+[Awesome fasthttp tools](https://github.com/fasthttp)
+
+[Switching from net/http to fasthttp](#switching-from-nethttp-to-fasthttp)
+
+[Fasthttp best practices](#fasthttp-best-practices)
+
+[Tricks with byte buffers](#tricks-with-byte-buffers)
+
+[Related projects](#related-projects)
+
+[FAQ](#faq)
+
+## HTTP server performance comparison with [net/http](https://pkg.go.dev/net/http)
+
+In short, fasthttp server is up to 10 times faster than net/http.
+Below are benchmark results.
+
+*GOMAXPROCS=1*
+
+net/http server:
+```
+$ GOMAXPROCS=1 go test -bench=NetHTTPServerGet -benchmem -benchtime=10s
+BenchmarkNetHTTPServerGet1ReqPerConn 1000000 12052 ns/op 2297 B/op 29 allocs/op
+BenchmarkNetHTTPServerGet2ReqPerConn 1000000 12278 ns/op 2327 B/op 24 allocs/op
+BenchmarkNetHTTPServerGet10ReqPerConn 2000000 8903 ns/op 2112 B/op 19 allocs/op
+BenchmarkNetHTTPServerGet10KReqPerConn 2000000 8451 ns/op 2058 B/op 18 allocs/op
+BenchmarkNetHTTPServerGet1ReqPerConn10KClients 500000 26733 ns/op 3229 B/op 29 allocs/op
+BenchmarkNetHTTPServerGet2ReqPerConn10KClients 1000000 23351 ns/op 3211 B/op 24 allocs/op
+BenchmarkNetHTTPServerGet10ReqPerConn10KClients 1000000 13390 ns/op 2483 B/op 19 allocs/op
+BenchmarkNetHTTPServerGet100ReqPerConn10KClients 1000000 13484 ns/op 2171 B/op 18 allocs/op
+```
+
+fasthttp server:
+```
+$ GOMAXPROCS=1 go test -bench=kServerGet -benchmem -benchtime=10s
+BenchmarkServerGet1ReqPerConn 10000000 1559 ns/op 0 B/op 0 allocs/op
+BenchmarkServerGet2ReqPerConn 10000000 1248 ns/op 0 B/op 0 allocs/op
+BenchmarkServerGet10ReqPerConn 20000000 797 ns/op 0 B/op 0 allocs/op
+BenchmarkServerGet10KReqPerConn 20000000 716 ns/op 0 B/op 0 allocs/op
+BenchmarkServerGet1ReqPerConn10KClients 10000000 1974 ns/op 0 B/op 0 allocs/op
+BenchmarkServerGet2ReqPerConn10KClients 10000000 1352 ns/op 0 B/op 0 allocs/op
+BenchmarkServerGet10ReqPerConn10KClients 20000000 789 ns/op 2 B/op 0 allocs/op
+BenchmarkServerGet100ReqPerConn10KClients 20000000 604 ns/op 0 B/op 0 allocs/op
+```
+
+*GOMAXPROCS=4*
+
+net/http server:
+```
+$ GOMAXPROCS=4 go test -bench=NetHTTPServerGet -benchmem -benchtime=10s
+BenchmarkNetHTTPServerGet1ReqPerConn-4 3000000 4529 ns/op 2389 B/op 29 allocs/op
+BenchmarkNetHTTPServerGet2ReqPerConn-4 5000000 3896 ns/op 2418 B/op 24 allocs/op
+BenchmarkNetHTTPServerGet10ReqPerConn-4 5000000 3145 ns/op 2160 B/op 19 allocs/op
+BenchmarkNetHTTPServerGet10KReqPerConn-4 5000000 3054 ns/op 2065 B/op 18 allocs/op
+BenchmarkNetHTTPServerGet1ReqPerConn10KClients-4 1000000 10321 ns/op 3710 B/op 30 allocs/op
+BenchmarkNetHTTPServerGet2ReqPerConn10KClients-4 2000000 7556 ns/op 3296 B/op 24 allocs/op
+BenchmarkNetHTTPServerGet10ReqPerConn10KClients-4 5000000 3905 ns/op 2349 B/op 19 allocs/op
+BenchmarkNetHTTPServerGet100ReqPerConn10KClients-4 5000000 3435 ns/op 2130 B/op 18 allocs/op
+```
+
+fasthttp server:
+```
+$ GOMAXPROCS=4 go test -bench=kServerGet -benchmem -benchtime=10s
+BenchmarkServerGet1ReqPerConn-4 10000000 1141 ns/op 0 B/op 0 allocs/op
+BenchmarkServerGet2ReqPerConn-4 20000000 707 ns/op 0 B/op 0 allocs/op
+BenchmarkServerGet10ReqPerConn-4 30000000 341 ns/op 0 B/op 0 allocs/op
+BenchmarkServerGet10KReqPerConn-4 50000000 310 ns/op 0 B/op 0 allocs/op
+BenchmarkServerGet1ReqPerConn10KClients-4 10000000 1119 ns/op 0 B/op 0 allocs/op
+BenchmarkServerGet2ReqPerConn10KClients-4 20000000 644 ns/op 0 B/op 0 allocs/op
+BenchmarkServerGet10ReqPerConn10KClients-4 30000000 346 ns/op 0 B/op 0 allocs/op
+BenchmarkServerGet100ReqPerConn10KClients-4 50000000 282 ns/op 0 B/op 0 allocs/op
+```
+
+## HTTP client comparison with net/http
+
+In short, fasthttp client is up to 10 times faster than net/http.
+Below are benchmark results.
+
+*GOMAXPROCS=1*
+
+net/http client:
+```
+$ GOMAXPROCS=1 go test -bench='HTTPClient(Do|GetEndToEnd)' -benchmem -benchtime=10s
+BenchmarkNetHTTPClientDoFastServer 1000000 12567 ns/op 2616 B/op 35 allocs/op
+BenchmarkNetHTTPClientGetEndToEnd1TCP 200000 67030 ns/op 5028 B/op 56 allocs/op
+BenchmarkNetHTTPClientGetEndToEnd10TCP 300000 51098 ns/op 5031 B/op 56 allocs/op
+BenchmarkNetHTTPClientGetEndToEnd100TCP 300000 45096 ns/op 5026 B/op 55 allocs/op
+BenchmarkNetHTTPClientGetEndToEnd1Inmemory 500000 24779 ns/op 5035 B/op 57 allocs/op
+BenchmarkNetHTTPClientGetEndToEnd10Inmemory 1000000 26425 ns/op 5035 B/op 57 allocs/op
+BenchmarkNetHTTPClientGetEndToEnd100Inmemory 500000 28515 ns/op 5045 B/op 57 allocs/op
+BenchmarkNetHTTPClientGetEndToEnd1000Inmemory 500000 39511 ns/op 5096 B/op 56 allocs/op
+```
+
+fasthttp client:
+```
+$ GOMAXPROCS=1 go test -bench='kClient(Do|GetEndToEnd)' -benchmem -benchtime=10s
+BenchmarkClientDoFastServer 20000000 865 ns/op 0 B/op 0 allocs/op
+BenchmarkClientGetEndToEnd1TCP 1000000 18711 ns/op 0 B/op 0 allocs/op
+BenchmarkClientGetEndToEnd10TCP 1000000 14664 ns/op 0 B/op 0 allocs/op
+BenchmarkClientGetEndToEnd100TCP 1000000 14043 ns/op 1 B/op 0 allocs/op
+BenchmarkClientGetEndToEnd1Inmemory 5000000 3965 ns/op 0 B/op 0 allocs/op
+BenchmarkClientGetEndToEnd10Inmemory 3000000 4060 ns/op 0 B/op 0 allocs/op
+BenchmarkClientGetEndToEnd100Inmemory 5000000 3396 ns/op 0 B/op 0 allocs/op
+BenchmarkClientGetEndToEnd1000Inmemory 5000000 3306 ns/op 2 B/op 0 allocs/op
+```
+
+*GOMAXPROCS=4*
+
+net/http client:
+```
+$ GOMAXPROCS=4 go test -bench='HTTPClient(Do|GetEndToEnd)' -benchmem -benchtime=10s
+BenchmarkNetHTTPClientDoFastServer-4 2000000 8774 ns/op 2619 B/op 35 allocs/op
+BenchmarkNetHTTPClientGetEndToEnd1TCP-4 500000 22951 ns/op 5047 B/op 56 allocs/op
+BenchmarkNetHTTPClientGetEndToEnd10TCP-4 1000000 19182 ns/op 5037 B/op 55 allocs/op
+BenchmarkNetHTTPClientGetEndToEnd100TCP-4 1000000 16535 ns/op 5031 B/op 55 allocs/op
+BenchmarkNetHTTPClientGetEndToEnd1Inmemory-4 1000000 14495 ns/op 5038 B/op 56 allocs/op
+BenchmarkNetHTTPClientGetEndToEnd10Inmemory-4 1000000 10237 ns/op 5034 B/op 56 allocs/op
+BenchmarkNetHTTPClientGetEndToEnd100Inmemory-4 1000000 10125 ns/op 5045 B/op 56 allocs/op
+BenchmarkNetHTTPClientGetEndToEnd1000Inmemory-4 1000000 11132 ns/op 5136 B/op 56 allocs/op
+```
+
+fasthttp client:
+```
+$ GOMAXPROCS=4 go test -bench='kClient(Do|GetEndToEnd)' -benchmem -benchtime=10s
+BenchmarkClientDoFastServer-4 50000000 397 ns/op 0 B/op 0 allocs/op
+BenchmarkClientGetEndToEnd1TCP-4 2000000 7388 ns/op 0 B/op 0 allocs/op
+BenchmarkClientGetEndToEnd10TCP-4 2000000 6689 ns/op 0 B/op 0 allocs/op
+BenchmarkClientGetEndToEnd100TCP-4 3000000 4927 ns/op 1 B/op 0 allocs/op
+BenchmarkClientGetEndToEnd1Inmemory-4 10000000 1604 ns/op 0 B/op 0 allocs/op
+BenchmarkClientGetEndToEnd10Inmemory-4 10000000 1458 ns/op 0 B/op 0 allocs/op
+BenchmarkClientGetEndToEnd100Inmemory-4 10000000 1329 ns/op 0 B/op 0 allocs/op
+BenchmarkClientGetEndToEnd1000Inmemory-4 10000000 1316 ns/op 5 B/op 0 allocs/op
+```
+
+
+## Install
+
+```
+go get -u github.com/valyala/fasthttp
+```
+
+
+## Switching from net/http to fasthttp
+
+Unfortunately, fasthttp doesn't provide API identical to net/http.
+See the [FAQ](#faq) for details.
+There is [net/http -> fasthttp handler converter](https://pkg.go.dev/github.com/valyala/fasthttp/fasthttpadaptor),
+but it is better to write fasthttp request handlers by hand in order to use
+all of the fasthttp advantages (especially high performance :) ).
+
+Important points:
+
+* Fasthttp works with [RequestHandler functions](https://pkg.go.dev/github.com/valyala/fasthttp#RequestHandler)
+instead of objects implementing [Handler interface](https://pkg.go.dev/net/http#Handler).
+Fortunately, it is easy to pass bound struct methods to fasthttp:
+
+ ```go
+ type MyHandler struct {
+ foobar string
+ }
+
+ // request handler in net/http style, i.e. method bound to MyHandler struct.
+ func (h *MyHandler) HandleFastHTTP(ctx *fasthttp.RequestCtx) {
+ // notice that we may access MyHandler properties here - see h.foobar.
+ fmt.Fprintf(ctx, "Hello, world! Requested path is %q. Foobar is %q",
+ ctx.Path(), h.foobar)
+ }
+
+ // request handler in fasthttp style, i.e. just plain function.
+ func fastHTTPHandler(ctx *fasthttp.RequestCtx) {
+ fmt.Fprintf(ctx, "Hi there! RequestURI is %q", ctx.RequestURI())
+ }
+
+ // pass bound struct method to fasthttp
+ myHandler := &MyHandler{
+ foobar: "foobar",
+ }
+ fasthttp.ListenAndServe(":8080", myHandler.HandleFastHTTP)
+
+ // pass plain function to fasthttp
+ fasthttp.ListenAndServe(":8081", fastHTTPHandler)
+ ```
+
+* The [RequestHandler](https://pkg.go.dev/github.com/valyala/fasthttp#RequestHandler)
+accepts only one argument - [RequestCtx](https://pkg.go.dev/github.com/valyala/fasthttp#RequestCtx).
+It contains all the functionality required for http request processing
+and response writing. Below is an example of a simple request handler conversion
+from net/http to fasthttp.
+
+ ```go
+ // net/http request handler
+ requestHandler := func(w http.ResponseWriter, r *http.Request) {
+ switch r.URL.Path {
+ case "/foo":
+ fooHandler(w, r)
+ case "/bar":
+ barHandler(w, r)
+ default:
+ http.Error(w, "Unsupported path", http.StatusNotFound)
+ }
+ }
+ ```
+
+ ```go
+ // the corresponding fasthttp request handler
+ requestHandler := func(ctx *fasthttp.RequestCtx) {
+ switch string(ctx.Path()) {
+ case "/foo":
+ fooHandler(ctx)
+ case "/bar":
+ barHandler(ctx)
+ default:
+ ctx.Error("Unsupported path", fasthttp.StatusNotFound)
+ }
+ }
+ ```
+
+* Fasthttp allows setting response headers and writing response body
+in an arbitrary order. There is no 'headers first, then body' restriction
+like in net/http. The following code is valid for fasthttp:
+
+ ```go
+ requestHandler := func(ctx *fasthttp.RequestCtx) {
+ // set some headers and status code first
+ ctx.SetContentType("foo/bar")
+ ctx.SetStatusCode(fasthttp.StatusOK)
+
+ // then write the first part of body
+ fmt.Fprintf(ctx, "this is the first part of body\n")
+
+ // then set more headers
+ ctx.Response.Header.Set("Foo-Bar", "baz")
+
+ // then write more body
+ fmt.Fprintf(ctx, "this is the second part of body\n")
+
+ // then override already written body
+ ctx.SetBody([]byte("this is completely new body contents"))
+
+ // then update status code
+ ctx.SetStatusCode(fasthttp.StatusNotFound)
+
+ // basically, anything may be updated many times before
+ // returning from RequestHandler.
+ //
+ // Unlike net/http fasthttp doesn't put response to the wire until
+ // returning from RequestHandler.
+ }
+ ```
+
+* Fasthttp doesn't provide [ServeMux](https://pkg.go.dev/net/http#ServeMux),
+but there are more powerful third-party routers and web frameworks
+with fasthttp support:
+
+ * [fasthttp-routing](https://github.com/qiangxue/fasthttp-routing)
+ * [router](https://github.com/fasthttp/router)
+ * [lu](https://github.com/vincentLiuxiang/lu)
+ * [atreugo](https://github.com/savsgio/atreugo)
+ * [Fiber](https://github.com/gofiber/fiber)
+ * [Gearbox](https://github.com/gogearbox/gearbox)
+
+ Net/http code with simple ServeMux is trivially converted to fasthttp code:
+
+ ```go
+ // net/http code
+
+ m := &http.ServeMux{}
+ m.HandleFunc("/foo", fooHandlerFunc)
+ m.HandleFunc("/bar", barHandlerFunc)
+ m.Handle("/baz", bazHandler)
+
+ http.ListenAndServe(":80", m)
+ ```
+
+ ```go
+ // the corresponding fasthttp code
+ m := func(ctx *fasthttp.RequestCtx) {
+ switch string(ctx.Path()) {
+ case "/foo":
+ fooHandlerFunc(ctx)
+ case "/bar":
+ barHandlerFunc(ctx)
+ case "/baz":
+ bazHandler.HandlerFunc(ctx)
+ default:
+ ctx.Error("not found", fasthttp.StatusNotFound)
+ }
+ }
+
+ fasthttp.ListenAndServe(":80", m)
+ ```
+
+* Because creating a new channel for every request is just too expensive, so the channel returned by RequestCtx.Done() is only closed when the server is shutting down.
+
+ ```go
+ func main() {
+ fasthttp.ListenAndServe(":8080", fasthttp.TimeoutHandler(func(ctx *fasthttp.RequestCtx) {
+ select {
+ case <-ctx.Done():
+ // ctx.Done() is only closed when the server is shutting down.
+ log.Println("context cancelled")
+ return
+ case <-time.After(10 * time.Second):
+ log.Println("process finished ok")
+ }
+ }, time.Second*2, "timeout"))
+ }
+ ```
+
+* net/http -> fasthttp conversion table:
+
+ * All the pseudocode below assumes w, r and ctx have these types:
+ ```go
+ var (
+ w http.ResponseWriter
+ r *http.Request
+ ctx *fasthttp.RequestCtx
+ )
+ ```
+ * r.Body -> [ctx.PostBody()](https://pkg.go.dev/github.com/valyala/fasthttp#RequestCtx.PostBody)
+ * r.URL.Path -> [ctx.Path()](https://pkg.go.dev/github.com/valyala/fasthttp#RequestCtx.Path)
+ * r.URL -> [ctx.URI()](https://pkg.go.dev/github.com/valyala/fasthttp#RequestCtx.URI)
+ * r.Method -> [ctx.Method()](https://pkg.go.dev/github.com/valyala/fasthttp#RequestCtx.Method)
+ * r.Header -> [ctx.Request.Header](https://pkg.go.dev/github.com/valyala/fasthttp#RequestHeader)
+ * r.Header.Get() -> [ctx.Request.Header.Peek()](https://pkg.go.dev/github.com/valyala/fasthttp#RequestHeader.Peek)
+ * r.Host -> [ctx.Host()](https://pkg.go.dev/github.com/valyala/fasthttp#RequestCtx.Host)
+ * r.Form -> [ctx.QueryArgs()](https://pkg.go.dev/github.com/valyala/fasthttp#RequestCtx.QueryArgs) +
+ [ctx.PostArgs()](https://pkg.go.dev/github.com/valyala/fasthttp#RequestCtx.PostArgs)
+ * r.PostForm -> [ctx.PostArgs()](https://pkg.go.dev/github.com/valyala/fasthttp#RequestCtx.PostArgs)
+ * r.FormValue() -> [ctx.FormValue()](https://pkg.go.dev/github.com/valyala/fasthttp#RequestCtx.FormValue)
+ * r.FormFile() -> [ctx.FormFile()](https://pkg.go.dev/github.com/valyala/fasthttp#RequestCtx.FormFile)
+ * r.MultipartForm -> [ctx.MultipartForm()](https://pkg.go.dev/github.com/valyala/fasthttp#RequestCtx.MultipartForm)
+ * r.RemoteAddr -> [ctx.RemoteAddr()](https://pkg.go.dev/github.com/valyala/fasthttp#RequestCtx.RemoteAddr)
+ * r.RequestURI -> [ctx.RequestURI()](https://pkg.go.dev/github.com/valyala/fasthttp#RequestCtx.RequestURI)
+ * r.TLS -> [ctx.IsTLS()](https://pkg.go.dev/github.com/valyala/fasthttp#RequestCtx.IsTLS)
+ * r.Cookie() -> [ctx.Request.Header.Cookie()](https://pkg.go.dev/github.com/valyala/fasthttp#RequestHeader.Cookie)
+ * r.Referer() -> [ctx.Referer()](https://pkg.go.dev/github.com/valyala/fasthttp#RequestCtx.Referer)
+ * r.UserAgent() -> [ctx.UserAgent()](https://pkg.go.dev/github.com/valyala/fasthttp#RequestCtx.UserAgent)
+ * w.Header() -> [ctx.Response.Header](https://pkg.go.dev/github.com/valyala/fasthttp#ResponseHeader)
+ * w.Header().Set() -> [ctx.Response.Header.Set()](https://pkg.go.dev/github.com/valyala/fasthttp#ResponseHeader.Set)
+ * w.Header().Set("Content-Type") -> [ctx.SetContentType()](https://pkg.go.dev/github.com/valyala/fasthttp#RequestCtx.SetContentType)
+ * w.Header().Set("Set-Cookie") -> [ctx.Response.Header.SetCookie()](https://pkg.go.dev/github.com/valyala/fasthttp#ResponseHeader.SetCookie)
+ * w.Write() -> [ctx.Write()](https://pkg.go.dev/github.com/valyala/fasthttp#RequestCtx.Write),
+ [ctx.SetBody()](https://pkg.go.dev/github.com/valyala/fasthttp#RequestCtx.SetBody),
+ [ctx.SetBodyStream()](https://pkg.go.dev/github.com/valyala/fasthttp#RequestCtx.SetBodyStream),
+ [ctx.SetBodyStreamWriter()](https://pkg.go.dev/github.com/valyala/fasthttp#RequestCtx.SetBodyStreamWriter)
+ * w.WriteHeader() -> [ctx.SetStatusCode()](https://pkg.go.dev/github.com/valyala/fasthttp#RequestCtx.SetStatusCode)
+ * w.(http.Hijacker).Hijack() -> [ctx.Hijack()](https://pkg.go.dev/github.com/valyala/fasthttp#RequestCtx.Hijack)
+ * http.Error() -> [ctx.Error()](https://pkg.go.dev/github.com/valyala/fasthttp#RequestCtx.Error)
+ * http.FileServer() -> [fasthttp.FSHandler()](https://pkg.go.dev/github.com/valyala/fasthttp#FSHandler),
+ [fasthttp.FS](https://pkg.go.dev/github.com/valyala/fasthttp#FS)
+ * http.ServeFile() -> [fasthttp.ServeFile()](https://pkg.go.dev/github.com/valyala/fasthttp#ServeFile)
+ * http.Redirect() -> [ctx.Redirect()](https://pkg.go.dev/github.com/valyala/fasthttp#RequestCtx.Redirect)
+ * http.NotFound() -> [ctx.NotFound()](https://pkg.go.dev/github.com/valyala/fasthttp#RequestCtx.NotFound)
+ * http.StripPrefix() -> [fasthttp.PathRewriteFunc](https://pkg.go.dev/github.com/valyala/fasthttp#PathRewriteFunc)
+
+* *VERY IMPORTANT!* Fasthttp disallows holding references
+to [RequestCtx](https://pkg.go.dev/github.com/valyala/fasthttp#RequestCtx) or to its'
+members after returning from [RequestHandler](https://pkg.go.dev/github.com/valyala/fasthttp#RequestHandler).
+Otherwise [data races](http://go.dev/blog/race-detector) are inevitable.
+Carefully inspect all the net/http request handlers converted to fasthttp whether
+they retain references to RequestCtx or to its' members after returning.
+RequestCtx provides the following _band aids_ for this case:
+
+ * Wrap RequestHandler into [TimeoutHandler](https://pkg.go.dev/github.com/valyala/fasthttp#TimeoutHandler).
+ * Call [TimeoutError](https://pkg.go.dev/github.com/valyala/fasthttp#RequestCtx.TimeoutError)
+ before returning from RequestHandler if there are references to RequestCtx or to its' members.
+ See [the example](https://pkg.go.dev/github.com/valyala/fasthttp#example-RequestCtx-TimeoutError)
+ for more details.
+
+Use this brilliant tool - [race detector](http://go.dev/blog/race-detector) -
+for detecting and eliminating data races in your program. If you detected
+data race related to fasthttp in your program, then there is high probability
+you forgot calling [TimeoutError](https://pkg.go.dev/github.com/valyala/fasthttp#RequestCtx.TimeoutError)
+before returning from [RequestHandler](https://pkg.go.dev/github.com/valyala/fasthttp#RequestHandler).
+
+* Blind switching from net/http to fasthttp won't give you performance boost.
+While fasthttp is optimized for speed, its' performance may be easily saturated
+by slow [RequestHandler](https://pkg.go.dev/github.com/valyala/fasthttp#RequestHandler).
+So [profile](http://go.dev/blog/pprof) and optimize your
+code after switching to fasthttp. For instance, use [quicktemplate](https://github.com/valyala/quicktemplate)
+instead of [html/template](https://pkg.go.dev/html/template).
+
+* See also [fasthttputil](https://pkg.go.dev/github.com/valyala/fasthttp/fasthttputil),
+[fasthttpadaptor](https://pkg.go.dev/github.com/valyala/fasthttp/fasthttpadaptor) and
+[expvarhandler](https://pkg.go.dev/github.com/valyala/fasthttp/expvarhandler).
+
+
+## Performance optimization tips for multi-core systems
+
+* Use [reuseport](https://pkg.go.dev/github.com/valyala/fasthttp/reuseport) listener.
+* Run a separate server instance per CPU core with GOMAXPROCS=1.
+* Pin each server instance to a separate CPU core using [taskset](http://linux.die.net/man/1/taskset).
+* Ensure the interrupts of multiqueue network card are evenly distributed between CPU cores.
+ See [this article](https://blog.cloudflare.com/how-to-achieve-low-latency/) for details.
+* Use the latest version of Go as each version contains performance improvements.
+
+
+## Fasthttp best practices
+
+* Do not allocate objects and `[]byte` buffers - just reuse them as much
+ as possible. Fasthttp API design encourages this.
+* [sync.Pool](https://pkg.go.dev/sync#Pool) is your best friend.
+* [Profile your program](http://go.dev/blog/pprof)
+ in production.
+ `go tool pprof --alloc_objects your-program mem.pprof` usually gives better
+ insights for optimization opportunities than `go tool pprof your-program cpu.pprof`.
+* Write [tests and benchmarks](https://pkg.go.dev/testing) for hot paths.
+* Avoid conversion between `[]byte` and `string`, since this may result in memory
+ allocation+copy. Fasthttp API provides functions for both `[]byte` and `string` -
+ use these functions instead of converting manually between `[]byte` and `string`.
+ There are some exceptions - see [this wiki page](https://github.com/golang/go/wiki/CompilerOptimizations#string-and-byte)
+ for more details.
+* Verify your tests and production code under
+ [race detector](https://go.dev/doc/articles/race_detector.html) on a regular basis.
+* Prefer [quicktemplate](https://github.com/valyala/quicktemplate) instead of
+ [html/template](https://pkg.go.dev/html/template) in your webserver.
+
+
+## Tricks with `[]byte` buffers
+
+The following tricks are used by fasthttp. Use them in your code too.
+
+* Standard Go functions accept nil buffers
+```go
+var (
+ // both buffers are uninitialized
+ dst []byte
+ src []byte
+)
+dst = append(dst, src...) // is legal if dst is nil and/or src is nil
+copy(dst, src) // is legal if dst is nil and/or src is nil
+(string(src) == "") // is true if src is nil
+(len(src) == 0) // is true if src is nil
+src = src[:0] // works like a charm with nil src
+
+// this for loop doesn't panic if src is nil
+for i, ch := range src {
+ doSomething(i, ch)
+}
+```
+
+So throw away nil checks for `[]byte` buffers from you code. For example,
+```go
+srcLen := 0
+if src != nil {
+ srcLen = len(src)
+}
+```
+
+becomes
+
+```go
+srcLen := len(src)
+```
+
+* String may be appended to `[]byte` buffer with `append`
+```go
+dst = append(dst, "foobar"...)
+```
+
+* `[]byte` buffer may be extended to its' capacity.
+```go
+buf := make([]byte, 100)
+a := buf[:10] // len(a) == 10, cap(a) == 100.
+b := a[:100] // is valid, since cap(a) == 100.
+```
+
+* All fasthttp functions accept nil `[]byte` buffer
+```go
+statusCode, body, err := fasthttp.Get(nil, "http://google.com/")
+uintBuf := fasthttp.AppendUint(nil, 1234)
+```
+
+* String and `[]byte` buffers may converted without memory allocations
+```go
+func b2s(b []byte) string {
+ return *(*string)(unsafe.Pointer(&b))
+}
+
+func s2b(s string) (b []byte) {
+ bh := (*reflect.SliceHeader)(unsafe.Pointer(&b))
+ sh := (*reflect.StringHeader)(unsafe.Pointer(&s))
+ bh.Data = sh.Data
+ bh.Cap = sh.Len
+ bh.Len = sh.Len
+ return b
+}
+```
+
+### Warning:
+This is an **unsafe** way, the result string and `[]byte` buffer share the same bytes.
+
+**Please make sure not to modify the bytes in the `[]byte` buffer if the string still survives!**
+
+## Related projects
+
+ * [fasthttp](https://github.com/fasthttp) - various useful
+ helpers for projects based on fasthttp.
+ * [fasthttp-routing](https://github.com/qiangxue/fasthttp-routing) - fast and
+ powerful routing package for fasthttp servers.
+ * [http2](https://github.com/dgrr/http2) - HTTP/2 implementation for fasthttp.
+ * [router](https://github.com/fasthttp/router) - a high
+ performance fasthttp request router that scales well.
+ * [fastws](https://github.com/fasthttp/fastws) - Bloatless WebSocket package made for fasthttp
+ to handle Read/Write operations concurrently.
+ * [gramework](https://github.com/gramework/gramework) - a web framework made by one of fasthttp maintainers
+ * [lu](https://github.com/vincentLiuxiang/lu) - a high performance
+ go middleware web framework which is based on fasthttp.
+ * [websocket](https://github.com/fasthttp/websocket) - Gorilla-based
+ websocket implementation for fasthttp.
+ * [websocket](https://github.com/dgrr/websocket) - Event-based high-performance WebSocket library for zero-allocation
+ websocket servers and clients.
+ * [fasthttpsession](https://github.com/phachon/fasthttpsession) - a fast and powerful session package for fasthttp servers.
+ * [atreugo](https://github.com/savsgio/atreugo) - High performance and extensible micro web framework with zero memory allocations in hot paths.
+ * [kratgo](https://github.com/savsgio/kratgo) - Simple, lightweight and ultra-fast HTTP Cache to speed up your websites.
+ * [kit-plugins](https://github.com/wencan/kit-plugins/tree/master/transport/fasthttp) - go-kit transport implementation for fasthttp.
+ * [Fiber](https://github.com/gofiber/fiber) - An Expressjs inspired web framework running on Fasthttp
+ * [Gearbox](https://github.com/gogearbox/gearbox) - :gear: gearbox is a web framework written in Go with a focus on high performance and memory optimization
+ * [http2curl](https://github.com/li-jin-gou/http2curl) - A tool to convert fasthttp requests to curl command line
+
+## FAQ
+
+* *Why creating yet another http package instead of optimizing net/http?*
+
+ Because net/http API limits many optimization opportunities.
+ For example:
+ * net/http Request object lifetime isn't limited by request handler execution
+ time. So the server must create a new request object per each request instead
+ of reusing existing objects like fasthttp does.
+ * net/http headers are stored in a `map[string][]string`. So the server
+ must parse all the headers, convert them from `[]byte` to `string` and put
+ them into the map before calling user-provided request handler.
+ This all requires unnecessary memory allocations avoided by fasthttp.
+ * net/http client API requires creating a new response object per each request.
+
+* *Why fasthttp API is incompatible with net/http?*
+
+ Because net/http API limits many optimization opportunities. See the answer
+ above for more details. Also certain net/http API parts are suboptimal
+ for use:
+ * Compare [net/http connection hijacking](https://pkg.go.dev/net/http#Hijacker)
+ to [fasthttp connection hijacking](https://pkg.go.dev/github.com/valyala/fasthttp#RequestCtx.Hijack).
+ * Compare [net/http Request.Body reading](https://pkg.go.dev/net/http#Request)
+ to [fasthttp request body reading](https://pkg.go.dev/github.com/valyala/fasthttp#RequestCtx.PostBody).
+
+* *Why fasthttp doesn't support HTTP/2.0 and WebSockets?*
+
+ [HTTP/2.0 support](https://github.com/fasthttp/http2) is in progress. [WebSockets](https://github.com/fasthttp/websockets) has been done already.
+ Third parties also may use [RequestCtx.Hijack](https://pkg.go.dev/github.com/valyala/fasthttp#RequestCtx.Hijack)
+ for implementing these goodies.
+
+* *Are there known net/http advantages comparing to fasthttp?*
+
+ Yes:
+ * net/http supports [HTTP/2.0 starting from go1.6](https://pkg.go.dev/golang.org/x/net/http2).
+ * net/http API is stable, while fasthttp API constantly evolves.
+ * net/http handles more HTTP corner cases.
+ * net/http can stream both request and response bodies
+ * net/http can handle bigger bodies as it doesn't read the whole body into memory
+ * net/http should contain less bugs, since it is used and tested by much
+ wider audience.
+
+* *Why fasthttp API prefers returning `[]byte` instead of `string`?*
+
+ Because `[]byte` to `string` conversion isn't free - it requires memory
+ allocation and copy. Feel free wrapping returned `[]byte` result into
+ `string()` if you prefer working with strings instead of byte slices.
+ But be aware that this has non-zero overhead.
+
+* *Which GO versions are supported by fasthttp?*
+
+ Go 1.15.x. Older versions won't be supported.
+
+* *Please provide real benchmark data and server information*
+
+ See [this issue](https://github.com/valyala/fasthttp/issues/4).
+
+* *Are there plans to add request routing to fasthttp?*
+
+ There are no plans to add request routing into fasthttp.
+ Use third-party routers and web frameworks with fasthttp support:
+
+ * [fasthttp-routing](https://github.com/qiangxue/fasthttp-routing)
+ * [router](https://github.com/fasthttp/router)
+ * [gramework](https://github.com/gramework/gramework)
+ * [lu](https://github.com/vincentLiuxiang/lu)
+ * [atreugo](https://github.com/savsgio/atreugo)
+ * [Fiber](https://github.com/gofiber/fiber)
+ * [Gearbox](https://github.com/gogearbox/gearbox)
+
+ See also [this issue](https://github.com/valyala/fasthttp/issues/9) for more info.
+
+* *I detected data race in fasthttp!*
+
+ Cool! [File a bug](https://github.com/valyala/fasthttp/issues/new). But before
+ doing this check the following in your code:
+
+ * Make sure there are no references to [RequestCtx](https://pkg.go.dev/github.com/valyala/fasthttp#RequestCtx)
+ or to its' members after returning from [RequestHandler](https://pkg.go.dev/github.com/valyala/fasthttp#RequestHandler).
+ * Make sure you call [TimeoutError](https://pkg.go.dev/github.com/valyala/fasthttp#RequestCtx.TimeoutError)
+ before returning from [RequestHandler](https://pkg.go.dev/github.com/valyala/fasthttp#RequestHandler)
+ if there are references to [RequestCtx](https://pkg.go.dev/github.com/valyala/fasthttp#RequestCtx)
+ or to its' members, which may be accessed by other goroutines.
+
+* *I didn't find an answer for my question here*
+
+ Try exploring [these questions](https://github.com/valyala/fasthttp/issues?q=label%3Aquestion).
diff --git a/vendor/github.com/valyala/fasthttp/SECURITY.md b/vendor/github.com/valyala/fasthttp/SECURITY.md
new file mode 100644
index 0000000..d1ad42c
--- /dev/null
+++ b/vendor/github.com/valyala/fasthttp/SECURITY.md
@@ -0,0 +1,41 @@
+### TL;DR
+
+We use a simplified version of [Golang Security Policy](https://go.dev/security).
+For example, for now we skip CVE assignment.
+
+### Reporting a Security Bug
+
+Please report to us any issues you find. This document explains how to do that and what to expect in return.
+
+All security bugs in our releases should be reported by email to erik@dubbelboer.com
+Your email will be acknowledged within 24 hours, and you'll receive a more detailed response
+to your email within 72 hours indicating the next steps in handling your report.
+Please use a descriptive subject line for your report email.
+
+### Flagging Existing Issues as Security-related
+
+If you believe that an existing issue is security-related, we ask that you send an email to erik@dubbelboer.com
+The email should include the issue ID and a short description of why it should be handled according to this security policy.
+
+### Disclosure Process
+
+Our project uses the following disclosure process:
+
+- Once the security report is received it is assigned a primary handler. This person coordinates the fix and release process.
+- The issue is confirmed and a list of affected software is determined.
+- Code is audited to find any potential similar problems.
+- Fixes are prepared for the two most recent major releases and the head/master revision. These fixes are not yet committed to the public repository.
+- To notify users, a new issue without security details is submitted to our GitHub repository.
+- Three working days following this notification, the fixes are applied to the public repository and a new release is issued.
+- On the date that the fixes are applied, announcement is published in the issue.
+
+This process can take some time, especially when coordination is required with maintainers of other projects.
+Every effort will be made to handle the bug in as timely a manner as possible, however it's important that we follow
+the process described above to ensure that disclosures are handled consistently.
+
+### Receiving Security Updates
+The best way to receive security announcements is to subscribe ("Watch") to our repository.
+Any GitHub issues pertaining to a security issue will be prefixed with [security].
+
+### Comments on This Policy
+If you have any suggestions to improve this policy, please send an email to erik@dubbelboer.com for discussion.
diff --git a/vendor/github.com/valyala/fasthttp/TODO b/vendor/github.com/valyala/fasthttp/TODO
new file mode 100644
index 0000000..ce7505f
--- /dev/null
+++ b/vendor/github.com/valyala/fasthttp/TODO
@@ -0,0 +1,4 @@
+- SessionClient with referer and cookies support.
+- ProxyHandler similar to FSHandler.
+- WebSockets. See https://tools.ietf.org/html/rfc6455 .
+- HTTP/2.0. See https://tools.ietf.org/html/rfc7540 .
diff --git a/vendor/github.com/valyala/fasthttp/args.go b/vendor/github.com/valyala/fasthttp/args.go
new file mode 100644
index 0000000..9cc1106
--- /dev/null
+++ b/vendor/github.com/valyala/fasthttp/args.go
@@ -0,0 +1,644 @@
+package fasthttp
+
+import (
+ "bytes"
+ "errors"
+ "io"
+ "sort"
+ "sync"
+
+ "github.com/valyala/bytebufferpool"
+)
+
+const (
+ argsNoValue = true
+ argsHasValue = false
+)
+
+// AcquireArgs returns an empty Args object from the pool.
+//
+// The returned Args may be returned to the pool with ReleaseArgs
+// when no longer needed. This allows reducing GC load.
+func AcquireArgs() *Args {
+ return argsPool.Get().(*Args)
+}
+
+// ReleaseArgs returns the object acquired via AcquireArgs to the pool.
+//
+// Do not access the released Args object, otherwise data races may occur.
+func ReleaseArgs(a *Args) {
+ a.Reset()
+ argsPool.Put(a)
+}
+
+var argsPool = &sync.Pool{
+ New: func() interface{} {
+ return &Args{}
+ },
+}
+
+// Args represents query arguments.
+//
+// It is forbidden copying Args instances. Create new instances instead
+// and use CopyTo().
+//
+// Args instance MUST NOT be used from concurrently running goroutines.
+type Args struct {
+ noCopy noCopy
+
+ args []argsKV
+ buf []byte
+}
+
+type argsKV struct {
+ key []byte
+ value []byte
+ noValue bool
+}
+
+// Reset clears query args.
+func (a *Args) Reset() {
+ a.args = a.args[:0]
+}
+
+// CopyTo copies all args to dst.
+func (a *Args) CopyTo(dst *Args) {
+ dst.args = copyArgs(dst.args, a.args)
+}
+
+// VisitAll calls f for each existing arg.
+//
+// f must not retain references to key and value after returning.
+// Make key and/or value copies if you need storing them after returning.
+func (a *Args) VisitAll(f func(key, value []byte)) {
+ visitArgs(a.args, f)
+}
+
+// Len returns the number of query args.
+func (a *Args) Len() int {
+ return len(a.args)
+}
+
+// Parse parses the given string containing query args.
+func (a *Args) Parse(s string) {
+ a.buf = append(a.buf[:0], s...)
+ a.ParseBytes(a.buf)
+}
+
+// ParseBytes parses the given b containing query args.
+func (a *Args) ParseBytes(b []byte) {
+ a.Reset()
+
+ var s argsScanner
+ s.b = b
+
+ var kv *argsKV
+ a.args, kv = allocArg(a.args)
+ for s.next(kv) {
+ if len(kv.key) > 0 || len(kv.value) > 0 {
+ a.args, kv = allocArg(a.args)
+ }
+ }
+ a.args = releaseArg(a.args)
+}
+
+// String returns string representation of query args.
+func (a *Args) String() string {
+ return string(a.QueryString())
+}
+
+// QueryString returns query string for the args.
+//
+// The returned value is valid until the Args is reused or released (ReleaseArgs).
+// Do not store references to the returned value. Make copies instead.
+func (a *Args) QueryString() []byte {
+ a.buf = a.AppendBytes(a.buf[:0])
+ return a.buf
+}
+
+// Sort sorts Args by key and then value using 'f' as comparison function.
+//
+// For example args.Sort(bytes.Compare)
+func (a *Args) Sort(f func(x, y []byte) int) {
+ sort.SliceStable(a.args, func(i, j int) bool {
+ n := f(a.args[i].key, a.args[j].key)
+ if n == 0 {
+ return f(a.args[i].value, a.args[j].value) == -1
+ }
+ return n == -1
+ })
+}
+
+// AppendBytes appends query string to dst and returns the extended dst.
+func (a *Args) AppendBytes(dst []byte) []byte {
+ for i, n := 0, len(a.args); i < n; i++ {
+ kv := &a.args[i]
+ dst = AppendQuotedArg(dst, kv.key)
+ if !kv.noValue {
+ dst = append(dst, '=')
+ if len(kv.value) > 0 {
+ dst = AppendQuotedArg(dst, kv.value)
+ }
+ }
+ if i+1 < n {
+ dst = append(dst, '&')
+ }
+ }
+ return dst
+}
+
+// WriteTo writes query string to w.
+//
+// WriteTo implements io.WriterTo interface.
+func (a *Args) WriteTo(w io.Writer) (int64, error) {
+ n, err := w.Write(a.QueryString())
+ return int64(n), err
+}
+
+// Del deletes argument with the given key from query args.
+func (a *Args) Del(key string) {
+ a.args = delAllArgs(a.args, key)
+}
+
+// DelBytes deletes argument with the given key from query args.
+func (a *Args) DelBytes(key []byte) {
+ a.args = delAllArgs(a.args, b2s(key))
+}
+
+// Add adds 'key=value' argument.
+//
+// Multiple values for the same key may be added.
+func (a *Args) Add(key, value string) {
+ a.args = appendArg(a.args, key, value, argsHasValue)
+}
+
+// AddBytesK adds 'key=value' argument.
+//
+// Multiple values for the same key may be added.
+func (a *Args) AddBytesK(key []byte, value string) {
+ a.args = appendArg(a.args, b2s(key), value, argsHasValue)
+}
+
+// AddBytesV adds 'key=value' argument.
+//
+// Multiple values for the same key may be added.
+func (a *Args) AddBytesV(key string, value []byte) {
+ a.args = appendArg(a.args, key, b2s(value), argsHasValue)
+}
+
+// AddBytesKV adds 'key=value' argument.
+//
+// Multiple values for the same key may be added.
+func (a *Args) AddBytesKV(key, value []byte) {
+ a.args = appendArg(a.args, b2s(key), b2s(value), argsHasValue)
+}
+
+// AddNoValue adds only 'key' as argument without the '='.
+//
+// Multiple values for the same key may be added.
+func (a *Args) AddNoValue(key string) {
+ a.args = appendArg(a.args, key, "", argsNoValue)
+}
+
+// AddBytesKNoValue adds only 'key' as argument without the '='.
+//
+// Multiple values for the same key may be added.
+func (a *Args) AddBytesKNoValue(key []byte) {
+ a.args = appendArg(a.args, b2s(key), "", argsNoValue)
+}
+
+// Set sets 'key=value' argument.
+func (a *Args) Set(key, value string) {
+ a.args = setArg(a.args, key, value, argsHasValue)
+}
+
+// SetBytesK sets 'key=value' argument.
+func (a *Args) SetBytesK(key []byte, value string) {
+ a.args = setArg(a.args, b2s(key), value, argsHasValue)
+}
+
+// SetBytesV sets 'key=value' argument.
+func (a *Args) SetBytesV(key string, value []byte) {
+ a.args = setArg(a.args, key, b2s(value), argsHasValue)
+}
+
+// SetBytesKV sets 'key=value' argument.
+func (a *Args) SetBytesKV(key, value []byte) {
+ a.args = setArgBytes(a.args, key, value, argsHasValue)
+}
+
+// SetNoValue sets only 'key' as argument without the '='.
+//
+// Only key in argument, like key1&key2
+func (a *Args) SetNoValue(key string) {
+ a.args = setArg(a.args, key, "", argsNoValue)
+}
+
+// SetBytesKNoValue sets 'key' argument.
+func (a *Args) SetBytesKNoValue(key []byte) {
+ a.args = setArg(a.args, b2s(key), "", argsNoValue)
+}
+
+// Peek returns query arg value for the given key.
+//
+// The returned value is valid until the Args is reused or released (ReleaseArgs).
+// Do not store references to the returned value. Make copies instead.
+func (a *Args) Peek(key string) []byte {
+ return peekArgStr(a.args, key)
+}
+
+// PeekBytes returns query arg value for the given key.
+//
+// The returned value is valid until the Args is reused or released (ReleaseArgs).
+// Do not store references to the returned value. Make copies instead.
+func (a *Args) PeekBytes(key []byte) []byte {
+ return peekArgBytes(a.args, key)
+}
+
+// PeekMulti returns all the arg values for the given key.
+func (a *Args) PeekMulti(key string) [][]byte {
+ var values [][]byte
+ a.VisitAll(func(k, v []byte) {
+ if string(k) == key {
+ values = append(values, v)
+ }
+ })
+ return values
+}
+
+// PeekMultiBytes returns all the arg values for the given key.
+func (a *Args) PeekMultiBytes(key []byte) [][]byte {
+ return a.PeekMulti(b2s(key))
+}
+
+// Has returns true if the given key exists in Args.
+func (a *Args) Has(key string) bool {
+ return hasArg(a.args, key)
+}
+
+// HasBytes returns true if the given key exists in Args.
+func (a *Args) HasBytes(key []byte) bool {
+ return hasArg(a.args, b2s(key))
+}
+
+// ErrNoArgValue is returned when Args value with the given key is missing.
+var ErrNoArgValue = errors.New("no Args value for the given key")
+
+// GetUint returns uint value for the given key.
+func (a *Args) GetUint(key string) (int, error) {
+ value := a.Peek(key)
+ if len(value) == 0 {
+ return -1, ErrNoArgValue
+ }
+ return ParseUint(value)
+}
+
+// SetUint sets uint value for the given key.
+func (a *Args) SetUint(key string, value int) {
+ bb := bytebufferpool.Get()
+ bb.B = AppendUint(bb.B[:0], value)
+ a.SetBytesV(key, bb.B)
+ bytebufferpool.Put(bb)
+}
+
+// SetUintBytes sets uint value for the given key.
+func (a *Args) SetUintBytes(key []byte, value int) {
+ a.SetUint(b2s(key), value)
+}
+
+// GetUintOrZero returns uint value for the given key.
+//
+// Zero (0) is returned on error.
+func (a *Args) GetUintOrZero(key string) int {
+ n, err := a.GetUint(key)
+ if err != nil {
+ n = 0
+ }
+ return n
+}
+
+// GetUfloat returns ufloat value for the given key.
+func (a *Args) GetUfloat(key string) (float64, error) {
+ value := a.Peek(key)
+ if len(value) == 0 {
+ return -1, ErrNoArgValue
+ }
+ return ParseUfloat(value)
+}
+
+// GetUfloatOrZero returns ufloat value for the given key.
+//
+// Zero (0) is returned on error.
+func (a *Args) GetUfloatOrZero(key string) float64 {
+ f, err := a.GetUfloat(key)
+ if err != nil {
+ f = 0
+ }
+ return f
+}
+
+// GetBool returns boolean value for the given key.
+//
+// true is returned for "1", "t", "T", "true", "TRUE", "True", "y", "yes", "Y", "YES", "Yes",
+// otherwise false is returned.
+func (a *Args) GetBool(key string) bool {
+ switch string(a.Peek(key)) {
+ // Support the same true cases as strconv.ParseBool
+ // See: https://github.com/golang/go/blob/4e1b11e2c9bdb0ddea1141eed487be1a626ff5be/src/strconv/atob.go#L12
+ // and Y and Yes versions.
+ case "1", "t", "T", "true", "TRUE", "True", "y", "yes", "Y", "YES", "Yes":
+ return true
+ default:
+ return false
+ }
+}
+
+func visitArgs(args []argsKV, f func(k, v []byte)) {
+ for i, n := 0, len(args); i < n; i++ {
+ kv := &args[i]
+ f(kv.key, kv.value)
+ }
+}
+
+func visitArgsKey(args []argsKV, f func(k []byte)) {
+ for i, n := 0, len(args); i < n; i++ {
+ kv := &args[i]
+ f(kv.key)
+ }
+}
+
+func copyArgs(dst, src []argsKV) []argsKV {
+ if cap(dst) < len(src) {
+ tmp := make([]argsKV, len(src))
+ dstLen := len(dst)
+ dst = dst[:cap(dst)] // copy all of dst.
+ copy(tmp, dst)
+ for i := dstLen; i < len(tmp); i++ {
+ // Make sure nothing is nil.
+ tmp[i].key = []byte{}
+ tmp[i].value = []byte{}
+ }
+ dst = tmp
+ }
+ n := len(src)
+ dst = dst[:n]
+ for i := 0; i < n; i++ {
+ dstKV := &dst[i]
+ srcKV := &src[i]
+ dstKV.key = append(dstKV.key[:0], srcKV.key...)
+ if srcKV.noValue {
+ dstKV.value = dstKV.value[:0]
+ } else {
+ dstKV.value = append(dstKV.value[:0], srcKV.value...)
+ }
+ dstKV.noValue = srcKV.noValue
+ }
+ return dst
+}
+
+func delAllArgsBytes(args []argsKV, key []byte) []argsKV {
+ return delAllArgs(args, b2s(key))
+}
+
+func delAllArgs(args []argsKV, key string) []argsKV {
+ for i, n := 0, len(args); i < n; i++ {
+ kv := &args[i]
+ if key == string(kv.key) {
+ tmp := *kv
+ copy(args[i:], args[i+1:])
+ n--
+ i--
+ args[n] = tmp
+ args = args[:n]
+ }
+ }
+ return args
+}
+
+func setArgBytes(h []argsKV, key, value []byte, noValue bool) []argsKV {
+ return setArg(h, b2s(key), b2s(value), noValue)
+}
+
+func setArg(h []argsKV, key, value string, noValue bool) []argsKV {
+ n := len(h)
+ for i := 0; i < n; i++ {
+ kv := &h[i]
+ if key == string(kv.key) {
+ if noValue {
+ kv.value = kv.value[:0]
+ } else {
+ kv.value = append(kv.value[:0], value...)
+ }
+ kv.noValue = noValue
+ return h
+ }
+ }
+ return appendArg(h, key, value, noValue)
+}
+
+func appendArgBytes(h []argsKV, key, value []byte, noValue bool) []argsKV {
+ return appendArg(h, b2s(key), b2s(value), noValue)
+}
+
+func appendArg(args []argsKV, key, value string, noValue bool) []argsKV {
+ var kv *argsKV
+ args, kv = allocArg(args)
+ kv.key = append(kv.key[:0], key...)
+ if noValue {
+ kv.value = kv.value[:0]
+ } else {
+ kv.value = append(kv.value[:0], value...)
+ }
+ kv.noValue = noValue
+ return args
+}
+
+func allocArg(h []argsKV) ([]argsKV, *argsKV) {
+ n := len(h)
+ if cap(h) > n {
+ h = h[:n+1]
+ } else {
+ h = append(h, argsKV{
+ value: []byte{},
+ })
+ }
+ return h, &h[n]
+}
+
+func releaseArg(h []argsKV) []argsKV {
+ return h[:len(h)-1]
+}
+
+func hasArg(h []argsKV, key string) bool {
+ for i, n := 0, len(h); i < n; i++ {
+ kv := &h[i]
+ if key == string(kv.key) {
+ return true
+ }
+ }
+ return false
+}
+
+func peekArgBytes(h []argsKV, k []byte) []byte {
+ for i, n := 0, len(h); i < n; i++ {
+ kv := &h[i]
+ if bytes.Equal(kv.key, k) {
+ return kv.value
+ }
+ }
+ return nil
+}
+
+func peekArgStr(h []argsKV, k string) []byte {
+ for i, n := 0, len(h); i < n; i++ {
+ kv := &h[i]
+ if string(kv.key) == k {
+ return kv.value
+ }
+ }
+ return nil
+}
+
+type argsScanner struct {
+ b []byte
+}
+
+func (s *argsScanner) next(kv *argsKV) bool {
+ if len(s.b) == 0 {
+ return false
+ }
+ kv.noValue = argsHasValue
+
+ isKey := true
+ k := 0
+ for i, c := range s.b {
+ switch c {
+ case '=':
+ if isKey {
+ isKey = false
+ kv.key = decodeArgAppend(kv.key[:0], s.b[:i])
+ k = i + 1
+ }
+ case '&':
+ if isKey {
+ kv.key = decodeArgAppend(kv.key[:0], s.b[:i])
+ kv.value = kv.value[:0]
+ kv.noValue = argsNoValue
+ } else {
+ kv.value = decodeArgAppend(kv.value[:0], s.b[k:i])
+ }
+ s.b = s.b[i+1:]
+ return true
+ }
+ }
+
+ if isKey {
+ kv.key = decodeArgAppend(kv.key[:0], s.b)
+ kv.value = kv.value[:0]
+ kv.noValue = argsNoValue
+ } else {
+ kv.value = decodeArgAppend(kv.value[:0], s.b[k:])
+ }
+ s.b = s.b[len(s.b):]
+ return true
+}
+
+func decodeArgAppend(dst, src []byte) []byte {
+ idxPercent := bytes.IndexByte(src, '%')
+ idxPlus := bytes.IndexByte(src, '+')
+ if idxPercent == -1 && idxPlus == -1 {
+ // fast path: src doesn't contain encoded chars
+ return append(dst, src...)
+ }
+
+ idx := 0
+ switch {
+ case idxPercent == -1:
+ idx = idxPlus
+ case idxPlus == -1:
+ idx = idxPercent
+ case idxPercent > idxPlus:
+ idx = idxPlus
+ default:
+ idx = idxPercent
+ }
+
+ dst = append(dst, src[:idx]...)
+
+ // slow path
+ for i := idx; i < len(src); i++ {
+ c := src[i]
+ switch c {
+ case '%':
+ if i+2 >= len(src) {
+ return append(dst, src[i:]...)
+ }
+ x2 := hex2intTable[src[i+2]]
+ x1 := hex2intTable[src[i+1]]
+ if x1 == 16 || x2 == 16 {
+ dst = append(dst, '%')
+ } else {
+ dst = append(dst, x1<<4|x2)
+ i += 2
+ }
+ case '+':
+ dst = append(dst, ' ')
+ default:
+ dst = append(dst, c)
+ }
+ }
+ return dst
+}
+
+// decodeArgAppendNoPlus is almost identical to decodeArgAppend, but it doesn't
+// substitute '+' with ' '.
+//
+// The function is copy-pasted from decodeArgAppend due to the performance
+// reasons only.
+func decodeArgAppendNoPlus(dst, src []byte) []byte {
+ idx := bytes.IndexByte(src, '%')
+ if idx < 0 {
+ // fast path: src doesn't contain encoded chars
+ return append(dst, src...)
+ }
+ dst = append(dst, src[:idx]...)
+
+ // slow path
+ for i := idx; i < len(src); i++ {
+ c := src[i]
+ if c == '%' {
+ if i+2 >= len(src) {
+ return append(dst, src[i:]...)
+ }
+ x2 := hex2intTable[src[i+2]]
+ x1 := hex2intTable[src[i+1]]
+ if x1 == 16 || x2 == 16 {
+ dst = append(dst, '%')
+ } else {
+ dst = append(dst, x1<<4|x2)
+ i += 2
+ }
+ } else {
+ dst = append(dst, c)
+ }
+ }
+ return dst
+}
+
+func peekAllArgBytesToDst(dst [][]byte, h []argsKV, k []byte) [][]byte {
+ for i, n := 0, len(h); i < n; i++ {
+ kv := &h[i]
+ if bytes.Equal(kv.key, k) {
+ dst = append(dst, kv.value)
+ }
+ }
+ return dst
+}
+
+func peekArgsKeys(dst [][]byte, h []argsKV) [][]byte {
+ for i, n := 0, len(h); i < n; i++ {
+ kv := &h[i]
+ dst = append(dst, kv.key)
+ }
+ return dst
+}
diff --git a/vendor/github.com/valyala/fasthttp/b2s_new.go b/vendor/github.com/valyala/fasthttp/b2s_new.go
new file mode 100644
index 0000000..a45222c
--- /dev/null
+++ b/vendor/github.com/valyala/fasthttp/b2s_new.go
@@ -0,0 +1,11 @@
+//go:build go1.20
+
+package fasthttp
+
+import "unsafe"
+
+// b2s converts byte slice to a string without memory allocation.
+// See https://groups.google.com/forum/#!msg/Golang-Nuts/ENgbUzYvCuU/90yGx7GUAgAJ .
+func b2s(b []byte) string {
+ return unsafe.String(unsafe.SliceData(b), len(b))
+}
diff --git a/vendor/github.com/valyala/fasthttp/b2s_old.go b/vendor/github.com/valyala/fasthttp/b2s_old.go
new file mode 100644
index 0000000..f6e9466
--- /dev/null
+++ b/vendor/github.com/valyala/fasthttp/b2s_old.go
@@ -0,0 +1,14 @@
+//go:build !go1.20
+
+package fasthttp
+
+import "unsafe"
+
+// b2s converts byte slice to a string without memory allocation.
+// See https://groups.google.com/forum/#!msg/Golang-Nuts/ENgbUzYvCuU/90yGx7GUAgAJ .
+//
+// Note it may break if string and/or slice header will change
+// in the future go versions.
+func b2s(b []byte) string {
+ return *(*string)(unsafe.Pointer(&b))
+}
diff --git a/vendor/github.com/valyala/fasthttp/brotli.go b/vendor/github.com/valyala/fasthttp/brotli.go
new file mode 100644
index 0000000..032bd95
--- /dev/null
+++ b/vendor/github.com/valyala/fasthttp/brotli.go
@@ -0,0 +1,200 @@
+package fasthttp
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "sync"
+
+ "github.com/andybalholm/brotli"
+ "github.com/valyala/bytebufferpool"
+ "github.com/valyala/fasthttp/stackless"
+)
+
+// Supported compression levels.
+const (
+ CompressBrotliNoCompression = 0
+ CompressBrotliBestSpeed = brotli.BestSpeed
+ CompressBrotliBestCompression = brotli.BestCompression
+
+ // Choose a default brotli compression level comparable to
+ // CompressDefaultCompression (gzip 6)
+ // See: https://github.com/valyala/fasthttp/issues/798#issuecomment-626293806
+ CompressBrotliDefaultCompression = 4
+)
+
+func acquireBrotliReader(r io.Reader) (*brotli.Reader, error) {
+ v := brotliReaderPool.Get()
+ if v == nil {
+ return brotli.NewReader(r), nil
+ }
+ zr := v.(*brotli.Reader)
+ if err := zr.Reset(r); err != nil {
+ return nil, err
+ }
+ return zr, nil
+}
+
+func releaseBrotliReader(zr *brotli.Reader) {
+ brotliReaderPool.Put(zr)
+}
+
+var brotliReaderPool sync.Pool
+
+func acquireStacklessBrotliWriter(w io.Writer, level int) stackless.Writer {
+ nLevel := normalizeBrotliCompressLevel(level)
+ p := stacklessBrotliWriterPoolMap[nLevel]
+ v := p.Get()
+ if v == nil {
+ return stackless.NewWriter(w, func(w io.Writer) stackless.Writer {
+ return acquireRealBrotliWriter(w, level)
+ })
+ }
+ sw := v.(stackless.Writer)
+ sw.Reset(w)
+ return sw
+}
+
+func releaseStacklessBrotliWriter(sw stackless.Writer, level int) {
+ sw.Close()
+ nLevel := normalizeBrotliCompressLevel(level)
+ p := stacklessBrotliWriterPoolMap[nLevel]
+ p.Put(sw)
+}
+
+func acquireRealBrotliWriter(w io.Writer, level int) *brotli.Writer {
+ nLevel := normalizeBrotliCompressLevel(level)
+ p := realBrotliWriterPoolMap[nLevel]
+ v := p.Get()
+ if v == nil {
+ zw := brotli.NewWriterLevel(w, level)
+ return zw
+ }
+ zw := v.(*brotli.Writer)
+ zw.Reset(w)
+ return zw
+}
+
+func releaseRealBrotliWriter(zw *brotli.Writer, level int) {
+ zw.Close()
+ nLevel := normalizeBrotliCompressLevel(level)
+ p := realBrotliWriterPoolMap[nLevel]
+ p.Put(zw)
+}
+
+var (
+ stacklessBrotliWriterPoolMap = newCompressWriterPoolMap()
+ realBrotliWriterPoolMap = newCompressWriterPoolMap()
+)
+
+// AppendBrotliBytesLevel appends brotlied src to dst using the given
+// compression level and returns the resulting dst.
+//
+// Supported compression levels are:
+//
+// - CompressBrotliNoCompression
+// - CompressBrotliBestSpeed
+// - CompressBrotliBestCompression
+// - CompressBrotliDefaultCompression
+func AppendBrotliBytesLevel(dst, src []byte, level int) []byte {
+ w := &byteSliceWriter{dst}
+ WriteBrotliLevel(w, src, level) //nolint:errcheck
+ return w.b
+}
+
+// WriteBrotliLevel writes brotlied p to w using the given compression level
+// and returns the number of compressed bytes written to w.
+//
+// Supported compression levels are:
+//
+// - CompressBrotliNoCompression
+// - CompressBrotliBestSpeed
+// - CompressBrotliBestCompression
+// - CompressBrotliDefaultCompression
+func WriteBrotliLevel(w io.Writer, p []byte, level int) (int, error) {
+ switch w.(type) {
+ case *byteSliceWriter,
+ *bytes.Buffer,
+ *bytebufferpool.ByteBuffer:
+ // These writers don't block, so we can just use stacklessWriteBrotli
+ ctx := &compressCtx{
+ w: w,
+ p: p,
+ level: level,
+ }
+ stacklessWriteBrotli(ctx)
+ return len(p), nil
+ default:
+ zw := acquireStacklessBrotliWriter(w, level)
+ n, err := zw.Write(p)
+ releaseStacklessBrotliWriter(zw, level)
+ return n, err
+ }
+}
+
+var (
+ stacklessWriteBrotliOnce sync.Once
+ stacklessWriteBrotliFunc func(ctx interface{}) bool
+)
+
+func stacklessWriteBrotli(ctx interface{}) {
+ stacklessWriteBrotliOnce.Do(func() {
+ stacklessWriteBrotliFunc = stackless.NewFunc(nonblockingWriteBrotli)
+ })
+ stacklessWriteBrotliFunc(ctx)
+}
+
+func nonblockingWriteBrotli(ctxv interface{}) {
+ ctx := ctxv.(*compressCtx)
+ zw := acquireRealBrotliWriter(ctx.w, ctx.level)
+
+ zw.Write(ctx.p) //nolint:errcheck // no way to handle this error anyway
+
+ releaseRealBrotliWriter(zw, ctx.level)
+}
+
+// WriteBrotli writes brotlied p to w and returns the number of compressed
+// bytes written to w.
+func WriteBrotli(w io.Writer, p []byte) (int, error) {
+ return WriteBrotliLevel(w, p, CompressBrotliDefaultCompression)
+}
+
+// AppendBrotliBytes appends brotlied src to dst and returns the resulting dst.
+func AppendBrotliBytes(dst, src []byte) []byte {
+ return AppendBrotliBytesLevel(dst, src, CompressBrotliDefaultCompression)
+}
+
+// WriteUnbrotli writes unbrotlied p to w and returns the number of uncompressed
+// bytes written to w.
+func WriteUnbrotli(w io.Writer, p []byte) (int, error) {
+ r := &byteSliceReader{p}
+ zr, err := acquireBrotliReader(r)
+ if err != nil {
+ return 0, err
+ }
+ n, err := copyZeroAlloc(w, zr)
+ releaseBrotliReader(zr)
+ nn := int(n)
+ if int64(nn) != n {
+ return 0, fmt.Errorf("too much data unbrotlied: %d", n)
+ }
+ return nn, err
+}
+
+// AppendUnbrotliBytes appends unbrotlied src to dst and returns the resulting dst.
+func AppendUnbrotliBytes(dst, src []byte) ([]byte, error) {
+ w := &byteSliceWriter{dst}
+ _, err := WriteUnbrotli(w, src)
+ return w.b, err
+}
+
+// normalizes compression level into [0..11], so it could be used as an index
+// in *PoolMap.
+func normalizeBrotliCompressLevel(level int) int {
+ // -2 is the lowest compression level - CompressHuffmanOnly
+ // 9 is the highest compression level - CompressBestCompression
+ if level < 0 || level > 11 {
+ level = CompressBrotliDefaultCompression
+ }
+ return level
+}
diff --git a/vendor/github.com/valyala/fasthttp/bytesconv.go b/vendor/github.com/valyala/fasthttp/bytesconv.go
new file mode 100644
index 0000000..b3cf29e
--- /dev/null
+++ b/vendor/github.com/valyala/fasthttp/bytesconv.go
@@ -0,0 +1,357 @@
+//go:generate go run bytesconv_table_gen.go
+
+package fasthttp
+
+import (
+ "bufio"
+ "bytes"
+ "errors"
+ "fmt"
+ "io"
+ "math"
+ "net"
+ "sync"
+ "time"
+)
+
+// AppendHTMLEscape appends html-escaped s to dst and returns the extended dst.
+func AppendHTMLEscape(dst []byte, s string) []byte {
+ var (
+ prev int
+ sub string
+ )
+
+ for i, n := 0, len(s); i < n; i++ {
+ sub = ""
+ switch s[i] {
+ case '&':
+ sub = "&"
+ case '<':
+ sub = "<"
+ case '>':
+ sub = ">"
+ case '"':
+ sub = """ // """ is shorter than """.
+ case '\'':
+ sub = "'" // "'" is shorter than "'" and apos was not in HTML until HTML5.
+ }
+ if len(sub) > 0 {
+ dst = append(dst, s[prev:i]...)
+ dst = append(dst, sub...)
+ prev = i + 1
+ }
+ }
+ return append(dst, s[prev:]...)
+}
+
+// AppendHTMLEscapeBytes appends html-escaped s to dst and returns
+// the extended dst.
+func AppendHTMLEscapeBytes(dst, s []byte) []byte {
+ return AppendHTMLEscape(dst, b2s(s))
+}
+
+// AppendIPv4 appends string representation of the given ip v4 to dst
+// and returns the extended dst.
+func AppendIPv4(dst []byte, ip net.IP) []byte {
+ ip = ip.To4()
+ if ip == nil {
+ return append(dst, "non-v4 ip passed to AppendIPv4"...)
+ }
+
+ dst = AppendUint(dst, int(ip[0]))
+ for i := 1; i < 4; i++ {
+ dst = append(dst, '.')
+ dst = AppendUint(dst, int(ip[i]))
+ }
+ return dst
+}
+
+var errEmptyIPStr = errors.New("empty ip address string")
+
+// ParseIPv4 parses ip address from ipStr into dst and returns the extended dst.
+func ParseIPv4(dst net.IP, ipStr []byte) (net.IP, error) {
+ if len(ipStr) == 0 {
+ return dst, errEmptyIPStr
+ }
+ if len(dst) < net.IPv4len {
+ dst = make([]byte, net.IPv4len)
+ }
+ copy(dst, net.IPv4zero)
+ dst = dst.To4()
+ if dst == nil {
+ // developer sanity-check
+ panic("BUG: dst must not be nil")
+ }
+
+ b := ipStr
+ for i := 0; i < 3; i++ {
+ n := bytes.IndexByte(b, '.')
+ if n < 0 {
+ return dst, fmt.Errorf("cannot find dot in ipStr %q", ipStr)
+ }
+ v, err := ParseUint(b[:n])
+ if err != nil {
+ return dst, fmt.Errorf("cannot parse ipStr %q: %w", ipStr, err)
+ }
+ if v > 255 {
+ return dst, fmt.Errorf("cannot parse ipStr %q: ip part cannot exceed 255: parsed %d", ipStr, v)
+ }
+ dst[i] = byte(v)
+ b = b[n+1:]
+ }
+ v, err := ParseUint(b)
+ if err != nil {
+ return dst, fmt.Errorf("cannot parse ipStr %q: %w", ipStr, err)
+ }
+ if v > 255 {
+ return dst, fmt.Errorf("cannot parse ipStr %q: ip part cannot exceed 255: parsed %d", ipStr, v)
+ }
+ dst[3] = byte(v)
+
+ return dst, nil
+}
+
+// AppendHTTPDate appends HTTP-compliant (RFC1123) representation of date
+// to dst and returns the extended dst.
+func AppendHTTPDate(dst []byte, date time.Time) []byte {
+ dst = date.In(time.UTC).AppendFormat(dst, time.RFC1123)
+ copy(dst[len(dst)-3:], strGMT)
+ return dst
+}
+
+// ParseHTTPDate parses HTTP-compliant (RFC1123) date.
+func ParseHTTPDate(date []byte) (time.Time, error) {
+ return time.Parse(time.RFC1123, b2s(date))
+}
+
+// AppendUint appends n to dst and returns the extended dst.
+func AppendUint(dst []byte, n int) []byte {
+ if n < 0 {
+ // developer sanity-check
+ panic("BUG: int must be positive")
+ }
+
+ var b [20]byte
+ buf := b[:]
+ i := len(buf)
+ var q int
+ for n >= 10 {
+ i--
+ q = n / 10
+ buf[i] = '0' + byte(n-q*10)
+ n = q
+ }
+ i--
+ buf[i] = '0' + byte(n)
+
+ dst = append(dst, buf[i:]...)
+ return dst
+}
+
+// ParseUint parses uint from buf.
+func ParseUint(buf []byte) (int, error) {
+ v, n, err := parseUintBuf(buf)
+ if n != len(buf) {
+ return -1, errUnexpectedTrailingChar
+ }
+ return v, err
+}
+
+var (
+ errEmptyInt = errors.New("empty integer")
+ errUnexpectedFirstChar = errors.New("unexpected first char found. Expecting 0-9")
+ errUnexpectedTrailingChar = errors.New("unexpected trailing char found. Expecting 0-9")
+ errTooLongInt = errors.New("too long int")
+)
+
+func parseUintBuf(b []byte) (int, int, error) {
+ n := len(b)
+ if n == 0 {
+ return -1, 0, errEmptyInt
+ }
+ v := 0
+ for i := 0; i < n; i++ {
+ c := b[i]
+ k := c - '0'
+ if k > 9 {
+ if i == 0 {
+ return -1, i, errUnexpectedFirstChar
+ }
+ return v, i, nil
+ }
+ vNew := 10*v + int(k)
+ // Test for overflow.
+ if vNew < v {
+ return -1, i, errTooLongInt
+ }
+ v = vNew
+ }
+ return v, n, nil
+}
+
+var (
+ errEmptyFloat = errors.New("empty float number")
+ errDuplicateFloatPoint = errors.New("duplicate point found in float number")
+ errUnexpectedFloatEnd = errors.New("unexpected end of float number")
+ errInvalidFloatExponent = errors.New("invalid float number exponent")
+ errUnexpectedFloatChar = errors.New("unexpected char found in float number")
+)
+
+// ParseUfloat parses unsigned float from buf.
+func ParseUfloat(buf []byte) (float64, error) {
+ if len(buf) == 0 {
+ return -1, errEmptyFloat
+ }
+ b := buf
+ var v uint64
+ offset := 1.0
+ var pointFound bool
+ for i, c := range b {
+ if c < '0' || c > '9' {
+ if c == '.' {
+ if pointFound {
+ return -1, errDuplicateFloatPoint
+ }
+ pointFound = true
+ continue
+ }
+ if c == 'e' || c == 'E' {
+ if i+1 >= len(b) {
+ return -1, errUnexpectedFloatEnd
+ }
+ b = b[i+1:]
+ minus := -1
+ switch b[0] {
+ case '+':
+ b = b[1:]
+ minus = 1
+ case '-':
+ b = b[1:]
+ default:
+ minus = 1
+ }
+ vv, err := ParseUint(b)
+ if err != nil {
+ return -1, errInvalidFloatExponent
+ }
+ return float64(v) * offset * math.Pow10(minus*vv), nil
+ }
+ return -1, errUnexpectedFloatChar
+ }
+ v = 10*v + uint64(c-'0')
+ if pointFound {
+ offset /= 10
+ }
+ }
+ return float64(v) * offset, nil
+}
+
+var (
+ errEmptyHexNum = errors.New("empty hex number")
+ errTooLargeHexNum = errors.New("too large hex number")
+)
+
+func readHexInt(r *bufio.Reader) (int, error) {
+ var k, i, n int
+ for {
+ c, err := r.ReadByte()
+ if err != nil {
+ if err == io.EOF && i > 0 {
+ return n, nil
+ }
+ return -1, err
+ }
+ k = int(hex2intTable[c])
+ if k == 16 {
+ if i == 0 {
+ return -1, errEmptyHexNum
+ }
+ if err := r.UnreadByte(); err != nil {
+ return -1, err
+ }
+ return n, nil
+ }
+ if i >= maxHexIntChars {
+ return -1, errTooLargeHexNum
+ }
+ n = (n << 4) | k
+ i++
+ }
+}
+
+var hexIntBufPool sync.Pool
+
+func writeHexInt(w *bufio.Writer, n int) error {
+ if n < 0 {
+ // developer sanity-check
+ panic("BUG: int must be positive")
+ }
+
+ v := hexIntBufPool.Get()
+ if v == nil {
+ v = make([]byte, maxHexIntChars+1)
+ }
+ buf := v.([]byte)
+ i := len(buf) - 1
+ for {
+ buf[i] = lowerhex[n&0xf]
+ n >>= 4
+ if n == 0 {
+ break
+ }
+ i--
+ }
+ _, err := w.Write(buf[i:])
+ hexIntBufPool.Put(v)
+ return err
+}
+
+const (
+ upperhex = "0123456789ABCDEF"
+ lowerhex = "0123456789abcdef"
+)
+
+func lowercaseBytes(b []byte) {
+ for i := 0; i < len(b); i++ {
+ p := &b[i]
+ *p = toLowerTable[*p]
+ }
+}
+
+// AppendUnquotedArg appends url-decoded src to dst and returns appended dst.
+//
+// dst may point to src. In this case src will be overwritten.
+func AppendUnquotedArg(dst, src []byte) []byte {
+ return decodeArgAppend(dst, src)
+}
+
+// AppendQuotedArg appends url-encoded src to dst and returns appended dst.
+func AppendQuotedArg(dst, src []byte) []byte {
+ for _, c := range src {
+ switch {
+ case c == ' ':
+ dst = append(dst, '+')
+ case quotedArgShouldEscapeTable[int(c)] != 0:
+ dst = append(dst, '%', upperhex[c>>4], upperhex[c&0xf])
+ default:
+ dst = append(dst, c)
+ }
+ }
+ return dst
+}
+
+func appendQuotedPath(dst, src []byte) []byte {
+ // Fix issue in https://github.com/golang/go/issues/11202
+ if len(src) == 1 && src[0] == '*' {
+ return append(dst, '*')
+ }
+
+ for _, c := range src {
+ if quotedPathShouldEscapeTable[int(c)] != 0 {
+ dst = append(dst, '%', upperhex[c>>4], upperhex[c&0xf])
+ } else {
+ dst = append(dst, c)
+ }
+ }
+ return dst
+}
diff --git a/vendor/github.com/valyala/fasthttp/bytesconv_32.go b/vendor/github.com/valyala/fasthttp/bytesconv_32.go
new file mode 100644
index 0000000..baa9459
--- /dev/null
+++ b/vendor/github.com/valyala/fasthttp/bytesconv_32.go
@@ -0,0 +1,7 @@
+//go:build !amd64 && !arm64 && !ppc64 && !ppc64le && !s390x
+
+package fasthttp
+
+const (
+ maxHexIntChars = 7
+)
diff --git a/vendor/github.com/valyala/fasthttp/bytesconv_64.go b/vendor/github.com/valyala/fasthttp/bytesconv_64.go
new file mode 100644
index 0000000..e7c01bb
--- /dev/null
+++ b/vendor/github.com/valyala/fasthttp/bytesconv_64.go
@@ -0,0 +1,7 @@
+//go:build amd64 || arm64 || ppc64 || ppc64le || s390x
+
+package fasthttp
+
+const (
+ maxHexIntChars = 15
+)
diff --git a/vendor/github.com/valyala/fasthttp/bytesconv_table.go b/vendor/github.com/valyala/fasthttp/bytesconv_table.go
new file mode 100644
index 0000000..78a12a3
--- /dev/null
+++ b/vendor/github.com/valyala/fasthttp/bytesconv_table.go
@@ -0,0 +1,10 @@
+package fasthttp
+
+// Code generated by go run bytesconv_table_gen.go; DO NOT EDIT.
+// See bytesconv_table_gen.go for more information about these tables.
+
+const hex2intTable = "\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x00\x01\x02\x03\x04\x05\x06\a\b\t\x10\x10\x10\x10\x10\x10\x10\n\v\f\r\x0e\x0f\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\n\v\f\r\x0e\x0f\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10"
+const toLowerTable = "\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@abcdefghijklmnopqrstuvwxyz[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\u007f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"
+const toUpperTable = "\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`ABCDEFGHIJKLMNOPQRSTUVWXYZ{|}~\u007f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"
+const quotedArgShouldEscapeTable = "\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x01\x01\x01\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x01\x01\x01\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x01\x01\x00\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01"
+const quotedPathShouldEscapeTable = "\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x00\x01\x00\x01\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x01\x01\x01\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x01\x01\x00\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01"
diff --git a/vendor/github.com/valyala/fasthttp/client.go b/vendor/github.com/valyala/fasthttp/client.go
new file mode 100644
index 0000000..498de05
--- /dev/null
+++ b/vendor/github.com/valyala/fasthttp/client.go
@@ -0,0 +1,2958 @@
+package fasthttp
+
+import (
+ "bufio"
+ "crypto/tls"
+ "errors"
+ "fmt"
+ "io"
+ "net"
+ "strings"
+ "sync"
+ "sync/atomic"
+ "time"
+)
+
+// Do performs the given http request and fills the given http response.
+//
+// Request must contain at least non-zero RequestURI with full url (including
+// scheme and host) or non-zero Host header + RequestURI.
+//
+// Client determines the server to be requested in the following order:
+//
+// - from RequestURI if it contains full url with scheme and host;
+// - from Host header otherwise.
+//
+// The function doesn't follow redirects. Use Get* for following redirects.
+//
+// Response is ignored if resp is nil.
+//
+// ErrNoFreeConns is returned if all DefaultMaxConnsPerHost connections
+// to the requested host are busy.
+//
+// It is recommended obtaining req and resp via AcquireRequest
+// and AcquireResponse in performance-critical code.
+func Do(req *Request, resp *Response) error {
+ return defaultClient.Do(req, resp)
+}
+
+// DoTimeout performs the given request and waits for response during
+// the given timeout duration.
+//
+// Request must contain at least non-zero RequestURI with full url (including
+// scheme and host) or non-zero Host header + RequestURI.
+//
+// Client determines the server to be requested in the following order:
+//
+// - from RequestURI if it contains full url with scheme and host;
+// - from Host header otherwise.
+//
+// The function doesn't follow redirects. Use Get* for following redirects.
+//
+// Response is ignored if resp is nil.
+//
+// ErrTimeout is returned if the response wasn't returned during
+// the given timeout.
+//
+// ErrNoFreeConns is returned if all DefaultMaxConnsPerHost connections
+// to the requested host are busy.
+//
+// It is recommended obtaining req and resp via AcquireRequest
+// and AcquireResponse in performance-critical code.
+func DoTimeout(req *Request, resp *Response, timeout time.Duration) error {
+ return defaultClient.DoTimeout(req, resp, timeout)
+}
+
+// DoDeadline performs the given request and waits for response until
+// the given deadline.
+//
+// Request must contain at least non-zero RequestURI with full url (including
+// scheme and host) or non-zero Host header + RequestURI.
+//
+// Client determines the server to be requested in the following order:
+//
+// - from RequestURI if it contains full url with scheme and host;
+// - from Host header otherwise.
+//
+// The function doesn't follow redirects. Use Get* for following redirects.
+//
+// Response is ignored if resp is nil.
+//
+// ErrTimeout is returned if the response wasn't returned until
+// the given deadline.
+//
+// ErrNoFreeConns is returned if all DefaultMaxConnsPerHost connections
+// to the requested host are busy.
+//
+// It is recommended obtaining req and resp via AcquireRequest
+// and AcquireResponse in performance-critical code.
+func DoDeadline(req *Request, resp *Response, deadline time.Time) error {
+ return defaultClient.DoDeadline(req, resp, deadline)
+}
+
+// DoRedirects performs the given http request and fills the given http response,
+// following up to maxRedirectsCount redirects. When the redirect count exceeds
+// maxRedirectsCount, ErrTooManyRedirects is returned.
+//
+// Request must contain at least non-zero RequestURI with full url (including
+// scheme and host) or non-zero Host header + RequestURI.
+//
+// Client determines the server to be requested in the following order:
+//
+// - from RequestURI if it contains full url with scheme and host;
+// - from Host header otherwise.
+//
+// Response is ignored if resp is nil.
+//
+// ErrNoFreeConns is returned if all DefaultMaxConnsPerHost connections
+// to the requested host are busy.
+//
+// It is recommended obtaining req and resp via AcquireRequest
+// and AcquireResponse in performance-critical code.
+func DoRedirects(req *Request, resp *Response, maxRedirectsCount int) error {
+ _, _, err := doRequestFollowRedirects(req, resp, req.URI().String(), maxRedirectsCount, &defaultClient)
+ return err
+}
+
+// Get returns the status code and body of url.
+//
+// The contents of dst will be replaced by the body and returned, if the dst
+// is too small a new slice will be allocated.
+//
+// The function follows redirects. Use Do* for manually handling redirects.
+func Get(dst []byte, url string) (statusCode int, body []byte, err error) {
+ return defaultClient.Get(dst, url)
+}
+
+// GetTimeout returns the status code and body of url.
+//
+// The contents of dst will be replaced by the body and returned, if the dst
+// is too small a new slice will be allocated.
+//
+// The function follows redirects. Use Do* for manually handling redirects.
+//
+// ErrTimeout error is returned if url contents couldn't be fetched
+// during the given timeout.
+func GetTimeout(dst []byte, url string, timeout time.Duration) (statusCode int, body []byte, err error) {
+ return defaultClient.GetTimeout(dst, url, timeout)
+}
+
+// GetDeadline returns the status code and body of url.
+//
+// The contents of dst will be replaced by the body and returned, if the dst
+// is too small a new slice will be allocated.
+//
+// The function follows redirects. Use Do* for manually handling redirects.
+//
+// ErrTimeout error is returned if url contents couldn't be fetched
+// until the given deadline.
+func GetDeadline(dst []byte, url string, deadline time.Time) (statusCode int, body []byte, err error) {
+ return defaultClient.GetDeadline(dst, url, deadline)
+}
+
+// Post sends POST request to the given url with the given POST arguments.
+//
+// The contents of dst will be replaced by the body and returned, if the dst
+// is too small a new slice will be allocated.
+//
+// The function follows redirects. Use Do* for manually handling redirects.
+//
+// Empty POST body is sent if postArgs is nil.
+func Post(dst []byte, url string, postArgs *Args) (statusCode int, body []byte, err error) {
+ return defaultClient.Post(dst, url, postArgs)
+}
+
+var defaultClient Client
+
+// Client implements http client.
+//
+// Copying Client by value is prohibited. Create new instance instead.
+//
+// It is safe calling Client methods from concurrently running goroutines.
+//
+// The fields of a Client should not be changed while it is in use.
+type Client struct {
+ noCopy noCopy
+
+ // Client name. Used in User-Agent request header.
+ //
+ // Default client name is used if not set.
+ Name string
+
+ // NoDefaultUserAgentHeader when set to true, causes the default
+ // User-Agent header to be excluded from the Request.
+ NoDefaultUserAgentHeader bool
+
+ // Callback for establishing new connections to hosts.
+ //
+ // Default Dial is used if not set.
+ Dial DialFunc
+
+ // Attempt to connect to both ipv4 and ipv6 addresses if set to true.
+ //
+ // This option is used only if default TCP dialer is used,
+ // i.e. if Dial is blank.
+ //
+ // By default client connects only to ipv4 addresses,
+ // since unfortunately ipv6 remains broken in many networks worldwide :)
+ DialDualStack bool
+
+ // TLS config for https connections.
+ //
+ // Default TLS config is used if not set.
+ TLSConfig *tls.Config
+
+ // Maximum number of connections per each host which may be established.
+ //
+ // DefaultMaxConnsPerHost is used if not set.
+ MaxConnsPerHost int
+
+ // Idle keep-alive connections are closed after this duration.
+ //
+ // By default idle connections are closed
+ // after DefaultMaxIdleConnDuration.
+ MaxIdleConnDuration time.Duration
+
+ // Keep-alive connections are closed after this duration.
+ //
+ // By default connection duration is unlimited.
+ MaxConnDuration time.Duration
+
+ // Maximum number of attempts for idempotent calls
+ //
+ // DefaultMaxIdemponentCallAttempts is used if not set.
+ MaxIdemponentCallAttempts int
+
+ // Per-connection buffer size for responses' reading.
+ // This also limits the maximum header size.
+ //
+ // Default buffer size is used if 0.
+ ReadBufferSize int
+
+ // Per-connection buffer size for requests' writing.
+ //
+ // Default buffer size is used if 0.
+ WriteBufferSize int
+
+ // Maximum duration for full response reading (including body).
+ //
+ // By default response read timeout is unlimited.
+ ReadTimeout time.Duration
+
+ // Maximum duration for full request writing (including body).
+ //
+ // By default request write timeout is unlimited.
+ WriteTimeout time.Duration
+
+ // Maximum response body size.
+ //
+ // The client returns ErrBodyTooLarge if this limit is greater than 0
+ // and response body is greater than the limit.
+ //
+ // By default response body size is unlimited.
+ MaxResponseBodySize int
+
+ // Header names are passed as-is without normalization
+ // if this option is set.
+ //
+ // Disabled header names' normalization may be useful only for proxying
+ // responses to other clients expecting case-sensitive
+ // header names. See https://github.com/valyala/fasthttp/issues/57
+ // for details.
+ //
+ // By default request and response header names are normalized, i.e.
+ // The first letter and the first letters following dashes
+ // are uppercased, while all the other letters are lowercased.
+ // Examples:
+ //
+ // * HOST -> Host
+ // * content-type -> Content-Type
+ // * cONTENT-lenGTH -> Content-Length
+ DisableHeaderNamesNormalizing bool
+
+ // Path values are sent as-is without normalization
+ //
+ // Disabled path normalization may be useful for proxying incoming requests
+ // to servers that are expecting paths to be forwarded as-is.
+ //
+ // By default path values are normalized, i.e.
+ // extra slashes are removed, special characters are encoded.
+ DisablePathNormalizing bool
+
+ // Maximum duration for waiting for a free connection.
+ //
+ // By default will not waiting, return ErrNoFreeConns immediately
+ MaxConnWaitTimeout time.Duration
+
+ // RetryIf controls whether a retry should be attempted after an error.
+ //
+ // By default will use isIdempotent function
+ RetryIf RetryIfFunc
+
+ // Connection pool strategy. Can be either LIFO or FIFO (default).
+ ConnPoolStrategy ConnPoolStrategyType
+
+ // StreamResponseBody enables response body streaming
+ StreamResponseBody bool
+
+ // ConfigureClient configures the fasthttp.HostClient.
+ ConfigureClient func(hc *HostClient) error
+
+ mLock sync.RWMutex
+ mOnce sync.Once
+ m map[string]*HostClient
+ ms map[string]*HostClient
+ readerPool sync.Pool
+ writerPool sync.Pool
+}
+
+// Get returns the status code and body of url.
+//
+// The contents of dst will be replaced by the body and returned, if the dst
+// is too small a new slice will be allocated.
+//
+// The function follows redirects. Use Do* for manually handling redirects.
+func (c *Client) Get(dst []byte, url string) (statusCode int, body []byte, err error) {
+ return clientGetURL(dst, url, c)
+}
+
+// GetTimeout returns the status code and body of url.
+//
+// The contents of dst will be replaced by the body and returned, if the dst
+// is too small a new slice will be allocated.
+//
+// The function follows redirects. Use Do* for manually handling redirects.
+//
+// ErrTimeout error is returned if url contents couldn't be fetched
+// during the given timeout.
+func (c *Client) GetTimeout(dst []byte, url string, timeout time.Duration) (statusCode int, body []byte, err error) {
+ return clientGetURLTimeout(dst, url, timeout, c)
+}
+
+// GetDeadline returns the status code and body of url.
+//
+// The contents of dst will be replaced by the body and returned, if the dst
+// is too small a new slice will be allocated.
+//
+// The function follows redirects. Use Do* for manually handling redirects.
+//
+// ErrTimeout error is returned if url contents couldn't be fetched
+// until the given deadline.
+func (c *Client) GetDeadline(dst []byte, url string, deadline time.Time) (statusCode int, body []byte, err error) {
+ return clientGetURLDeadline(dst, url, deadline, c)
+}
+
+// Post sends POST request to the given url with the given POST arguments.
+//
+// The contents of dst will be replaced by the body and returned, if the dst
+// is too small a new slice will be allocated.
+//
+// The function follows redirects. Use Do* for manually handling redirects.
+//
+// Empty POST body is sent if postArgs is nil.
+func (c *Client) Post(dst []byte, url string, postArgs *Args) (statusCode int, body []byte, err error) {
+ return clientPostURL(dst, url, postArgs, c)
+}
+
+// DoTimeout performs the given request and waits for response during
+// the given timeout duration.
+//
+// Request must contain at least non-zero RequestURI with full url (including
+// scheme and host) or non-zero Host header + RequestURI.
+//
+// Client determines the server to be requested in the following order:
+//
+// - from RequestURI if it contains full url with scheme and host;
+// - from Host header otherwise.
+//
+// The function doesn't follow redirects. Use Get* for following redirects.
+//
+// Response is ignored if resp is nil.
+//
+// ErrTimeout is returned if the response wasn't returned during
+// the given timeout.
+// Immediately returns ErrTimeout if timeout value is negative.
+//
+// ErrNoFreeConns is returned if all Client.MaxConnsPerHost connections
+// to the requested host are busy.
+//
+// It is recommended obtaining req and resp via AcquireRequest
+// and AcquireResponse in performance-critical code.
+func (c *Client) DoTimeout(req *Request, resp *Response, timeout time.Duration) error {
+ req.timeout = timeout
+ if req.timeout <= 0 {
+ return ErrTimeout
+ }
+ return c.Do(req, resp)
+}
+
+// DoDeadline performs the given request and waits for response until
+// the given deadline.
+//
+// Request must contain at least non-zero RequestURI with full url (including
+// scheme and host) or non-zero Host header + RequestURI.
+//
+// Client determines the server to be requested in the following order:
+//
+// - from RequestURI if it contains full url with scheme and host;
+// - from Host header otherwise.
+//
+// The function doesn't follow redirects. Use Get* for following redirects.
+//
+// Response is ignored if resp is nil.
+//
+// ErrTimeout is returned if the response wasn't returned until
+// the given deadline.
+// Immediately returns ErrTimeout if the deadline has already been reached.
+//
+// ErrNoFreeConns is returned if all Client.MaxConnsPerHost connections
+// to the requested host are busy.
+//
+// It is recommended obtaining req and resp via AcquireRequest
+// and AcquireResponse in performance-critical code.
+func (c *Client) DoDeadline(req *Request, resp *Response, deadline time.Time) error {
+ req.timeout = time.Until(deadline)
+ if req.timeout <= 0 {
+ return ErrTimeout
+ }
+ return c.Do(req, resp)
+}
+
+// DoRedirects performs the given http request and fills the given http response,
+// following up to maxRedirectsCount redirects. When the redirect count exceeds
+// maxRedirectsCount, ErrTooManyRedirects is returned.
+//
+// Request must contain at least non-zero RequestURI with full url (including
+// scheme and host) or non-zero Host header + RequestURI.
+//
+// Client determines the server to be requested in the following order:
+//
+// - from RequestURI if it contains full url with scheme and host;
+// - from Host header otherwise.
+//
+// Response is ignored if resp is nil.
+//
+// ErrNoFreeConns is returned if all DefaultMaxConnsPerHost connections
+// to the requested host are busy.
+//
+// It is recommended obtaining req and resp via AcquireRequest
+// and AcquireResponse in performance-critical code.
+func (c *Client) DoRedirects(req *Request, resp *Response, maxRedirectsCount int) error {
+ _, _, err := doRequestFollowRedirects(req, resp, req.URI().String(), maxRedirectsCount, c)
+ return err
+}
+
+// Do performs the given http request and fills the given http response.
+//
+// Request must contain at least non-zero RequestURI with full url (including
+// scheme and host) or non-zero Host header + RequestURI.
+//
+// Client determines the server to be requested in the following order:
+//
+// - from RequestURI if it contains full url with scheme and host;
+// - from Host header otherwise.
+//
+// Response is ignored if resp is nil.
+//
+// The function doesn't follow redirects. Use Get* for following redirects.
+//
+// ErrNoFreeConns is returned if all Client.MaxConnsPerHost connections
+// to the requested host are busy.
+//
+// It is recommended obtaining req and resp via AcquireRequest
+// and AcquireResponse in performance-critical code.
+func (c *Client) Do(req *Request, resp *Response) error {
+ uri := req.URI()
+ if uri == nil {
+ return ErrorInvalidURI
+ }
+
+ host := uri.Host()
+
+ isTLS := false
+ if uri.isHTTPS() {
+ isTLS = true
+ } else if !uri.isHTTP() {
+ return fmt.Errorf("unsupported protocol %q. http and https are supported", uri.Scheme())
+ }
+
+ c.mOnce.Do(func() {
+ c.mLock.Lock()
+ c.m = make(map[string]*HostClient)
+ c.ms = make(map[string]*HostClient)
+ c.mLock.Unlock()
+ })
+
+ startCleaner := false
+
+ c.mLock.RLock()
+ m := c.m
+ if isTLS {
+ m = c.ms
+ }
+ hc := m[string(host)]
+ if hc != nil {
+ atomic.AddInt32(&hc.pendingClientRequests, 1)
+ defer atomic.AddInt32(&hc.pendingClientRequests, -1)
+ }
+ c.mLock.RUnlock()
+ if hc == nil {
+ c.mLock.Lock()
+ hc = m[string(host)]
+ if hc == nil {
+ hc = &HostClient{
+ Addr: AddMissingPort(string(host), isTLS),
+ Name: c.Name,
+ NoDefaultUserAgentHeader: c.NoDefaultUserAgentHeader,
+ Dial: c.Dial,
+ DialDualStack: c.DialDualStack,
+ IsTLS: isTLS,
+ TLSConfig: c.TLSConfig,
+ MaxConns: c.MaxConnsPerHost,
+ MaxIdleConnDuration: c.MaxIdleConnDuration,
+ MaxConnDuration: c.MaxConnDuration,
+ MaxIdemponentCallAttempts: c.MaxIdemponentCallAttempts,
+ ReadBufferSize: c.ReadBufferSize,
+ WriteBufferSize: c.WriteBufferSize,
+ ReadTimeout: c.ReadTimeout,
+ WriteTimeout: c.WriteTimeout,
+ MaxResponseBodySize: c.MaxResponseBodySize,
+ DisableHeaderNamesNormalizing: c.DisableHeaderNamesNormalizing,
+ DisablePathNormalizing: c.DisablePathNormalizing,
+ MaxConnWaitTimeout: c.MaxConnWaitTimeout,
+ RetryIf: c.RetryIf,
+ ConnPoolStrategy: c.ConnPoolStrategy,
+ StreamResponseBody: c.StreamResponseBody,
+ clientReaderPool: &c.readerPool,
+ clientWriterPool: &c.writerPool,
+ }
+
+ if c.ConfigureClient != nil {
+ if err := c.ConfigureClient(hc); err != nil {
+ c.mLock.Unlock()
+ return err
+ }
+ }
+
+ m[string(host)] = hc
+ if len(m) == 1 {
+ startCleaner = true
+ }
+ }
+ atomic.AddInt32(&hc.pendingClientRequests, 1)
+ defer atomic.AddInt32(&hc.pendingClientRequests, -1)
+ c.mLock.Unlock()
+ }
+
+ if startCleaner {
+ go c.mCleaner(m)
+ }
+
+ return hc.Do(req, resp)
+}
+
+// CloseIdleConnections closes any connections which were previously
+// connected from previous requests but are now sitting idle in a
+// "keep-alive" state. It does not interrupt any connections currently
+// in use.
+func (c *Client) CloseIdleConnections() {
+ c.mLock.RLock()
+ for _, v := range c.m {
+ v.CloseIdleConnections()
+ }
+ for _, v := range c.ms {
+ v.CloseIdleConnections()
+ }
+ c.mLock.RUnlock()
+}
+
+func (c *Client) mCleaner(m map[string]*HostClient) {
+ mustStop := false
+
+ sleep := c.MaxIdleConnDuration
+ if sleep < time.Second {
+ sleep = time.Second
+ } else if sleep > 10*time.Second {
+ sleep = 10 * time.Second
+ }
+
+ for {
+ time.Sleep(sleep)
+ c.mLock.Lock()
+ for k, v := range m {
+ v.connsLock.Lock()
+ /* #nosec G601 */
+ if v.connsCount == 0 && atomic.LoadInt32(&v.pendingClientRequests) == 0 {
+ delete(m, k)
+ }
+ v.connsLock.Unlock()
+ }
+ if len(m) == 0 {
+ mustStop = true
+ }
+ c.mLock.Unlock()
+
+ if mustStop {
+ break
+ }
+ }
+}
+
+// DefaultMaxConnsPerHost is the maximum number of concurrent connections
+// http client may establish per host by default (i.e. if
+// Client.MaxConnsPerHost isn't set).
+const DefaultMaxConnsPerHost = 512
+
+// DefaultMaxIdleConnDuration is the default duration before idle keep-alive
+// connection is closed.
+const DefaultMaxIdleConnDuration = 10 * time.Second
+
+// DefaultMaxIdemponentCallAttempts is the default idempotent calls attempts count.
+const DefaultMaxIdemponentCallAttempts = 5
+
+// DialFunc must establish connection to addr.
+//
+// There is no need in establishing TLS (SSL) connection for https.
+// The client automatically converts connection to TLS
+// if HostClient.IsTLS is set.
+//
+// TCP address passed to DialFunc always contains host and port.
+// Example TCP addr values:
+//
+// - foobar.com:80
+// - foobar.com:443
+// - foobar.com:8080
+type DialFunc func(addr string) (net.Conn, error)
+
+// RetryIfFunc signature of retry if function
+//
+// Request argument passed to RetryIfFunc, if there are any request errors.
+type RetryIfFunc func(request *Request) bool
+
+// RoundTripper wraps every request/response.
+type RoundTripper interface {
+ RoundTrip(hc *HostClient, req *Request, resp *Response) (retry bool, err error)
+}
+
+// ConnPoolStrategyType define strategy of connection pool enqueue/dequeue
+type ConnPoolStrategyType int
+
+const (
+ FIFO ConnPoolStrategyType = iota
+ LIFO
+)
+
+// HostClient balances http requests among hosts listed in Addr.
+//
+// HostClient may be used for balancing load among multiple upstream hosts.
+// While multiple addresses passed to HostClient.Addr may be used for balancing
+// load among them, it would be better using LBClient instead, since HostClient
+// may unevenly balance load among upstream hosts.
+//
+// It is forbidden copying HostClient instances. Create new instances instead.
+//
+// It is safe calling HostClient methods from concurrently running goroutines.
+type HostClient struct {
+ noCopy noCopy
+
+ // Comma-separated list of upstream HTTP server host addresses,
+ // which are passed to Dial in a round-robin manner.
+ //
+ // Each address may contain port if default dialer is used.
+ // For example,
+ //
+ // - foobar.com:80
+ // - foobar.com:443
+ // - foobar.com:8080
+ Addr string
+
+ // Client name. Used in User-Agent request header.
+ Name string
+
+ // NoDefaultUserAgentHeader when set to true, causes the default
+ // User-Agent header to be excluded from the Request.
+ NoDefaultUserAgentHeader bool
+
+ // Callback for establishing new connection to the host.
+ //
+ // Default Dial is used if not set.
+ Dial DialFunc
+
+ // Attempt to connect to both ipv4 and ipv6 host addresses
+ // if set to true.
+ //
+ // This option is used only if default TCP dialer is used,
+ // i.e. if Dial is blank.
+ //
+ // By default client connects only to ipv4 addresses,
+ // since unfortunately ipv6 remains broken in many networks worldwide :)
+ DialDualStack bool
+
+ // Whether to use TLS (aka SSL or HTTPS) for host connections.
+ IsTLS bool
+
+ // Optional TLS config.
+ TLSConfig *tls.Config
+
+ // Maximum number of connections which may be established to all hosts
+ // listed in Addr.
+ //
+ // You can change this value while the HostClient is being used
+ // with HostClient.SetMaxConns(value)
+ //
+ // DefaultMaxConnsPerHost is used if not set.
+ MaxConns int
+
+ // Keep-alive connections are closed after this duration.
+ //
+ // By default connection duration is unlimited.
+ MaxConnDuration time.Duration
+
+ // Idle keep-alive connections are closed after this duration.
+ //
+ // By default idle connections are closed
+ // after DefaultMaxIdleConnDuration.
+ MaxIdleConnDuration time.Duration
+
+ // Maximum number of attempts for idempotent calls
+ //
+ // DefaultMaxIdemponentCallAttempts is used if not set.
+ MaxIdemponentCallAttempts int
+
+ // Per-connection buffer size for responses' reading.
+ // This also limits the maximum header size.
+ //
+ // Default buffer size is used if 0.
+ ReadBufferSize int
+
+ // Per-connection buffer size for requests' writing.
+ //
+ // Default buffer size is used if 0.
+ WriteBufferSize int
+
+ // Maximum duration for full response reading (including body).
+ //
+ // By default response read timeout is unlimited.
+ ReadTimeout time.Duration
+
+ // Maximum duration for full request writing (including body).
+ //
+ // By default request write timeout is unlimited.
+ WriteTimeout time.Duration
+
+ // Maximum response body size.
+ //
+ // The client returns ErrBodyTooLarge if this limit is greater than 0
+ // and response body is greater than the limit.
+ //
+ // By default response body size is unlimited.
+ MaxResponseBodySize int
+
+ // Header names are passed as-is without normalization
+ // if this option is set.
+ //
+ // Disabled header names' normalization may be useful only for proxying
+ // responses to other clients expecting case-sensitive
+ // header names. See https://github.com/valyala/fasthttp/issues/57
+ // for details.
+ //
+ // By default request and response header names are normalized, i.e.
+ // The first letter and the first letters following dashes
+ // are uppercased, while all the other letters are lowercased.
+ // Examples:
+ //
+ // * HOST -> Host
+ // * content-type -> Content-Type
+ // * cONTENT-lenGTH -> Content-Length
+ DisableHeaderNamesNormalizing bool
+
+ // Path values are sent as-is without normalization
+ //
+ // Disabled path normalization may be useful for proxying incoming requests
+ // to servers that are expecting paths to be forwarded as-is.
+ //
+ // By default path values are normalized, i.e.
+ // extra slashes are removed, special characters are encoded.
+ DisablePathNormalizing bool
+
+ // Will not log potentially sensitive content in error logs
+ //
+ // This option is useful for servers that handle sensitive data
+ // in the request/response.
+ //
+ // Client logs full errors by default.
+ SecureErrorLogMessage bool
+
+ // Maximum duration for waiting for a free connection.
+ //
+ // By default will not waiting, return ErrNoFreeConns immediately
+ MaxConnWaitTimeout time.Duration
+
+ // RetryIf controls whether a retry should be attempted after an error.
+ //
+ // By default will use isIdempotent function
+ RetryIf RetryIfFunc
+
+ // Transport defines a transport-like mechanism that wraps every request/response.
+ Transport RoundTripper
+
+ // Connection pool strategy. Can be either LIFO or FIFO (default).
+ ConnPoolStrategy ConnPoolStrategyType
+
+ // StreamResponseBody enables response body streaming
+ StreamResponseBody bool
+
+ lastUseTime uint32
+
+ connsLock sync.Mutex
+ connsCount int
+ conns []*clientConn
+ connsWait *wantConnQueue
+
+ addrsLock sync.Mutex
+ addrs []string
+ addrIdx uint32
+
+ tlsConfigMap map[string]*tls.Config
+ tlsConfigMapLock sync.Mutex
+
+ readerPool sync.Pool
+ writerPool sync.Pool
+
+ clientReaderPool *sync.Pool
+ clientWriterPool *sync.Pool
+
+ pendingRequests int32
+
+ // pendingClientRequests counts the number of requests that a Client is currently running using this HostClient.
+ // It will be incremented earlier than pendingRequests and will be used by Client to see if the HostClient is still in use.
+ pendingClientRequests int32
+
+ connsCleanerRun bool
+}
+
+type clientConn struct {
+ c net.Conn
+
+ createdTime time.Time
+ lastUseTime time.Time
+}
+
+var startTimeUnix = time.Now().Unix()
+
+// LastUseTime returns time the client was last used
+func (c *HostClient) LastUseTime() time.Time {
+ n := atomic.LoadUint32(&c.lastUseTime)
+ return time.Unix(startTimeUnix+int64(n), 0)
+}
+
+// Get returns the status code and body of url.
+//
+// The contents of dst will be replaced by the body and returned, if the dst
+// is too small a new slice will be allocated.
+//
+// The function follows redirects. Use Do* for manually handling redirects.
+func (c *HostClient) Get(dst []byte, url string) (statusCode int, body []byte, err error) {
+ return clientGetURL(dst, url, c)
+}
+
+// GetTimeout returns the status code and body of url.
+//
+// The contents of dst will be replaced by the body and returned, if the dst
+// is too small a new slice will be allocated.
+//
+// The function follows redirects. Use Do* for manually handling redirects.
+//
+// ErrTimeout error is returned if url contents couldn't be fetched
+// during the given timeout.
+func (c *HostClient) GetTimeout(dst []byte, url string, timeout time.Duration) (statusCode int, body []byte, err error) {
+ return clientGetURLTimeout(dst, url, timeout, c)
+}
+
+// GetDeadline returns the status code and body of url.
+//
+// The contents of dst will be replaced by the body and returned, if the dst
+// is too small a new slice will be allocated.
+//
+// The function follows redirects. Use Do* for manually handling redirects.
+//
+// ErrTimeout error is returned if url contents couldn't be fetched
+// until the given deadline.
+func (c *HostClient) GetDeadline(dst []byte, url string, deadline time.Time) (statusCode int, body []byte, err error) {
+ return clientGetURLDeadline(dst, url, deadline, c)
+}
+
+// Post sends POST request to the given url with the given POST arguments.
+//
+// The contents of dst will be replaced by the body and returned, if the dst
+// is too small a new slice will be allocated.
+//
+// The function follows redirects. Use Do* for manually handling redirects.
+//
+// Empty POST body is sent if postArgs is nil.
+func (c *HostClient) Post(dst []byte, url string, postArgs *Args) (statusCode int, body []byte, err error) {
+ return clientPostURL(dst, url, postArgs, c)
+}
+
+type clientDoer interface {
+ Do(req *Request, resp *Response) error
+}
+
+func clientGetURL(dst []byte, url string, c clientDoer) (statusCode int, body []byte, err error) {
+ req := AcquireRequest()
+
+ statusCode, body, err = doRequestFollowRedirectsBuffer(req, dst, url, c)
+
+ ReleaseRequest(req)
+ return statusCode, body, err
+}
+
+func clientGetURLTimeout(dst []byte, url string, timeout time.Duration, c clientDoer) (statusCode int, body []byte, err error) {
+ deadline := time.Now().Add(timeout)
+ return clientGetURLDeadline(dst, url, deadline, c)
+}
+
+type clientURLResponse struct {
+ statusCode int
+ body []byte
+ err error
+}
+
+func clientGetURLDeadline(dst []byte, url string, deadline time.Time, c clientDoer) (statusCode int, body []byte, err error) {
+ timeout := time.Until(deadline)
+ if timeout <= 0 {
+ return 0, dst, ErrTimeout
+ }
+
+ var ch chan clientURLResponse
+ chv := clientURLResponseChPool.Get()
+ if chv == nil {
+ chv = make(chan clientURLResponse, 1)
+ }
+ ch = chv.(chan clientURLResponse)
+
+ // Note that the request continues execution on ErrTimeout until
+ // client-specific ReadTimeout exceeds. This helps limiting load
+ // on slow hosts by MaxConns* concurrent requests.
+ //
+ // Without this 'hack' the load on slow host could exceed MaxConns*
+ // concurrent requests, since timed out requests on client side
+ // usually continue execution on the host.
+
+ var mu sync.Mutex
+ var timedout, responded bool
+
+ go func() {
+ req := AcquireRequest()
+
+ statusCodeCopy, bodyCopy, errCopy := doRequestFollowRedirectsBuffer(req, dst, url, c)
+ mu.Lock()
+ if !timedout {
+ ch <- clientURLResponse{
+ statusCode: statusCodeCopy,
+ body: bodyCopy,
+ err: errCopy,
+ }
+ responded = true
+ }
+ mu.Unlock()
+
+ ReleaseRequest(req)
+ }()
+
+ tc := AcquireTimer(timeout)
+ select {
+ case resp := <-ch:
+ statusCode = resp.statusCode
+ body = resp.body
+ err = resp.err
+ case <-tc.C:
+ mu.Lock()
+ if responded {
+ resp := <-ch
+ statusCode = resp.statusCode
+ body = resp.body
+ err = resp.err
+ } else {
+ timedout = true
+ err = ErrTimeout
+ body = dst
+ }
+ mu.Unlock()
+ }
+ ReleaseTimer(tc)
+
+ clientURLResponseChPool.Put(chv)
+
+ return statusCode, body, err
+}
+
+var clientURLResponseChPool sync.Pool
+
+func clientPostURL(dst []byte, url string, postArgs *Args, c clientDoer) (statusCode int, body []byte, err error) {
+ req := AcquireRequest()
+ defer ReleaseRequest(req)
+
+ req.Header.SetMethod(MethodPost)
+ req.Header.SetContentTypeBytes(strPostArgsContentType)
+ if postArgs != nil {
+ if _, err := postArgs.WriteTo(req.BodyWriter()); err != nil {
+ return 0, nil, err
+ }
+ }
+
+ statusCode, body, err = doRequestFollowRedirectsBuffer(req, dst, url, c)
+
+ return statusCode, body, err
+}
+
+var (
+ // ErrMissingLocation is returned by clients when the Location header is missing on
+ // an HTTP response with a redirect status code.
+ ErrMissingLocation = errors.New("missing Location header for http redirect")
+ // ErrTooManyRedirects is returned by clients when the number of redirects followed
+ // exceed the max count.
+ ErrTooManyRedirects = errors.New("too many redirects detected when doing the request")
+
+ // HostClients are only able to follow redirects to the same protocol.
+ ErrHostClientRedirectToDifferentScheme = errors.New("HostClient can't follow redirects to a different protocol, please use Client instead")
+)
+
+const defaultMaxRedirectsCount = 16
+
+func doRequestFollowRedirectsBuffer(req *Request, dst []byte, url string, c clientDoer) (statusCode int, body []byte, err error) {
+ resp := AcquireResponse()
+ bodyBuf := resp.bodyBuffer()
+ resp.keepBodyBuffer = true
+ oldBody := bodyBuf.B
+ bodyBuf.B = dst
+
+ statusCode, _, err = doRequestFollowRedirects(req, resp, url, defaultMaxRedirectsCount, c)
+
+ body = bodyBuf.B
+ bodyBuf.B = oldBody
+ resp.keepBodyBuffer = false
+ ReleaseResponse(resp)
+
+ return statusCode, body, err
+}
+
+func doRequestFollowRedirects(req *Request, resp *Response, url string, maxRedirectsCount int, c clientDoer) (statusCode int, body []byte, err error) {
+ redirectsCount := 0
+
+ for {
+ req.SetRequestURI(url)
+ if err := req.parseURI(); err != nil {
+ return 0, nil, err
+ }
+
+ if err = c.Do(req, resp); err != nil {
+ break
+ }
+ statusCode = resp.Header.StatusCode()
+ if !StatusCodeIsRedirect(statusCode) {
+ break
+ }
+
+ redirectsCount++
+ if redirectsCount > maxRedirectsCount {
+ err = ErrTooManyRedirects
+ break
+ }
+ location := resp.Header.peek(strLocation)
+ if len(location) == 0 {
+ err = ErrMissingLocation
+ break
+ }
+ url = getRedirectURL(url, location, req.DisableRedirectPathNormalizing)
+ }
+
+ return statusCode, body, err
+}
+
+func getRedirectURL(baseURL string, location []byte, disablePathNormalizing bool) string {
+ u := AcquireURI()
+ u.Update(baseURL)
+ u.UpdateBytes(location)
+ u.DisablePathNormalizing = disablePathNormalizing
+ redirectURL := u.String()
+ ReleaseURI(u)
+ return redirectURL
+}
+
+// StatusCodeIsRedirect returns true if the status code indicates a redirect.
+func StatusCodeIsRedirect(statusCode int) bool {
+ return statusCode == StatusMovedPermanently ||
+ statusCode == StatusFound ||
+ statusCode == StatusSeeOther ||
+ statusCode == StatusTemporaryRedirect ||
+ statusCode == StatusPermanentRedirect
+}
+
+var (
+ requestPool sync.Pool
+ responsePool sync.Pool
+)
+
+// AcquireRequest returns an empty Request instance from request pool.
+//
+// The returned Request instance may be passed to ReleaseRequest when it is
+// no longer needed. This allows Request recycling, reduces GC pressure
+// and usually improves performance.
+func AcquireRequest() *Request {
+ v := requestPool.Get()
+ if v == nil {
+ return &Request{}
+ }
+ return v.(*Request)
+}
+
+// ReleaseRequest returns req acquired via AcquireRequest to request pool.
+//
+// It is forbidden accessing req and/or its' members after returning
+// it to request pool.
+func ReleaseRequest(req *Request) {
+ req.Reset()
+ requestPool.Put(req)
+}
+
+// AcquireResponse returns an empty Response instance from response pool.
+//
+// The returned Response instance may be passed to ReleaseResponse when it is
+// no longer needed. This allows Response recycling, reduces GC pressure
+// and usually improves performance.
+func AcquireResponse() *Response {
+ v := responsePool.Get()
+ if v == nil {
+ return &Response{}
+ }
+ return v.(*Response)
+}
+
+// ReleaseResponse return resp acquired via AcquireResponse to response pool.
+//
+// It is forbidden accessing resp and/or its' members after returning
+// it to response pool.
+func ReleaseResponse(resp *Response) {
+ resp.Reset()
+ responsePool.Put(resp)
+}
+
+// DoTimeout performs the given request and waits for response during
+// the given timeout duration.
+//
+// Request must contain at least non-zero RequestURI with full url (including
+// scheme and host) or non-zero Host header + RequestURI.
+//
+// The function doesn't follow redirects. Use Get* for following redirects.
+//
+// Response is ignored if resp is nil.
+//
+// ErrTimeout is returned if the response wasn't returned during
+// the given timeout.
+// Immediately returns ErrTimeout if timeout value is negative.
+//
+// ErrNoFreeConns is returned if all HostClient.MaxConns connections
+// to the host are busy.
+//
+// It is recommended obtaining req and resp via AcquireRequest
+// and AcquireResponse in performance-critical code.
+func (c *HostClient) DoTimeout(req *Request, resp *Response, timeout time.Duration) error {
+ req.timeout = timeout
+ if req.timeout <= 0 {
+ return ErrTimeout
+ }
+ return c.Do(req, resp)
+}
+
+// DoDeadline performs the given request and waits for response until
+// the given deadline.
+//
+// Request must contain at least non-zero RequestURI with full url (including
+// scheme and host) or non-zero Host header + RequestURI.
+//
+// The function doesn't follow redirects. Use Get* for following redirects.
+//
+// Response is ignored if resp is nil.
+//
+// ErrTimeout is returned if the response wasn't returned until
+// the given deadline.
+// Immediately returns ErrTimeout if the deadline has already been reached.
+//
+// ErrNoFreeConns is returned if all HostClient.MaxConns connections
+// to the host are busy.
+//
+// It is recommended obtaining req and resp via AcquireRequest
+// and AcquireResponse in performance-critical code.
+func (c *HostClient) DoDeadline(req *Request, resp *Response, deadline time.Time) error {
+ req.timeout = time.Until(deadline)
+ if req.timeout <= 0 {
+ return ErrTimeout
+ }
+ return c.Do(req, resp)
+}
+
+// DoRedirects performs the given http request and fills the given http response,
+// following up to maxRedirectsCount redirects. When the redirect count exceeds
+// maxRedirectsCount, ErrTooManyRedirects is returned.
+//
+// Request must contain at least non-zero RequestURI with full url (including
+// scheme and host) or non-zero Host header + RequestURI.
+//
+// Client determines the server to be requested in the following order:
+//
+// - from RequestURI if it contains full url with scheme and host;
+// - from Host header otherwise.
+//
+// Response is ignored if resp is nil.
+//
+// ErrNoFreeConns is returned if all DefaultMaxConnsPerHost connections
+// to the requested host are busy.
+//
+// It is recommended obtaining req and resp via AcquireRequest
+// and AcquireResponse in performance-critical code.
+func (c *HostClient) DoRedirects(req *Request, resp *Response, maxRedirectsCount int) error {
+ _, _, err := doRequestFollowRedirects(req, resp, req.URI().String(), maxRedirectsCount, c)
+ return err
+}
+
+// Do performs the given http request and sets the corresponding response.
+//
+// Request must contain at least non-zero RequestURI with full url (including
+// scheme and host) or non-zero Host header + RequestURI.
+//
+// The function doesn't follow redirects. Use Get* for following redirects.
+//
+// Response is ignored if resp is nil.
+//
+// ErrNoFreeConns is returned if all HostClient.MaxConns connections
+// to the host are busy.
+//
+// It is recommended obtaining req and resp via AcquireRequest
+// and AcquireResponse in performance-critical code.
+func (c *HostClient) Do(req *Request, resp *Response) error {
+ var err error
+ var retry bool
+ maxAttempts := c.MaxIdemponentCallAttempts
+ if maxAttempts <= 0 {
+ maxAttempts = DefaultMaxIdemponentCallAttempts
+ }
+ isRequestRetryable := isIdempotent
+ if c.RetryIf != nil {
+ isRequestRetryable = c.RetryIf
+ }
+ attempts := 0
+ hasBodyStream := req.IsBodyStream()
+
+ // If a request has a timeout we store the timeout
+ // and calculate a deadline so we can keep updating the
+ // timeout on each retry.
+ deadline := time.Time{}
+ timeout := req.timeout
+ if timeout > 0 {
+ deadline = time.Now().Add(timeout)
+ }
+
+ atomic.AddInt32(&c.pendingRequests, 1)
+ for {
+ // If the original timeout was set, we need to update
+ // the one set on the request to reflect the remaining time.
+ if timeout > 0 {
+ req.timeout = time.Until(deadline)
+ if req.timeout <= 0 {
+ err = ErrTimeout
+ break
+ }
+ }
+
+ retry, err = c.do(req, resp)
+ if err == nil || !retry {
+ break
+ }
+
+ if hasBodyStream {
+ break
+ }
+ if !isRequestRetryable(req) {
+ // Retry non-idempotent requests if the server closes
+ // the connection before sending the response.
+ //
+ // This case is possible if the server closes the idle
+ // keep-alive connection on timeout.
+ //
+ // Apache and nginx usually do this.
+ if err != io.EOF {
+ break
+ }
+ }
+ attempts++
+ if attempts >= maxAttempts {
+ break
+ }
+ }
+ atomic.AddInt32(&c.pendingRequests, -1)
+
+ // Restore the original timeout.
+ req.timeout = timeout
+
+ if err == io.EOF {
+ err = ErrConnectionClosed
+ }
+ return err
+}
+
+// PendingRequests returns the current number of requests the client
+// is executing.
+//
+// This function may be used for balancing load among multiple HostClient
+// instances.
+func (c *HostClient) PendingRequests() int {
+ return int(atomic.LoadInt32(&c.pendingRequests))
+}
+
+func isIdempotent(req *Request) bool {
+ return req.Header.IsGet() || req.Header.IsHead() || req.Header.IsPut()
+}
+
+func (c *HostClient) do(req *Request, resp *Response) (bool, error) {
+ if resp == nil {
+ resp = AcquireResponse()
+ defer ReleaseResponse(resp)
+ }
+
+ ok, err := c.doNonNilReqResp(req, resp)
+
+ return ok, err
+}
+
+func (c *HostClient) doNonNilReqResp(req *Request, resp *Response) (bool, error) {
+ if req == nil {
+ // for debugging purposes
+ panic("BUG: req cannot be nil")
+ }
+ if resp == nil {
+ // for debugging purposes
+ panic("BUG: resp cannot be nil")
+ }
+
+ // Secure header error logs configuration
+ resp.secureErrorLogMessage = c.SecureErrorLogMessage
+ resp.Header.secureErrorLogMessage = c.SecureErrorLogMessage
+ req.secureErrorLogMessage = c.SecureErrorLogMessage
+ req.Header.secureErrorLogMessage = c.SecureErrorLogMessage
+
+ if c.IsTLS != req.URI().isHTTPS() {
+ return false, ErrHostClientRedirectToDifferentScheme
+ }
+
+ atomic.StoreUint32(&c.lastUseTime, uint32(time.Now().Unix()-startTimeUnix))
+
+ // Free up resources occupied by response before sending the request,
+ // so the GC may reclaim these resources (e.g. response body).
+
+ // backing up SkipBody in case it was set explicitly
+ customSkipBody := resp.SkipBody
+ customStreamBody := resp.StreamBody || c.StreamResponseBody
+ resp.Reset()
+ resp.SkipBody = customSkipBody
+ resp.StreamBody = customStreamBody
+
+ req.URI().DisablePathNormalizing = c.DisablePathNormalizing
+
+ userAgentOld := req.Header.UserAgent()
+ if len(userAgentOld) == 0 {
+ userAgent := c.Name
+ if userAgent == "" && !c.NoDefaultUserAgentHeader {
+ userAgent = defaultUserAgent
+ }
+ if userAgent != "" {
+ req.Header.userAgent = append(req.Header.userAgent[:0], userAgent...)
+ }
+ }
+
+ return c.transport().RoundTrip(c, req, resp)
+}
+
+func (c *HostClient) transport() RoundTripper {
+ if c.Transport == nil {
+ return DefaultTransport
+ }
+ return c.Transport
+}
+
+var (
+ // ErrNoFreeConns is returned when no free connections available
+ // to the given host.
+ //
+ // Increase the allowed number of connections per host if you
+ // see this error.
+ ErrNoFreeConns = errors.New("no free connections available to host")
+
+ // ErrConnectionClosed may be returned from client methods if the server
+ // closes connection before returning the first response byte.
+ //
+ // If you see this error, then either fix the server by returning
+ // 'Connection: close' response header before closing the connection
+ // or add 'Connection: close' request header before sending requests
+ // to broken server.
+ ErrConnectionClosed = errors.New("the server closed connection before returning the first response byte. " +
+ "Make sure the server returns 'Connection: close' response header before closing the connection")
+
+ // ErrConnPoolStrategyNotImpl is returned when HostClient.ConnPoolStrategy is not implement yet.
+ // If you see this error, then you need to check your HostClient configuration.
+ ErrConnPoolStrategyNotImpl = errors.New("connection pool strategy is not implement")
+)
+
+type timeoutError struct{}
+
+func (e *timeoutError) Error() string {
+ return "timeout"
+}
+
+// Only implement the Timeout() function of the net.Error interface.
+// This allows for checks like:
+//
+// if x, ok := err.(interface{ Timeout() bool }); ok && x.Timeout() {
+func (e *timeoutError) Timeout() bool {
+ return true
+}
+
+// ErrTimeout is returned from timed out calls.
+var ErrTimeout = &timeoutError{}
+
+// SetMaxConns sets up the maximum number of connections which may be established to all hosts listed in Addr.
+func (c *HostClient) SetMaxConns(newMaxConns int) {
+ c.connsLock.Lock()
+ c.MaxConns = newMaxConns
+ c.connsLock.Unlock()
+}
+
+func (c *HostClient) acquireConn(reqTimeout time.Duration, connectionClose bool) (cc *clientConn, err error) {
+ createConn := false
+ startCleaner := false
+
+ var n int
+ c.connsLock.Lock()
+ n = len(c.conns)
+ if n == 0 {
+ maxConns := c.MaxConns
+ if maxConns <= 0 {
+ maxConns = DefaultMaxConnsPerHost
+ }
+ if c.connsCount < maxConns {
+ c.connsCount++
+ createConn = true
+ if !c.connsCleanerRun && !connectionClose {
+ startCleaner = true
+ c.connsCleanerRun = true
+ }
+ }
+ } else {
+ switch c.ConnPoolStrategy {
+ case LIFO:
+ n--
+ cc = c.conns[n]
+ c.conns[n] = nil
+ c.conns = c.conns[:n]
+ case FIFO:
+ cc = c.conns[0]
+ copy(c.conns, c.conns[1:])
+ c.conns[n-1] = nil
+ c.conns = c.conns[:n-1]
+ default:
+ c.connsLock.Unlock()
+ return nil, ErrConnPoolStrategyNotImpl
+ }
+ }
+ c.connsLock.Unlock()
+
+ if cc != nil {
+ return cc, nil
+ }
+ if !createConn {
+ if c.MaxConnWaitTimeout <= 0 {
+ return nil, ErrNoFreeConns
+ }
+
+ //nolint:dupword
+ // reqTimeout c.MaxConnWaitTimeout wait duration
+ // d1 d2 min(d1, d2)
+ // 0(not set) d2 d2
+ // d1 0(don't wait) 0(don't wait)
+ // 0(not set) d2 d2
+ timeout := c.MaxConnWaitTimeout
+ timeoutOverridden := false
+ // reqTimeout == 0 means not set
+ if reqTimeout > 0 && reqTimeout < timeout {
+ timeout = reqTimeout
+ timeoutOverridden = true
+ }
+
+ // wait for a free connection
+ tc := AcquireTimer(timeout)
+ defer ReleaseTimer(tc)
+
+ w := &wantConn{
+ ready: make(chan struct{}, 1),
+ }
+ defer func() {
+ if err != nil {
+ w.cancel(c, err)
+ }
+ }()
+
+ c.queueForIdle(w)
+
+ select {
+ case <-w.ready:
+ return w.conn, w.err
+ case <-tc.C:
+ if timeoutOverridden {
+ return nil, ErrTimeout
+ }
+ return nil, ErrNoFreeConns
+ }
+ }
+
+ if startCleaner {
+ go c.connsCleaner()
+ }
+
+ conn, err := c.dialHostHard(reqTimeout)
+ if err != nil {
+ c.decConnsCount()
+ return nil, err
+ }
+ cc = acquireClientConn(conn)
+
+ return cc, nil
+}
+
+func (c *HostClient) queueForIdle(w *wantConn) {
+ c.connsLock.Lock()
+ defer c.connsLock.Unlock()
+ if c.connsWait == nil {
+ c.connsWait = &wantConnQueue{}
+ }
+ c.connsWait.clearFront()
+ c.connsWait.pushBack(w)
+}
+
+func (c *HostClient) dialConnFor(w *wantConn) {
+ conn, err := c.dialHostHard(0)
+ if err != nil {
+ w.tryDeliver(nil, err)
+ c.decConnsCount()
+ return
+ }
+
+ cc := acquireClientConn(conn)
+ if !w.tryDeliver(cc, nil) {
+ // not delivered, return idle connection
+ c.releaseConn(cc)
+ }
+}
+
+// CloseIdleConnections closes any connections which were previously
+// connected from previous requests but are now sitting idle in a
+// "keep-alive" state. It does not interrupt any connections currently
+// in use.
+func (c *HostClient) CloseIdleConnections() {
+ c.connsLock.Lock()
+ scratch := append([]*clientConn{}, c.conns...)
+ for i := range c.conns {
+ c.conns[i] = nil
+ }
+ c.conns = c.conns[:0]
+ c.connsLock.Unlock()
+
+ for _, cc := range scratch {
+ c.closeConn(cc)
+ }
+}
+
+func (c *HostClient) connsCleaner() {
+ var (
+ scratch []*clientConn
+ maxIdleConnDuration = c.MaxIdleConnDuration
+ )
+ if maxIdleConnDuration <= 0 {
+ maxIdleConnDuration = DefaultMaxIdleConnDuration
+ }
+ for {
+ currentTime := time.Now()
+
+ // Determine idle connections to be closed.
+ c.connsLock.Lock()
+ conns := c.conns
+ n := len(conns)
+ i := 0
+ for i < n && currentTime.Sub(conns[i].lastUseTime) > maxIdleConnDuration {
+ i++
+ }
+ sleepFor := maxIdleConnDuration
+ if i < n {
+ // + 1 so we actually sleep past the expiration time and not up to it.
+ // Otherwise the > check above would still fail.
+ sleepFor = maxIdleConnDuration - currentTime.Sub(conns[i].lastUseTime) + 1
+ }
+ scratch = append(scratch[:0], conns[:i]...)
+ if i > 0 {
+ m := copy(conns, conns[i:])
+ for i = m; i < n; i++ {
+ conns[i] = nil
+ }
+ c.conns = conns[:m]
+ }
+ c.connsLock.Unlock()
+
+ // Close idle connections.
+ for i, cc := range scratch {
+ c.closeConn(cc)
+ scratch[i] = nil
+ }
+
+ // Determine whether to stop the connsCleaner.
+ c.connsLock.Lock()
+ mustStop := c.connsCount == 0
+ if mustStop {
+ c.connsCleanerRun = false
+ }
+ c.connsLock.Unlock()
+ if mustStop {
+ break
+ }
+
+ time.Sleep(sleepFor)
+ }
+}
+
+func (c *HostClient) closeConn(cc *clientConn) {
+ c.decConnsCount()
+ cc.c.Close()
+ releaseClientConn(cc)
+}
+
+func (c *HostClient) decConnsCount() {
+ if c.MaxConnWaitTimeout <= 0 {
+ c.connsLock.Lock()
+ c.connsCount--
+ c.connsLock.Unlock()
+ return
+ }
+
+ c.connsLock.Lock()
+ defer c.connsLock.Unlock()
+ dialed := false
+ if q := c.connsWait; q != nil && q.len() > 0 {
+ for q.len() > 0 {
+ w := q.popFront()
+ if w.waiting() {
+ go c.dialConnFor(w)
+ dialed = true
+ break
+ }
+ }
+ }
+ if !dialed {
+ c.connsCount--
+ }
+}
+
+// ConnsCount returns connection count of HostClient
+func (c *HostClient) ConnsCount() int {
+ c.connsLock.Lock()
+ defer c.connsLock.Unlock()
+
+ return c.connsCount
+}
+
+func acquireClientConn(conn net.Conn) *clientConn {
+ v := clientConnPool.Get()
+ if v == nil {
+ v = &clientConn{}
+ }
+ cc := v.(*clientConn)
+ cc.c = conn
+ cc.createdTime = time.Now()
+ return cc
+}
+
+func releaseClientConn(cc *clientConn) {
+ // Reset all fields.
+ *cc = clientConn{}
+ clientConnPool.Put(cc)
+}
+
+var clientConnPool sync.Pool
+
+func (c *HostClient) releaseConn(cc *clientConn) {
+ cc.lastUseTime = time.Now()
+ if c.MaxConnWaitTimeout <= 0 {
+ c.connsLock.Lock()
+ c.conns = append(c.conns, cc)
+ c.connsLock.Unlock()
+ return
+ }
+
+ // try to deliver an idle connection to a *wantConn
+ c.connsLock.Lock()
+ defer c.connsLock.Unlock()
+ delivered := false
+ if q := c.connsWait; q != nil && q.len() > 0 {
+ for q.len() > 0 {
+ w := q.popFront()
+ if w.waiting() {
+ delivered = w.tryDeliver(cc, nil)
+ break
+ }
+ }
+ }
+ if !delivered {
+ c.conns = append(c.conns, cc)
+ }
+}
+
+func (c *HostClient) acquireWriter(conn net.Conn) *bufio.Writer {
+ var v interface{}
+ if c.clientWriterPool != nil {
+ v = c.clientWriterPool.Get()
+ if v == nil {
+ n := c.WriteBufferSize
+ if n <= 0 {
+ n = defaultWriteBufferSize
+ }
+ return bufio.NewWriterSize(conn, n)
+ }
+ } else {
+ v = c.writerPool.Get()
+ if v == nil {
+ n := c.WriteBufferSize
+ if n <= 0 {
+ n = defaultWriteBufferSize
+ }
+ return bufio.NewWriterSize(conn, n)
+ }
+ }
+
+ bw := v.(*bufio.Writer)
+ bw.Reset(conn)
+ return bw
+}
+
+func (c *HostClient) releaseWriter(bw *bufio.Writer) {
+ if c.clientWriterPool != nil {
+ c.clientWriterPool.Put(bw)
+ } else {
+ c.writerPool.Put(bw)
+ }
+}
+
+func (c *HostClient) acquireReader(conn net.Conn) *bufio.Reader {
+ var v interface{}
+ if c.clientReaderPool != nil {
+ v = c.clientReaderPool.Get()
+ if v == nil {
+ n := c.ReadBufferSize
+ if n <= 0 {
+ n = defaultReadBufferSize
+ }
+ return bufio.NewReaderSize(conn, n)
+ }
+ } else {
+ v = c.readerPool.Get()
+ if v == nil {
+ n := c.ReadBufferSize
+ if n <= 0 {
+ n = defaultReadBufferSize
+ }
+ return bufio.NewReaderSize(conn, n)
+ }
+ }
+
+ br := v.(*bufio.Reader)
+ br.Reset(conn)
+ return br
+}
+
+func (c *HostClient) releaseReader(br *bufio.Reader) {
+ if c.clientReaderPool != nil {
+ c.clientReaderPool.Put(br)
+ } else {
+ c.readerPool.Put(br)
+ }
+}
+
+func newClientTLSConfig(c *tls.Config, addr string) *tls.Config {
+ if c == nil {
+ c = &tls.Config{}
+ } else {
+ c = c.Clone()
+ }
+
+ if len(c.ServerName) == 0 {
+ serverName := tlsServerName(addr)
+ if serverName == "*" {
+ c.InsecureSkipVerify = true
+ } else {
+ c.ServerName = serverName
+ }
+ }
+ return c
+}
+
+func tlsServerName(addr string) string {
+ if !strings.Contains(addr, ":") {
+ return addr
+ }
+ host, _, err := net.SplitHostPort(addr)
+ if err != nil {
+ return "*"
+ }
+ return host
+}
+
+func (c *HostClient) nextAddr() string {
+ c.addrsLock.Lock()
+ if c.addrs == nil {
+ c.addrs = strings.Split(c.Addr, ",")
+ }
+ addr := c.addrs[0]
+ if len(c.addrs) > 1 {
+ addr = c.addrs[c.addrIdx%uint32(len(c.addrs))]
+ c.addrIdx++
+ }
+ c.addrsLock.Unlock()
+ return addr
+}
+
+func (c *HostClient) dialHostHard(dialTimeout time.Duration) (conn net.Conn, err error) {
+ // use dialTimeout to control the timeout of each dial. It does not work if dialTimeout is 0 or dial has been set.
+ // attempt to dial all the available hosts before giving up.
+
+ c.addrsLock.Lock()
+ n := len(c.addrs)
+ c.addrsLock.Unlock()
+
+ if n == 0 {
+ // It looks like c.addrs isn't initialized yet.
+ n = 1
+ }
+
+ dial := c.Dial
+ if dialTimeout != 0 && dial == nil {
+ dial = func(addr string) (net.Conn, error) {
+ if c.DialDualStack {
+ return DialDualStackTimeout(addr, dialTimeout)
+ }
+ return DialTimeout(addr, dialTimeout)
+ }
+ }
+
+ timeout := c.ReadTimeout + c.WriteTimeout
+ if timeout <= 0 {
+ timeout = DefaultDialTimeout
+ }
+ deadline := time.Now().Add(timeout)
+ for n > 0 {
+ addr := c.nextAddr()
+ tlsConfig := c.cachedTLSConfig(addr)
+ conn, err = dialAddr(addr, dial, c.DialDualStack, c.IsTLS, tlsConfig, c.WriteTimeout)
+ if err == nil {
+ return conn, nil
+ }
+ if time.Since(deadline) >= 0 {
+ break
+ }
+ n--
+ }
+ return nil, err
+}
+
+func (c *HostClient) cachedTLSConfig(addr string) *tls.Config {
+ if !c.IsTLS {
+ return nil
+ }
+
+ c.tlsConfigMapLock.Lock()
+ if c.tlsConfigMap == nil {
+ c.tlsConfigMap = make(map[string]*tls.Config)
+ }
+ cfg := c.tlsConfigMap[addr]
+ if cfg == nil {
+ cfg = newClientTLSConfig(c.TLSConfig, addr)
+ c.tlsConfigMap[addr] = cfg
+ }
+ c.tlsConfigMapLock.Unlock()
+
+ return cfg
+}
+
+// ErrTLSHandshakeTimeout indicates there is a timeout from tls handshake.
+var ErrTLSHandshakeTimeout = errors.New("tls handshake timed out")
+
+func tlsClientHandshake(rawConn net.Conn, tlsConfig *tls.Config, deadline time.Time) (_ net.Conn, retErr error) {
+ defer func() {
+ if retErr != nil {
+ rawConn.Close()
+ }
+ }()
+ conn := tls.Client(rawConn, tlsConfig)
+ err := conn.SetDeadline(deadline)
+ if err != nil {
+ return nil, err
+ }
+ err = conn.Handshake()
+ if netErr, ok := err.(net.Error); ok && netErr.Timeout() {
+ return nil, ErrTLSHandshakeTimeout
+ }
+ if err != nil {
+ return nil, err
+ }
+ err = conn.SetDeadline(time.Time{})
+ if err != nil {
+ return nil, err
+ }
+ return conn, nil
+}
+
+func dialAddr(addr string, dial DialFunc, dialDualStack, isTLS bool, tlsConfig *tls.Config, timeout time.Duration) (net.Conn, error) {
+ deadline := time.Now().Add(timeout)
+ if dial == nil {
+ if dialDualStack {
+ dial = DialDualStack
+ } else {
+ dial = Dial
+ }
+ addr = AddMissingPort(addr, isTLS)
+ }
+ conn, err := dial(addr)
+ if err != nil {
+ return nil, err
+ }
+ if conn == nil {
+ return nil, errors.New("dialling unsuccessful. Please report this bug!")
+ }
+
+ // We assume that any conn that has the Handshake() method is a TLS conn already.
+ // This doesn't cover just tls.Conn but also other TLS implementations.
+ _, isTLSAlready := conn.(interface{ Handshake() error })
+
+ if isTLS && !isTLSAlready {
+ if timeout == 0 {
+ return tls.Client(conn, tlsConfig), nil
+ }
+ return tlsClientHandshake(conn, tlsConfig, deadline)
+ }
+ return conn, nil
+}
+
+// AddMissingPort adds a port to a host if it is missing.
+// A literal IPv6 address in hostport must be enclosed in square
+// brackets, as in "[::1]:80", "[::1%lo0]:80".
+func AddMissingPort(addr string, isTLS bool) string {
+ addrLen := len(addr)
+ if addrLen == 0 {
+ return addr
+ }
+
+ isIP6 := addr[0] == '['
+ if isIP6 {
+ // if the IPv6 has opening bracket but closing bracket is the last char then it doesn't have a port
+ isIP6WithoutPort := addr[addrLen-1] == ']'
+ if !isIP6WithoutPort {
+ return addr
+ }
+ } else { // IPv4
+ columnPos := strings.LastIndexByte(addr, ':')
+ if columnPos > 0 {
+ return addr
+ }
+ }
+ port := ":80"
+ if isTLS {
+ port = ":443"
+ }
+ return addr + port
+}
+
+// A wantConn records state about a wanted connection
+// (that is, an active call to getConn).
+// The conn may be gotten by dialing or by finding an idle connection,
+// or a cancellation may make the conn no longer wanted.
+// These three options are racing against each other and use
+// wantConn to coordinate and agree about the winning outcome.
+//
+// inspired by net/http/transport.go
+type wantConn struct {
+ ready chan struct{}
+ mu sync.Mutex // protects conn, err, close(ready)
+ conn *clientConn
+ err error
+}
+
+// waiting reports whether w is still waiting for an answer (connection or error).
+func (w *wantConn) waiting() bool {
+ select {
+ case <-w.ready:
+ return false
+ default:
+ return true
+ }
+}
+
+// tryDeliver attempts to deliver conn, err to w and reports whether it succeeded.
+func (w *wantConn) tryDeliver(conn *clientConn, err error) bool {
+ w.mu.Lock()
+ defer w.mu.Unlock()
+
+ if w.conn != nil || w.err != nil {
+ return false
+ }
+ w.conn = conn
+ w.err = err
+ if w.conn == nil && w.err == nil {
+ panic("fasthttp: internal error: misuse of tryDeliver")
+ }
+ close(w.ready)
+ return true
+}
+
+// cancel marks w as no longer wanting a result (for example, due to cancellation).
+// If a connection has been delivered already, cancel returns it with c.releaseConn.
+func (w *wantConn) cancel(c *HostClient, err error) {
+ w.mu.Lock()
+ if w.conn == nil && w.err == nil {
+ close(w.ready) // catch misbehavior in future delivery
+ }
+
+ conn := w.conn
+ w.conn = nil
+ w.err = err
+ w.mu.Unlock()
+
+ if conn != nil {
+ c.releaseConn(conn)
+ }
+}
+
+// A wantConnQueue is a queue of wantConns.
+//
+// inspired by net/http/transport.go
+type wantConnQueue struct {
+ // This is a queue, not a dequeue.
+ // It is split into two stages - head[headPos:] and tail.
+ // popFront is trivial (headPos++) on the first stage, and
+ // pushBack is trivial (append) on the second stage.
+ // If the first stage is empty, popFront can swap the
+ // first and second stages to remedy the situation.
+ //
+ // This two-stage split is analogous to the use of two lists
+ // in Okasaki's purely functional queue but without the
+ // overhead of reversing the list when swapping stages.
+ head []*wantConn
+ headPos int
+ tail []*wantConn
+}
+
+// len returns the number of items in the queue.
+func (q *wantConnQueue) len() int {
+ return len(q.head) - q.headPos + len(q.tail)
+}
+
+// pushBack adds w to the back of the queue.
+func (q *wantConnQueue) pushBack(w *wantConn) {
+ q.tail = append(q.tail, w)
+}
+
+// popFront removes and returns the wantConn at the front of the queue.
+func (q *wantConnQueue) popFront() *wantConn {
+ if q.headPos >= len(q.head) {
+ if len(q.tail) == 0 {
+ return nil
+ }
+ // Pick up tail as new head, clear tail.
+ q.head, q.headPos, q.tail = q.tail, 0, q.head[:0]
+ }
+
+ w := q.head[q.headPos]
+ q.head[q.headPos] = nil
+ q.headPos++
+ return w
+}
+
+// peekFront returns the wantConn at the front of the queue without removing it.
+func (q *wantConnQueue) peekFront() *wantConn {
+ if q.headPos < len(q.head) {
+ return q.head[q.headPos]
+ }
+ if len(q.tail) > 0 {
+ return q.tail[0]
+ }
+ return nil
+}
+
+// clearFront pops any wantConns that are no longer waiting from the head of the
+// queue, reporting whether any were popped.
+func (q *wantConnQueue) clearFront() (cleaned bool) {
+ for {
+ w := q.peekFront()
+ if w == nil || w.waiting() {
+ return cleaned
+ }
+ q.popFront()
+ cleaned = true
+ }
+}
+
+// PipelineClient pipelines requests over a limited set of concurrent
+// connections to the given Addr.
+//
+// This client may be used in highly loaded HTTP-based RPC systems for reducing
+// context switches and network level overhead.
+// See https://en.wikipedia.org/wiki/HTTP_pipelining for details.
+//
+// It is forbidden copying PipelineClient instances. Create new instances
+// instead.
+//
+// It is safe calling PipelineClient methods from concurrently running
+// goroutines.
+type PipelineClient struct {
+ noCopy noCopy
+
+ // Address of the host to connect to.
+ Addr string
+
+ // PipelineClient name. Used in User-Agent request header.
+ Name string
+
+ // NoDefaultUserAgentHeader when set to true, causes the default
+ // User-Agent header to be excluded from the Request.
+ NoDefaultUserAgentHeader bool
+
+ // The maximum number of concurrent connections to the Addr.
+ //
+ // A single connection is used by default.
+ MaxConns int
+
+ // The maximum number of pending pipelined requests over
+ // a single connection to Addr.
+ //
+ // DefaultMaxPendingRequests is used by default.
+ MaxPendingRequests int
+
+ // The maximum delay before sending pipelined requests as a batch
+ // to the server.
+ //
+ // By default requests are sent immediately to the server.
+ MaxBatchDelay time.Duration
+
+ // Callback for connection establishing to the host.
+ //
+ // Default Dial is used if not set.
+ Dial DialFunc
+
+ // Attempt to connect to both ipv4 and ipv6 host addresses
+ // if set to true.
+ //
+ // This option is used only if default TCP dialer is used,
+ // i.e. if Dial is blank.
+ //
+ // By default client connects only to ipv4 addresses,
+ // since unfortunately ipv6 remains broken in many networks worldwide :)
+ DialDualStack bool
+
+ // Response header names are passed as-is without normalization
+ // if this option is set.
+ //
+ // Disabled header names' normalization may be useful only for proxying
+ // responses to other clients expecting case-sensitive
+ // header names. See https://github.com/valyala/fasthttp/issues/57
+ // for details.
+ //
+ // By default request and response header names are normalized, i.e.
+ // The first letter and the first letters following dashes
+ // are uppercased, while all the other letters are lowercased.
+ // Examples:
+ //
+ // * HOST -> Host
+ // * content-type -> Content-Type
+ // * cONTENT-lenGTH -> Content-Length
+ DisableHeaderNamesNormalizing bool
+
+ // Path values are sent as-is without normalization
+ //
+ // Disabled path normalization may be useful for proxying incoming requests
+ // to servers that are expecting paths to be forwarded as-is.
+ //
+ // By default path values are normalized, i.e.
+ // extra slashes are removed, special characters are encoded.
+ DisablePathNormalizing bool
+
+ // Whether to use TLS (aka SSL or HTTPS) for host connections.
+ IsTLS bool
+
+ // Optional TLS config.
+ TLSConfig *tls.Config
+
+ // Idle connection to the host is closed after this duration.
+ //
+ // By default idle connection is closed after
+ // DefaultMaxIdleConnDuration.
+ MaxIdleConnDuration time.Duration
+
+ // Buffer size for responses' reading.
+ // This also limits the maximum header size.
+ //
+ // Default buffer size is used if 0.
+ ReadBufferSize int
+
+ // Buffer size for requests' writing.
+ //
+ // Default buffer size is used if 0.
+ WriteBufferSize int
+
+ // Maximum duration for full response reading (including body).
+ //
+ // By default response read timeout is unlimited.
+ ReadTimeout time.Duration
+
+ // Maximum duration for full request writing (including body).
+ //
+ // By default request write timeout is unlimited.
+ WriteTimeout time.Duration
+
+ // Logger for logging client errors.
+ //
+ // By default standard logger from log package is used.
+ Logger Logger
+
+ connClients []*pipelineConnClient
+ connClientsLock sync.Mutex
+}
+
+type pipelineConnClient struct {
+ noCopy noCopy
+
+ Addr string
+ Name string
+ NoDefaultUserAgentHeader bool
+ MaxPendingRequests int
+ MaxBatchDelay time.Duration
+ Dial DialFunc
+ DialDualStack bool
+ DisableHeaderNamesNormalizing bool
+ DisablePathNormalizing bool
+ IsTLS bool
+ TLSConfig *tls.Config
+ MaxIdleConnDuration time.Duration
+ ReadBufferSize int
+ WriteBufferSize int
+ ReadTimeout time.Duration
+ WriteTimeout time.Duration
+ Logger Logger
+
+ workPool sync.Pool
+
+ chLock sync.Mutex
+ chW chan *pipelineWork
+ chR chan *pipelineWork
+
+ tlsConfigLock sync.Mutex
+ tlsConfig *tls.Config
+}
+
+type pipelineWork struct {
+ reqCopy Request
+ respCopy Response
+ req *Request
+ resp *Response
+ t *time.Timer
+ deadline time.Time
+ err error
+ done chan struct{}
+}
+
+// DoTimeout performs the given request and waits for response during
+// the given timeout duration.
+//
+// Request must contain at least non-zero RequestURI with full url (including
+// scheme and host) or non-zero Host header + RequestURI.
+//
+// The function doesn't follow redirects.
+//
+// Response is ignored if resp is nil.
+//
+// ErrTimeout is returned if the response wasn't returned during
+// the given timeout.
+//
+// It is recommended obtaining req and resp via AcquireRequest
+// and AcquireResponse in performance-critical code.
+func (c *PipelineClient) DoTimeout(req *Request, resp *Response, timeout time.Duration) error {
+ return c.DoDeadline(req, resp, time.Now().Add(timeout))
+}
+
+// DoDeadline performs the given request and waits for response until
+// the given deadline.
+//
+// Request must contain at least non-zero RequestURI with full url (including
+// scheme and host) or non-zero Host header + RequestURI.
+//
+// The function doesn't follow redirects.
+//
+// Response is ignored if resp is nil.
+//
+// ErrTimeout is returned if the response wasn't returned until
+// the given deadline.
+//
+// It is recommended obtaining req and resp via AcquireRequest
+// and AcquireResponse in performance-critical code.
+func (c *PipelineClient) DoDeadline(req *Request, resp *Response, deadline time.Time) error {
+ return c.getConnClient().DoDeadline(req, resp, deadline)
+}
+
+func (c *pipelineConnClient) DoDeadline(req *Request, resp *Response, deadline time.Time) error {
+ c.init()
+
+ timeout := time.Until(deadline)
+ if timeout <= 0 {
+ return ErrTimeout
+ }
+
+ if c.DisablePathNormalizing {
+ req.URI().DisablePathNormalizing = true
+ }
+
+ userAgentOld := req.Header.UserAgent()
+ if len(userAgentOld) == 0 {
+ userAgent := c.Name
+ if userAgent == "" && !c.NoDefaultUserAgentHeader {
+ userAgent = defaultUserAgent
+ }
+ if userAgent != "" {
+ req.Header.userAgent = append(req.Header.userAgent[:0], userAgent...)
+ }
+ }
+
+ w := c.acquirePipelineWork(timeout)
+ w.respCopy.Header.disableNormalizing = c.DisableHeaderNamesNormalizing
+ w.req = &w.reqCopy
+ w.resp = &w.respCopy
+
+ // Make a copy of the request in order to avoid data races on timeouts
+ req.copyToSkipBody(&w.reqCopy)
+ swapRequestBody(req, &w.reqCopy)
+
+ // Put the request to outgoing queue
+ select {
+ case c.chW <- w:
+ // Fast path: len(c.ch) < cap(c.ch)
+ default:
+ // Slow path
+ select {
+ case c.chW <- w:
+ case <-w.t.C:
+ c.releasePipelineWork(w)
+ return ErrTimeout
+ }
+ }
+
+ // Wait for the response
+ var err error
+ select {
+ case <-w.done:
+ if resp != nil {
+ w.respCopy.copyToSkipBody(resp)
+ swapResponseBody(resp, &w.respCopy)
+ }
+ err = w.err
+ c.releasePipelineWork(w)
+ case <-w.t.C:
+ err = ErrTimeout
+ }
+
+ return err
+}
+
+func (c *pipelineConnClient) acquirePipelineWork(timeout time.Duration) (w *pipelineWork) {
+ v := c.workPool.Get()
+ if v != nil {
+ w = v.(*pipelineWork)
+ } else {
+ w = &pipelineWork{
+ done: make(chan struct{}, 1),
+ }
+ }
+ if timeout > 0 {
+ if w.t == nil {
+ w.t = time.NewTimer(timeout)
+ } else {
+ w.t.Reset(timeout)
+ }
+ w.deadline = time.Now().Add(timeout)
+ } else {
+ w.deadline = zeroTime
+ }
+ return w
+}
+
+func (c *pipelineConnClient) releasePipelineWork(w *pipelineWork) {
+ if w.t != nil {
+ w.t.Stop()
+ }
+ w.reqCopy.Reset()
+ w.respCopy.Reset()
+ w.req = nil
+ w.resp = nil
+ w.err = nil
+ c.workPool.Put(w)
+}
+
+// Do performs the given http request and sets the corresponding response.
+//
+// Request must contain at least non-zero RequestURI with full url (including
+// scheme and host) or non-zero Host header + RequestURI.
+//
+// The function doesn't follow redirects. Use Get* for following redirects.
+//
+// Response is ignored if resp is nil.
+//
+// It is recommended obtaining req and resp via AcquireRequest
+// and AcquireResponse in performance-critical code.
+func (c *PipelineClient) Do(req *Request, resp *Response) error {
+ return c.getConnClient().Do(req, resp)
+}
+
+func (c *pipelineConnClient) Do(req *Request, resp *Response) error {
+ c.init()
+
+ if c.DisablePathNormalizing {
+ req.URI().DisablePathNormalizing = true
+ }
+
+ userAgentOld := req.Header.UserAgent()
+ if len(userAgentOld) == 0 {
+ userAgent := c.Name
+ if userAgent == "" && !c.NoDefaultUserAgentHeader {
+ userAgent = defaultUserAgent
+ }
+ if userAgent != "" {
+ req.Header.userAgent = append(req.Header.userAgent[:0], userAgent...)
+ }
+ }
+
+ w := c.acquirePipelineWork(0)
+ w.req = req
+ if resp != nil {
+ resp.Header.disableNormalizing = c.DisableHeaderNamesNormalizing
+ w.resp = resp
+ } else {
+ w.resp = &w.respCopy
+ }
+
+ // Put the request to outgoing queue
+ select {
+ case c.chW <- w:
+ default:
+ // Try substituting the oldest w with the current one.
+ select {
+ case wOld := <-c.chW:
+ wOld.err = ErrPipelineOverflow
+ wOld.done <- struct{}{}
+ default:
+ }
+ select {
+ case c.chW <- w:
+ default:
+ c.releasePipelineWork(w)
+ return ErrPipelineOverflow
+ }
+ }
+
+ // Wait for the response
+ <-w.done
+ err := w.err
+
+ c.releasePipelineWork(w)
+
+ return err
+}
+
+func (c *PipelineClient) getConnClient() *pipelineConnClient {
+ c.connClientsLock.Lock()
+ cc := c.getConnClientUnlocked()
+ c.connClientsLock.Unlock()
+ return cc
+}
+
+func (c *PipelineClient) getConnClientUnlocked() *pipelineConnClient {
+ if len(c.connClients) == 0 {
+ return c.newConnClient()
+ }
+
+ // Return the client with the minimum number of pending requests.
+ minCC := c.connClients[0]
+ minReqs := minCC.PendingRequests()
+ if minReqs == 0 {
+ return minCC
+ }
+ for i := 1; i < len(c.connClients); i++ {
+ cc := c.connClients[i]
+ reqs := cc.PendingRequests()
+ if reqs == 0 {
+ return cc
+ }
+ if reqs < minReqs {
+ minCC = cc
+ minReqs = reqs
+ }
+ }
+
+ maxConns := c.MaxConns
+ if maxConns <= 0 {
+ maxConns = 1
+ }
+ if len(c.connClients) < maxConns {
+ return c.newConnClient()
+ }
+ return minCC
+}
+
+func (c *PipelineClient) newConnClient() *pipelineConnClient {
+ cc := &pipelineConnClient{
+ Addr: c.Addr,
+ Name: c.Name,
+ NoDefaultUserAgentHeader: c.NoDefaultUserAgentHeader,
+ MaxPendingRequests: c.MaxPendingRequests,
+ MaxBatchDelay: c.MaxBatchDelay,
+ Dial: c.Dial,
+ DialDualStack: c.DialDualStack,
+ DisableHeaderNamesNormalizing: c.DisableHeaderNamesNormalizing,
+ DisablePathNormalizing: c.DisablePathNormalizing,
+ IsTLS: c.IsTLS,
+ TLSConfig: c.TLSConfig,
+ MaxIdleConnDuration: c.MaxIdleConnDuration,
+ ReadBufferSize: c.ReadBufferSize,
+ WriteBufferSize: c.WriteBufferSize,
+ ReadTimeout: c.ReadTimeout,
+ WriteTimeout: c.WriteTimeout,
+ Logger: c.Logger,
+ }
+ c.connClients = append(c.connClients, cc)
+ return cc
+}
+
+// ErrPipelineOverflow may be returned from PipelineClient.Do*
+// if the requests' queue is overflowed.
+var ErrPipelineOverflow = errors.New("pipelined requests' queue has been overflowed. Increase MaxConns and/or MaxPendingRequests")
+
+// DefaultMaxPendingRequests is the default value
+// for PipelineClient.MaxPendingRequests.
+const DefaultMaxPendingRequests = 1024
+
+func (c *pipelineConnClient) init() {
+ c.chLock.Lock()
+ if c.chR == nil {
+ maxPendingRequests := c.MaxPendingRequests
+ if maxPendingRequests <= 0 {
+ maxPendingRequests = DefaultMaxPendingRequests
+ }
+ c.chR = make(chan *pipelineWork, maxPendingRequests)
+ if c.chW == nil {
+ c.chW = make(chan *pipelineWork, maxPendingRequests)
+ }
+ go func() {
+ // Keep restarting the worker if it fails (connection errors for example).
+ for {
+ if err := c.worker(); err != nil {
+ c.logger().Printf("error in PipelineClient(%q): %v", c.Addr, err)
+ if netErr, ok := err.(net.Error); ok && netErr.Timeout() {
+ // Throttle client reconnections on timeout errors
+ time.Sleep(time.Second)
+ }
+ } else {
+ c.chLock.Lock()
+ stop := len(c.chR) == 0 && len(c.chW) == 0
+ if !stop {
+ c.chR = nil
+ c.chW = nil
+ }
+ c.chLock.Unlock()
+
+ if stop {
+ break
+ }
+ }
+ }
+ }()
+ }
+ c.chLock.Unlock()
+}
+
+func (c *pipelineConnClient) worker() error {
+ tlsConfig := c.cachedTLSConfig()
+ conn, err := dialAddr(c.Addr, c.Dial, c.DialDualStack, c.IsTLS, tlsConfig, c.WriteTimeout)
+ if err != nil {
+ return err
+ }
+
+ // Start reader and writer
+ stopW := make(chan struct{})
+ doneW := make(chan error)
+ go func() {
+ doneW <- c.writer(conn, stopW)
+ }()
+ stopR := make(chan struct{})
+ doneR := make(chan error)
+ go func() {
+ doneR <- c.reader(conn, stopR)
+ }()
+
+ // Wait until reader and writer are stopped
+ select {
+ case err = <-doneW:
+ conn.Close()
+ close(stopR)
+ <-doneR
+ case err = <-doneR:
+ conn.Close()
+ close(stopW)
+ <-doneW
+ }
+
+ // Notify pending readers
+ for len(c.chR) > 0 {
+ w := <-c.chR
+ w.err = errPipelineConnStopped
+ w.done <- struct{}{}
+ }
+
+ return err
+}
+
+func (c *pipelineConnClient) cachedTLSConfig() *tls.Config {
+ if !c.IsTLS {
+ return nil
+ }
+
+ c.tlsConfigLock.Lock()
+ cfg := c.tlsConfig
+ if cfg == nil {
+ cfg = newClientTLSConfig(c.TLSConfig, c.Addr)
+ c.tlsConfig = cfg
+ }
+ c.tlsConfigLock.Unlock()
+
+ return cfg
+}
+
+func (c *pipelineConnClient) writer(conn net.Conn, stopCh <-chan struct{}) error {
+ writeBufferSize := c.WriteBufferSize
+ if writeBufferSize <= 0 {
+ writeBufferSize = defaultWriteBufferSize
+ }
+ bw := bufio.NewWriterSize(conn, writeBufferSize)
+ defer bw.Flush()
+ chR := c.chR
+ chW := c.chW
+ writeTimeout := c.WriteTimeout
+
+ maxIdleConnDuration := c.MaxIdleConnDuration
+ if maxIdleConnDuration <= 0 {
+ maxIdleConnDuration = DefaultMaxIdleConnDuration
+ }
+ maxBatchDelay := c.MaxBatchDelay
+
+ var (
+ stopTimer = time.NewTimer(time.Hour)
+ flushTimer = time.NewTimer(time.Hour)
+ flushTimerCh <-chan time.Time
+ instantTimerCh = make(chan time.Time)
+
+ w *pipelineWork
+ err error
+ )
+ close(instantTimerCh)
+ for {
+ againChW:
+ select {
+ case w = <-chW:
+ // Fast path: len(chW) > 0
+ default:
+ // Slow path
+ stopTimer.Reset(maxIdleConnDuration)
+ select {
+ case w = <-chW:
+ case <-stopTimer.C:
+ return nil
+ case <-stopCh:
+ return nil
+ case <-flushTimerCh:
+ if err = bw.Flush(); err != nil {
+ return err
+ }
+ flushTimerCh = nil
+ goto againChW
+ }
+ }
+
+ if !w.deadline.IsZero() && time.Since(w.deadline) >= 0 {
+ w.err = ErrTimeout
+ w.done <- struct{}{}
+ continue
+ }
+
+ w.resp.parseNetConn(conn)
+
+ if writeTimeout > 0 {
+ // Set Deadline every time, since golang has fixed the performance issue
+ // See https://github.com/golang/go/issues/15133#issuecomment-271571395 for details
+ currentTime := time.Now()
+ if err = conn.SetWriteDeadline(currentTime.Add(writeTimeout)); err != nil {
+ w.err = err
+ w.done <- struct{}{}
+ return err
+ }
+ }
+ if err = w.req.Write(bw); err != nil {
+ w.err = err
+ w.done <- struct{}{}
+ return err
+ }
+ if flushTimerCh == nil && (len(chW) == 0 || len(chR) == cap(chR)) {
+ if maxBatchDelay > 0 {
+ flushTimer.Reset(maxBatchDelay)
+ flushTimerCh = flushTimer.C
+ } else {
+ flushTimerCh = instantTimerCh
+ }
+ }
+
+ againChR:
+ select {
+ case chR <- w:
+ // Fast path: len(chR) < cap(chR)
+ default:
+ // Slow path
+ select {
+ case chR <- w:
+ case <-stopCh:
+ w.err = errPipelineConnStopped
+ w.done <- struct{}{}
+ return nil
+ case <-flushTimerCh:
+ if err = bw.Flush(); err != nil {
+ w.err = err
+ w.done <- struct{}{}
+ return err
+ }
+ flushTimerCh = nil
+ goto againChR
+ }
+ }
+ }
+}
+
+func (c *pipelineConnClient) reader(conn net.Conn, stopCh <-chan struct{}) error {
+ readBufferSize := c.ReadBufferSize
+ if readBufferSize <= 0 {
+ readBufferSize = defaultReadBufferSize
+ }
+ br := bufio.NewReaderSize(conn, readBufferSize)
+ chR := c.chR
+ readTimeout := c.ReadTimeout
+
+ var (
+ w *pipelineWork
+ err error
+ )
+ for {
+ select {
+ case w = <-chR:
+ // Fast path: len(chR) > 0
+ default:
+ // Slow path
+ select {
+ case w = <-chR:
+ case <-stopCh:
+ return nil
+ }
+ }
+
+ if readTimeout > 0 {
+ // Set Deadline every time, since golang has fixed the performance issue
+ // See https://github.com/golang/go/issues/15133#issuecomment-271571395 for details
+ currentTime := time.Now()
+ if err = conn.SetReadDeadline(currentTime.Add(readTimeout)); err != nil {
+ w.err = err
+ w.done <- struct{}{}
+ return err
+ }
+ }
+ if err = w.resp.Read(br); err != nil {
+ w.err = err
+ w.done <- struct{}{}
+ return err
+ }
+
+ w.done <- struct{}{}
+ }
+}
+
+func (c *pipelineConnClient) logger() Logger {
+ if c.Logger != nil {
+ return c.Logger
+ }
+ return defaultLogger
+}
+
+// PendingRequests returns the current number of pending requests pipelined
+// to the server.
+//
+// This number may exceed MaxPendingRequests*MaxConns by up to two times, since
+// each connection to the server may keep up to MaxPendingRequests requests
+// in the queue before sending them to the server.
+//
+// This function may be used for balancing load among multiple PipelineClient
+// instances.
+func (c *PipelineClient) PendingRequests() int {
+ c.connClientsLock.Lock()
+ n := 0
+ for _, cc := range c.connClients {
+ n += cc.PendingRequests()
+ }
+ c.connClientsLock.Unlock()
+ return n
+}
+
+func (c *pipelineConnClient) PendingRequests() int {
+ c.init()
+
+ c.chLock.Lock()
+ n := len(c.chR) + len(c.chW)
+ c.chLock.Unlock()
+ return n
+}
+
+var errPipelineConnStopped = errors.New("pipeline connection has been stopped")
+
+var DefaultTransport RoundTripper = &transport{}
+
+type transport struct{}
+
+func (t *transport) RoundTrip(hc *HostClient, req *Request, resp *Response) (retry bool, err error) {
+ customSkipBody := resp.SkipBody
+ customStreamBody := resp.StreamBody
+
+ var deadline time.Time
+ if req.timeout > 0 {
+ deadline = time.Now().Add(req.timeout)
+ }
+
+ cc, err := hc.acquireConn(req.timeout, req.ConnectionClose())
+ if err != nil {
+ return false, err
+ }
+ conn := cc.c
+
+ resp.parseNetConn(conn)
+
+ writeDeadline := deadline
+ if hc.WriteTimeout > 0 {
+ tmpWriteDeadline := time.Now().Add(hc.WriteTimeout)
+ if writeDeadline.IsZero() || tmpWriteDeadline.Before(writeDeadline) {
+ writeDeadline = tmpWriteDeadline
+ }
+ }
+
+ if err = conn.SetWriteDeadline(writeDeadline); err != nil {
+ hc.closeConn(cc)
+ return true, err
+ }
+
+ resetConnection := false
+ if hc.MaxConnDuration > 0 && time.Since(cc.createdTime) > hc.MaxConnDuration && !req.ConnectionClose() {
+ req.SetConnectionClose()
+ resetConnection = true
+ }
+
+ bw := hc.acquireWriter(conn)
+ err = req.Write(bw)
+
+ if resetConnection {
+ req.Header.ResetConnectionClose()
+ }
+
+ if err == nil {
+ err = bw.Flush()
+ }
+ hc.releaseWriter(bw)
+
+ // Return ErrTimeout on any timeout.
+ if x, ok := err.(interface{ Timeout() bool }); ok && x.Timeout() {
+ err = ErrTimeout
+ }
+
+ isConnRST := isConnectionReset(err)
+ if err != nil && !isConnRST {
+ hc.closeConn(cc)
+ return true, err
+ }
+
+ readDeadline := deadline
+ if hc.ReadTimeout > 0 {
+ tmpReadDeadline := time.Now().Add(hc.ReadTimeout)
+ if readDeadline.IsZero() || tmpReadDeadline.Before(readDeadline) {
+ readDeadline = tmpReadDeadline
+ }
+ }
+
+ if err = conn.SetReadDeadline(readDeadline); err != nil {
+ hc.closeConn(cc)
+ return true, err
+ }
+
+ if customSkipBody || req.Header.IsHead() {
+ resp.SkipBody = true
+ }
+ if hc.DisableHeaderNamesNormalizing {
+ resp.Header.DisableNormalizing()
+ }
+
+ br := hc.acquireReader(conn)
+ err = resp.ReadLimitBody(br, hc.MaxResponseBodySize)
+ if err != nil {
+ hc.releaseReader(br)
+ hc.closeConn(cc)
+ // Don't retry in case of ErrBodyTooLarge since we will just get the same again.
+ needRetry := err != ErrBodyTooLarge
+ return needRetry, err
+ }
+
+ closeConn := resetConnection || req.ConnectionClose() || resp.ConnectionClose() || isConnRST
+ if customStreamBody && resp.bodyStream != nil {
+ rbs := resp.bodyStream
+ resp.bodyStream = newCloseReader(rbs, func() error {
+ hc.releaseReader(br)
+ if r, ok := rbs.(*requestStream); ok {
+ releaseRequestStream(r)
+ }
+ if closeConn || resp.ConnectionClose() {
+ hc.closeConn(cc)
+ } else {
+ hc.releaseConn(cc)
+ }
+ return nil
+ })
+ return false, nil
+ } else {
+ hc.releaseReader(br)
+ }
+
+ if closeConn {
+ hc.closeConn(cc)
+ } else {
+ hc.releaseConn(cc)
+ }
+ return false, nil
+}
diff --git a/vendor/github.com/valyala/fasthttp/coarsetime.go b/vendor/github.com/valyala/fasthttp/coarsetime.go
new file mode 100644
index 0000000..4679df6
--- /dev/null
+++ b/vendor/github.com/valyala/fasthttp/coarsetime.go
@@ -0,0 +1,13 @@
+package fasthttp
+
+import (
+ "time"
+)
+
+// CoarseTimeNow returns the current time truncated to the nearest second.
+//
+// Deprecated: This is slower than calling time.Now() directly.
+// This is now time.Now().Truncate(time.Second) shortcut.
+func CoarseTimeNow() time.Time {
+ return time.Now().Truncate(time.Second)
+}
diff --git a/vendor/github.com/valyala/fasthttp/compress.go b/vendor/github.com/valyala/fasthttp/compress.go
new file mode 100644
index 0000000..1f44f1e
--- /dev/null
+++ b/vendor/github.com/valyala/fasthttp/compress.go
@@ -0,0 +1,480 @@
+package fasthttp
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "io/fs"
+ "sync"
+
+ "github.com/klauspost/compress/flate"
+ "github.com/klauspost/compress/gzip"
+ "github.com/klauspost/compress/zlib"
+ "github.com/valyala/bytebufferpool"
+ "github.com/valyala/fasthttp/stackless"
+)
+
+// Supported compression levels.
+const (
+ CompressNoCompression = flate.NoCompression
+ CompressBestSpeed = flate.BestSpeed
+ CompressBestCompression = flate.BestCompression
+ CompressDefaultCompression = 6 // flate.DefaultCompression
+ CompressHuffmanOnly = -2 // flate.HuffmanOnly
+)
+
+func acquireGzipReader(r io.Reader) (*gzip.Reader, error) {
+ v := gzipReaderPool.Get()
+ if v == nil {
+ return gzip.NewReader(r)
+ }
+ zr := v.(*gzip.Reader)
+ if err := zr.Reset(r); err != nil {
+ return nil, err
+ }
+ return zr, nil
+}
+
+func releaseGzipReader(zr *gzip.Reader) {
+ zr.Close()
+ gzipReaderPool.Put(zr)
+}
+
+var gzipReaderPool sync.Pool
+
+func acquireFlateReader(r io.Reader) (io.ReadCloser, error) {
+ v := flateReaderPool.Get()
+ if v == nil {
+ zr, err := zlib.NewReader(r)
+ if err != nil {
+ return nil, err
+ }
+ return zr, nil
+ }
+ zr := v.(io.ReadCloser)
+ if err := resetFlateReader(zr, r); err != nil {
+ return nil, err
+ }
+ return zr, nil
+}
+
+func releaseFlateReader(zr io.ReadCloser) {
+ zr.Close()
+ flateReaderPool.Put(zr)
+}
+
+func resetFlateReader(zr io.ReadCloser, r io.Reader) error {
+ zrr, ok := zr.(zlib.Resetter)
+ if !ok {
+ // sanity check. should only be called with a zlib.Reader
+ panic("BUG: zlib.Reader doesn't implement zlib.Resetter???")
+ }
+ return zrr.Reset(r, nil)
+}
+
+var flateReaderPool sync.Pool
+
+func acquireStacklessGzipWriter(w io.Writer, level int) stackless.Writer {
+ nLevel := normalizeCompressLevel(level)
+ p := stacklessGzipWriterPoolMap[nLevel]
+ v := p.Get()
+ if v == nil {
+ return stackless.NewWriter(w, func(w io.Writer) stackless.Writer {
+ return acquireRealGzipWriter(w, level)
+ })
+ }
+ sw := v.(stackless.Writer)
+ sw.Reset(w)
+ return sw
+}
+
+func releaseStacklessGzipWriter(sw stackless.Writer, level int) {
+ sw.Close()
+ nLevel := normalizeCompressLevel(level)
+ p := stacklessGzipWriterPoolMap[nLevel]
+ p.Put(sw)
+}
+
+func acquireRealGzipWriter(w io.Writer, level int) *gzip.Writer {
+ nLevel := normalizeCompressLevel(level)
+ p := realGzipWriterPoolMap[nLevel]
+ v := p.Get()
+ if v == nil {
+ zw, err := gzip.NewWriterLevel(w, level)
+ if err != nil {
+ // gzip.NewWriterLevel only errors for invalid
+ // compression levels. Clamp it to be min or max.
+ if level < gzip.HuffmanOnly {
+ level = gzip.HuffmanOnly
+ } else {
+ level = gzip.BestCompression
+ }
+ zw, _ = gzip.NewWriterLevel(w, level)
+ }
+ return zw
+ }
+ zw := v.(*gzip.Writer)
+ zw.Reset(w)
+ return zw
+}
+
+func releaseRealGzipWriter(zw *gzip.Writer, level int) {
+ zw.Close()
+ nLevel := normalizeCompressLevel(level)
+ p := realGzipWriterPoolMap[nLevel]
+ p.Put(zw)
+}
+
+var (
+ stacklessGzipWriterPoolMap = newCompressWriterPoolMap()
+ realGzipWriterPoolMap = newCompressWriterPoolMap()
+)
+
+// AppendGzipBytesLevel appends gzipped src to dst using the given
+// compression level and returns the resulting dst.
+//
+// Supported compression levels are:
+//
+// - CompressNoCompression
+// - CompressBestSpeed
+// - CompressBestCompression
+// - CompressDefaultCompression
+// - CompressHuffmanOnly
+func AppendGzipBytesLevel(dst, src []byte, level int) []byte {
+ w := &byteSliceWriter{dst}
+ WriteGzipLevel(w, src, level) //nolint:errcheck
+ return w.b
+}
+
+// WriteGzipLevel writes gzipped p to w using the given compression level
+// and returns the number of compressed bytes written to w.
+//
+// Supported compression levels are:
+//
+// - CompressNoCompression
+// - CompressBestSpeed
+// - CompressBestCompression
+// - CompressDefaultCompression
+// - CompressHuffmanOnly
+func WriteGzipLevel(w io.Writer, p []byte, level int) (int, error) {
+ switch w.(type) {
+ case *byteSliceWriter,
+ *bytes.Buffer,
+ *bytebufferpool.ByteBuffer:
+ // These writers don't block, so we can just use stacklessWriteGzip
+ ctx := &compressCtx{
+ w: w,
+ p: p,
+ level: level,
+ }
+ stacklessWriteGzip(ctx)
+ return len(p), nil
+ default:
+ zw := acquireStacklessGzipWriter(w, level)
+ n, err := zw.Write(p)
+ releaseStacklessGzipWriter(zw, level)
+ return n, err
+ }
+}
+
+var (
+ stacklessWriteGzipOnce sync.Once
+ stacklessWriteGzipFunc func(ctx interface{}) bool
+)
+
+func stacklessWriteGzip(ctx interface{}) {
+ stacklessWriteGzipOnce.Do(func() {
+ stacklessWriteGzipFunc = stackless.NewFunc(nonblockingWriteGzip)
+ })
+ stacklessWriteGzipFunc(ctx)
+}
+
+func nonblockingWriteGzip(ctxv interface{}) {
+ ctx := ctxv.(*compressCtx)
+ zw := acquireRealGzipWriter(ctx.w, ctx.level)
+
+ zw.Write(ctx.p) //nolint:errcheck // no way to handle this error anyway
+
+ releaseRealGzipWriter(zw, ctx.level)
+}
+
+// WriteGzip writes gzipped p to w and returns the number of compressed
+// bytes written to w.
+func WriteGzip(w io.Writer, p []byte) (int, error) {
+ return WriteGzipLevel(w, p, CompressDefaultCompression)
+}
+
+// AppendGzipBytes appends gzipped src to dst and returns the resulting dst.
+func AppendGzipBytes(dst, src []byte) []byte {
+ return AppendGzipBytesLevel(dst, src, CompressDefaultCompression)
+}
+
+// WriteGunzip writes ungzipped p to w and returns the number of uncompressed
+// bytes written to w.
+func WriteGunzip(w io.Writer, p []byte) (int, error) {
+ r := &byteSliceReader{p}
+ zr, err := acquireGzipReader(r)
+ if err != nil {
+ return 0, err
+ }
+ n, err := copyZeroAlloc(w, zr)
+ releaseGzipReader(zr)
+ nn := int(n)
+ if int64(nn) != n {
+ return 0, fmt.Errorf("too much data gunzipped: %d", n)
+ }
+ return nn, err
+}
+
+// AppendGunzipBytes appends gunzipped src to dst and returns the resulting dst.
+func AppendGunzipBytes(dst, src []byte) ([]byte, error) {
+ w := &byteSliceWriter{dst}
+ _, err := WriteGunzip(w, src)
+ return w.b, err
+}
+
+// AppendDeflateBytesLevel appends deflated src to dst using the given
+// compression level and returns the resulting dst.
+//
+// Supported compression levels are:
+//
+// - CompressNoCompression
+// - CompressBestSpeed
+// - CompressBestCompression
+// - CompressDefaultCompression
+// - CompressHuffmanOnly
+func AppendDeflateBytesLevel(dst, src []byte, level int) []byte {
+ w := &byteSliceWriter{dst}
+ WriteDeflateLevel(w, src, level) //nolint:errcheck
+ return w.b
+}
+
+// WriteDeflateLevel writes deflated p to w using the given compression level
+// and returns the number of compressed bytes written to w.
+//
+// Supported compression levels are:
+//
+// - CompressNoCompression
+// - CompressBestSpeed
+// - CompressBestCompression
+// - CompressDefaultCompression
+// - CompressHuffmanOnly
+func WriteDeflateLevel(w io.Writer, p []byte, level int) (int, error) {
+ switch w.(type) {
+ case *byteSliceWriter,
+ *bytes.Buffer,
+ *bytebufferpool.ByteBuffer:
+ // These writers don't block, so we can just use stacklessWriteDeflate
+ ctx := &compressCtx{
+ w: w,
+ p: p,
+ level: level,
+ }
+ stacklessWriteDeflate(ctx)
+ return len(p), nil
+ default:
+ zw := acquireStacklessDeflateWriter(w, level)
+ n, err := zw.Write(p)
+ releaseStacklessDeflateWriter(zw, level)
+ return n, err
+ }
+}
+
+var (
+ stacklessWriteDeflateOnce sync.Once
+ stacklessWriteDeflateFunc func(ctx interface{}) bool
+)
+
+func stacklessWriteDeflate(ctx interface{}) {
+ stacklessWriteDeflateOnce.Do(func() {
+ stacklessWriteDeflateFunc = stackless.NewFunc(nonblockingWriteDeflate)
+ })
+ stacklessWriteDeflateFunc(ctx)
+}
+
+func nonblockingWriteDeflate(ctxv interface{}) {
+ ctx := ctxv.(*compressCtx)
+ zw := acquireRealDeflateWriter(ctx.w, ctx.level)
+
+ zw.Write(ctx.p) //nolint:errcheck // no way to handle this error anyway
+
+ releaseRealDeflateWriter(zw, ctx.level)
+}
+
+type compressCtx struct {
+ w io.Writer
+ p []byte
+ level int
+}
+
+// WriteDeflate writes deflated p to w and returns the number of compressed
+// bytes written to w.
+func WriteDeflate(w io.Writer, p []byte) (int, error) {
+ return WriteDeflateLevel(w, p, CompressDefaultCompression)
+}
+
+// AppendDeflateBytes appends deflated src to dst and returns the resulting dst.
+func AppendDeflateBytes(dst, src []byte) []byte {
+ return AppendDeflateBytesLevel(dst, src, CompressDefaultCompression)
+}
+
+// WriteInflate writes inflated p to w and returns the number of uncompressed
+// bytes written to w.
+func WriteInflate(w io.Writer, p []byte) (int, error) {
+ r := &byteSliceReader{p}
+ zr, err := acquireFlateReader(r)
+ if err != nil {
+ return 0, err
+ }
+ n, err := copyZeroAlloc(w, zr)
+ releaseFlateReader(zr)
+ nn := int(n)
+ if int64(nn) != n {
+ return 0, fmt.Errorf("too much data inflated: %d", n)
+ }
+ return nn, err
+}
+
+// AppendInflateBytes appends inflated src to dst and returns the resulting dst.
+func AppendInflateBytes(dst, src []byte) ([]byte, error) {
+ w := &byteSliceWriter{dst}
+ _, err := WriteInflate(w, src)
+ return w.b, err
+}
+
+type byteSliceWriter struct {
+ b []byte
+}
+
+func (w *byteSliceWriter) Write(p []byte) (int, error) {
+ w.b = append(w.b, p...)
+ return len(p), nil
+}
+
+type byteSliceReader struct {
+ b []byte
+}
+
+func (r *byteSliceReader) Read(p []byte) (int, error) {
+ if len(r.b) == 0 {
+ return 0, io.EOF
+ }
+ n := copy(p, r.b)
+ r.b = r.b[n:]
+ return n, nil
+}
+
+func (r *byteSliceReader) ReadByte() (byte, error) {
+ if len(r.b) == 0 {
+ return 0, io.EOF
+ }
+ n := r.b[0]
+ r.b = r.b[1:]
+ return n, nil
+}
+
+func acquireStacklessDeflateWriter(w io.Writer, level int) stackless.Writer {
+ nLevel := normalizeCompressLevel(level)
+ p := stacklessDeflateWriterPoolMap[nLevel]
+ v := p.Get()
+ if v == nil {
+ return stackless.NewWriter(w, func(w io.Writer) stackless.Writer {
+ return acquireRealDeflateWriter(w, level)
+ })
+ }
+ sw := v.(stackless.Writer)
+ sw.Reset(w)
+ return sw
+}
+
+func releaseStacklessDeflateWriter(sw stackless.Writer, level int) {
+ sw.Close()
+ nLevel := normalizeCompressLevel(level)
+ p := stacklessDeflateWriterPoolMap[nLevel]
+ p.Put(sw)
+}
+
+func acquireRealDeflateWriter(w io.Writer, level int) *zlib.Writer {
+ nLevel := normalizeCompressLevel(level)
+ p := realDeflateWriterPoolMap[nLevel]
+ v := p.Get()
+ if v == nil {
+ zw, err := zlib.NewWriterLevel(w, level)
+ if err != nil {
+ // zlib.NewWriterLevel only errors for invalid
+ // compression levels. Clamp it to be min or max.
+ if level < zlib.HuffmanOnly {
+ level = zlib.HuffmanOnly
+ } else {
+ level = zlib.BestCompression
+ }
+ zw, _ = zlib.NewWriterLevel(w, level)
+ }
+ return zw
+ }
+ zw := v.(*zlib.Writer)
+ zw.Reset(w)
+ return zw
+}
+
+func releaseRealDeflateWriter(zw *zlib.Writer, level int) {
+ zw.Close()
+ nLevel := normalizeCompressLevel(level)
+ p := realDeflateWriterPoolMap[nLevel]
+ p.Put(zw)
+}
+
+var (
+ stacklessDeflateWriterPoolMap = newCompressWriterPoolMap()
+ realDeflateWriterPoolMap = newCompressWriterPoolMap()
+)
+
+func newCompressWriterPoolMap() []*sync.Pool {
+ // Initialize pools for all the compression levels defined
+ // in https://pkg.go.dev/compress/flate#pkg-constants .
+ // Compression levels are normalized with normalizeCompressLevel,
+ // so the fit [0..11].
+ var m []*sync.Pool
+ for i := 0; i < 12; i++ {
+ m = append(m, &sync.Pool{})
+ }
+ return m
+}
+
+func isFileCompressible(f fs.File, minCompressRatio float64) bool {
+ // Try compressing the first 4kb of the file
+ // and see if it can be compressed by more than
+ // the given minCompressRatio.
+ b := bytebufferpool.Get()
+ zw := acquireStacklessGzipWriter(b, CompressDefaultCompression)
+ lr := &io.LimitedReader{
+ R: f,
+ N: 4096,
+ }
+ _, err := copyZeroAlloc(zw, lr)
+ releaseStacklessGzipWriter(zw, CompressDefaultCompression)
+ seeker, ok := f.(io.Seeker)
+ if !ok {
+ return false
+ }
+ seeker.Seek(0, io.SeekStart) //nolint:errcheck
+ if err != nil {
+ return false
+ }
+
+ n := 4096 - lr.N
+ zn := len(b.B)
+ bytebufferpool.Put(b)
+ return float64(zn) < float64(n)*minCompressRatio
+}
+
+// normalizes compression level into [0..11], so it could be used as an index
+// in *PoolMap.
+func normalizeCompressLevel(level int) int {
+ // -2 is the lowest compression level - CompressHuffmanOnly
+ // 9 is the highest compression level - CompressBestCompression
+ if level < -2 || level > 9 {
+ level = CompressDefaultCompression
+ }
+ return level + 2
+}
diff --git a/vendor/github.com/valyala/fasthttp/cookie.go b/vendor/github.com/valyala/fasthttp/cookie.go
new file mode 100644
index 0000000..4cc3624
--- /dev/null
+++ b/vendor/github.com/valyala/fasthttp/cookie.go
@@ -0,0 +1,555 @@
+package fasthttp
+
+import (
+ "bytes"
+ "errors"
+ "io"
+ "sync"
+ "time"
+)
+
+var zeroTime time.Time
+
+var (
+ // CookieExpireDelete may be set on Cookie.Expire for expiring the given cookie.
+ CookieExpireDelete = time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC)
+
+ // CookieExpireUnlimited indicates that the cookie doesn't expire.
+ CookieExpireUnlimited = zeroTime
+)
+
+// CookieSameSite is an enum for the mode in which the SameSite flag should be set for the given cookie.
+// See https://tools.ietf.org/html/draft-ietf-httpbis-cookie-same-site-00 for details.
+type CookieSameSite int
+
+const (
+ // CookieSameSiteDisabled removes the SameSite flag
+ CookieSameSiteDisabled CookieSameSite = iota
+ // CookieSameSiteDefaultMode sets the SameSite flag
+ CookieSameSiteDefaultMode
+ // CookieSameSiteLaxMode sets the SameSite flag with the "Lax" parameter
+ CookieSameSiteLaxMode
+ // CookieSameSiteStrictMode sets the SameSite flag with the "Strict" parameter
+ CookieSameSiteStrictMode
+ // CookieSameSiteNoneMode sets the SameSite flag with the "None" parameter
+ // see https://tools.ietf.org/html/draft-west-cookie-incrementalism-00
+ CookieSameSiteNoneMode
+)
+
+// AcquireCookie returns an empty Cookie object from the pool.
+//
+// The returned object may be returned back to the pool with ReleaseCookie.
+// This allows reducing GC load.
+func AcquireCookie() *Cookie {
+ return cookiePool.Get().(*Cookie)
+}
+
+// ReleaseCookie returns the Cookie object acquired with AcquireCookie back
+// to the pool.
+//
+// Do not access released Cookie object, otherwise data races may occur.
+func ReleaseCookie(c *Cookie) {
+ c.Reset()
+ cookiePool.Put(c)
+}
+
+var cookiePool = &sync.Pool{
+ New: func() interface{} {
+ return &Cookie{}
+ },
+}
+
+// Cookie represents HTTP response cookie.
+//
+// Do not copy Cookie objects. Create new object and use CopyTo instead.
+//
+// Cookie instance MUST NOT be used from concurrently running goroutines.
+type Cookie struct {
+ noCopy noCopy
+
+ key []byte
+ value []byte
+ expire time.Time
+ maxAge int
+ domain []byte
+ path []byte
+
+ httpOnly bool
+ secure bool
+ sameSite CookieSameSite
+
+ bufKV argsKV
+ buf []byte
+}
+
+// CopyTo copies src cookie to c.
+func (c *Cookie) CopyTo(src *Cookie) {
+ c.Reset()
+ c.key = append(c.key, src.key...)
+ c.value = append(c.value, src.value...)
+ c.expire = src.expire
+ c.maxAge = src.maxAge
+ c.domain = append(c.domain, src.domain...)
+ c.path = append(c.path, src.path...)
+ c.httpOnly = src.httpOnly
+ c.secure = src.secure
+ c.sameSite = src.sameSite
+}
+
+// HTTPOnly returns true if the cookie is http only.
+func (c *Cookie) HTTPOnly() bool {
+ return c.httpOnly
+}
+
+// SetHTTPOnly sets cookie's httpOnly flag to the given value.
+func (c *Cookie) SetHTTPOnly(httpOnly bool) {
+ c.httpOnly = httpOnly
+}
+
+// Secure returns true if the cookie is secure.
+func (c *Cookie) Secure() bool {
+ return c.secure
+}
+
+// SetSecure sets cookie's secure flag to the given value.
+func (c *Cookie) SetSecure(secure bool) {
+ c.secure = secure
+}
+
+// SameSite returns the SameSite mode.
+func (c *Cookie) SameSite() CookieSameSite {
+ return c.sameSite
+}
+
+// SetSameSite sets the cookie's SameSite flag to the given value.
+// set value CookieSameSiteNoneMode will set Secure to true also to avoid browser rejection
+func (c *Cookie) SetSameSite(mode CookieSameSite) {
+ c.sameSite = mode
+ if mode == CookieSameSiteNoneMode {
+ c.SetSecure(true)
+ }
+}
+
+// Path returns cookie path.
+func (c *Cookie) Path() []byte {
+ return c.path
+}
+
+// SetPath sets cookie path.
+func (c *Cookie) SetPath(path string) {
+ c.buf = append(c.buf[:0], path...)
+ c.path = normalizePath(c.path, c.buf)
+}
+
+// SetPathBytes sets cookie path.
+func (c *Cookie) SetPathBytes(path []byte) {
+ c.buf = append(c.buf[:0], path...)
+ c.path = normalizePath(c.path, c.buf)
+}
+
+// Domain returns cookie domain.
+//
+// The returned value is valid until the Cookie reused or released (ReleaseCookie).
+// Do not store references to the returned value. Make copies instead.
+func (c *Cookie) Domain() []byte {
+ return c.domain
+}
+
+// SetDomain sets cookie domain.
+func (c *Cookie) SetDomain(domain string) {
+ c.domain = append(c.domain[:0], domain...)
+}
+
+// SetDomainBytes sets cookie domain.
+func (c *Cookie) SetDomainBytes(domain []byte) {
+ c.domain = append(c.domain[:0], domain...)
+}
+
+// MaxAge returns the seconds until the cookie is meant to expire or 0
+// if no max age.
+func (c *Cookie) MaxAge() int {
+ return c.maxAge
+}
+
+// SetMaxAge sets cookie expiration time based on seconds. This takes precedence
+// over any absolute expiry set on the cookie
+//
+// Set max age to 0 to unset
+func (c *Cookie) SetMaxAge(seconds int) {
+ c.maxAge = seconds
+}
+
+// Expire returns cookie expiration time.
+//
+// CookieExpireUnlimited is returned if cookie doesn't expire
+func (c *Cookie) Expire() time.Time {
+ expire := c.expire
+ if expire.IsZero() {
+ expire = CookieExpireUnlimited
+ }
+ return expire
+}
+
+// SetExpire sets cookie expiration time.
+//
+// Set expiration time to CookieExpireDelete for expiring (deleting)
+// the cookie on the client.
+//
+// By default cookie lifetime is limited by browser session.
+func (c *Cookie) SetExpire(expire time.Time) {
+ c.expire = expire
+}
+
+// Value returns cookie value.
+//
+// The returned value is valid until the Cookie reused or released (ReleaseCookie).
+// Do not store references to the returned value. Make copies instead.
+func (c *Cookie) Value() []byte {
+ return c.value
+}
+
+// SetValue sets cookie value.
+func (c *Cookie) SetValue(value string) {
+ c.value = append(c.value[:0], value...)
+}
+
+// SetValueBytes sets cookie value.
+func (c *Cookie) SetValueBytes(value []byte) {
+ c.value = append(c.value[:0], value...)
+}
+
+// Key returns cookie name.
+//
+// The returned value is valid until the Cookie reused or released (ReleaseCookie).
+// Do not store references to the returned value. Make copies instead.
+func (c *Cookie) Key() []byte {
+ return c.key
+}
+
+// SetKey sets cookie name.
+func (c *Cookie) SetKey(key string) {
+ c.key = append(c.key[:0], key...)
+}
+
+// SetKeyBytes sets cookie name.
+func (c *Cookie) SetKeyBytes(key []byte) {
+ c.key = append(c.key[:0], key...)
+}
+
+// Reset clears the cookie.
+func (c *Cookie) Reset() {
+ c.key = c.key[:0]
+ c.value = c.value[:0]
+ c.expire = zeroTime
+ c.maxAge = 0
+ c.domain = c.domain[:0]
+ c.path = c.path[:0]
+ c.httpOnly = false
+ c.secure = false
+ c.sameSite = CookieSameSiteDisabled
+}
+
+// AppendBytes appends cookie representation to dst and returns
+// the extended dst.
+func (c *Cookie) AppendBytes(dst []byte) []byte {
+ if len(c.key) > 0 {
+ dst = append(dst, c.key...)
+ dst = append(dst, '=')
+ }
+ dst = append(dst, c.value...)
+
+ if c.maxAge > 0 {
+ dst = append(dst, ';', ' ')
+ dst = append(dst, strCookieMaxAge...)
+ dst = append(dst, '=')
+ dst = AppendUint(dst, c.maxAge)
+ } else if !c.expire.IsZero() {
+ c.bufKV.value = AppendHTTPDate(c.bufKV.value[:0], c.expire)
+ dst = append(dst, ';', ' ')
+ dst = append(dst, strCookieExpires...)
+ dst = append(dst, '=')
+ dst = append(dst, c.bufKV.value...)
+ }
+ if len(c.domain) > 0 {
+ dst = appendCookiePart(dst, strCookieDomain, c.domain)
+ }
+ if len(c.path) > 0 {
+ dst = appendCookiePart(dst, strCookiePath, c.path)
+ }
+ if c.httpOnly {
+ dst = append(dst, ';', ' ')
+ dst = append(dst, strCookieHTTPOnly...)
+ }
+ if c.secure {
+ dst = append(dst, ';', ' ')
+ dst = append(dst, strCookieSecure...)
+ }
+ switch c.sameSite {
+ case CookieSameSiteDefaultMode:
+ dst = append(dst, ';', ' ')
+ dst = append(dst, strCookieSameSite...)
+ case CookieSameSiteLaxMode:
+ dst = append(dst, ';', ' ')
+ dst = append(dst, strCookieSameSite...)
+ dst = append(dst, '=')
+ dst = append(dst, strCookieSameSiteLax...)
+ case CookieSameSiteStrictMode:
+ dst = append(dst, ';', ' ')
+ dst = append(dst, strCookieSameSite...)
+ dst = append(dst, '=')
+ dst = append(dst, strCookieSameSiteStrict...)
+ case CookieSameSiteNoneMode:
+ dst = append(dst, ';', ' ')
+ dst = append(dst, strCookieSameSite...)
+ dst = append(dst, '=')
+ dst = append(dst, strCookieSameSiteNone...)
+ }
+ return dst
+}
+
+// Cookie returns cookie representation.
+//
+// The returned value is valid until the Cookie reused or released (ReleaseCookie).
+// Do not store references to the returned value. Make copies instead.
+func (c *Cookie) Cookie() []byte {
+ c.buf = c.AppendBytes(c.buf[:0])
+ return c.buf
+}
+
+// String returns cookie representation.
+func (c *Cookie) String() string {
+ return string(c.Cookie())
+}
+
+// WriteTo writes cookie representation to w.
+//
+// WriteTo implements io.WriterTo interface.
+func (c *Cookie) WriteTo(w io.Writer) (int64, error) {
+ n, err := w.Write(c.Cookie())
+ return int64(n), err
+}
+
+var errNoCookies = errors.New("no cookies found")
+
+// Parse parses Set-Cookie header.
+func (c *Cookie) Parse(src string) error {
+ c.buf = append(c.buf[:0], src...)
+ return c.ParseBytes(c.buf)
+}
+
+// ParseBytes parses Set-Cookie header.
+func (c *Cookie) ParseBytes(src []byte) error {
+ c.Reset()
+
+ var s cookieScanner
+ s.b = src
+
+ kv := &c.bufKV
+ if !s.next(kv) {
+ return errNoCookies
+ }
+
+ c.key = append(c.key, kv.key...)
+ c.value = append(c.value, kv.value...)
+
+ for s.next(kv) {
+ if len(kv.key) != 0 {
+ // Case insensitive switch on first char
+ switch kv.key[0] | 0x20 {
+ case 'm':
+ if caseInsensitiveCompare(strCookieMaxAge, kv.key) {
+ maxAge, err := ParseUint(kv.value)
+ if err != nil {
+ return err
+ }
+ c.maxAge = maxAge
+ }
+
+ case 'e': // "expires"
+ if caseInsensitiveCompare(strCookieExpires, kv.key) {
+ v := b2s(kv.value)
+ // Try the same two formats as net/http
+ // See: https://github.com/golang/go/blob/00379be17e63a5b75b3237819392d2dc3b313a27/src/net/http/cookie.go#L133-L135
+ exptime, err := time.ParseInLocation(time.RFC1123, v, time.UTC)
+ if err != nil {
+ exptime, err = time.Parse("Mon, 02-Jan-2006 15:04:05 MST", v)
+ if err != nil {
+ return err
+ }
+ }
+ c.expire = exptime
+ }
+
+ case 'd': // "domain"
+ if caseInsensitiveCompare(strCookieDomain, kv.key) {
+ c.domain = append(c.domain, kv.value...)
+ }
+
+ case 'p': // "path"
+ if caseInsensitiveCompare(strCookiePath, kv.key) {
+ c.path = append(c.path, kv.value...)
+ }
+
+ case 's': // "samesite"
+ if caseInsensitiveCompare(strCookieSameSite, kv.key) {
+ if len(kv.value) > 0 {
+ // Case insensitive switch on first char
+ switch kv.value[0] | 0x20 {
+ case 'l': // "lax"
+ if caseInsensitiveCompare(strCookieSameSiteLax, kv.value) {
+ c.sameSite = CookieSameSiteLaxMode
+ }
+ case 's': // "strict"
+ if caseInsensitiveCompare(strCookieSameSiteStrict, kv.value) {
+ c.sameSite = CookieSameSiteStrictMode
+ }
+ case 'n': // "none"
+ if caseInsensitiveCompare(strCookieSameSiteNone, kv.value) {
+ c.sameSite = CookieSameSiteNoneMode
+ }
+ }
+ }
+ }
+ }
+ } else if len(kv.value) != 0 {
+ // Case insensitive switch on first char
+ switch kv.value[0] | 0x20 {
+ case 'h': // "httponly"
+ if caseInsensitiveCompare(strCookieHTTPOnly, kv.value) {
+ c.httpOnly = true
+ }
+
+ case 's': // "secure"
+ if caseInsensitiveCompare(strCookieSecure, kv.value) {
+ c.secure = true
+ } else if caseInsensitiveCompare(strCookieSameSite, kv.value) {
+ c.sameSite = CookieSameSiteDefaultMode
+ }
+ }
+ } // else empty or no match
+ }
+ return nil
+}
+
+func appendCookiePart(dst, key, value []byte) []byte {
+ dst = append(dst, ';', ' ')
+ dst = append(dst, key...)
+ dst = append(dst, '=')
+ return append(dst, value...)
+}
+
+func getCookieKey(dst, src []byte) []byte {
+ n := bytes.IndexByte(src, '=')
+ if n >= 0 {
+ src = src[:n]
+ }
+ return decodeCookieArg(dst, src, false)
+}
+
+func appendRequestCookieBytes(dst []byte, cookies []argsKV) []byte {
+ for i, n := 0, len(cookies); i < n; i++ {
+ kv := &cookies[i]
+ if len(kv.key) > 0 {
+ dst = append(dst, kv.key...)
+ dst = append(dst, '=')
+ }
+ dst = append(dst, kv.value...)
+ if i+1 < n {
+ dst = append(dst, ';', ' ')
+ }
+ }
+ return dst
+}
+
+// For Response we can not use the above function as response cookies
+// already contain the key= in the value.
+func appendResponseCookieBytes(dst []byte, cookies []argsKV) []byte {
+ for i, n := 0, len(cookies); i < n; i++ {
+ kv := &cookies[i]
+ dst = append(dst, kv.value...)
+ if i+1 < n {
+ dst = append(dst, ';', ' ')
+ }
+ }
+ return dst
+}
+
+func parseRequestCookies(cookies []argsKV, src []byte) []argsKV {
+ var s cookieScanner
+ s.b = src
+ var kv *argsKV
+ cookies, kv = allocArg(cookies)
+ for s.next(kv) {
+ if len(kv.key) > 0 || len(kv.value) > 0 {
+ cookies, kv = allocArg(cookies)
+ }
+ }
+ return releaseArg(cookies)
+}
+
+type cookieScanner struct {
+ b []byte
+}
+
+func (s *cookieScanner) next(kv *argsKV) bool {
+ b := s.b
+ if len(b) == 0 {
+ return false
+ }
+
+ isKey := true
+ k := 0
+ for i, c := range b {
+ switch c {
+ case '=':
+ if isKey {
+ isKey = false
+ kv.key = decodeCookieArg(kv.key, b[:i], false)
+ k = i + 1
+ }
+ case ';':
+ if isKey {
+ kv.key = kv.key[:0]
+ }
+ kv.value = decodeCookieArg(kv.value, b[k:i], true)
+ s.b = b[i+1:]
+ return true
+ }
+ }
+
+ if isKey {
+ kv.key = kv.key[:0]
+ }
+ kv.value = decodeCookieArg(kv.value, b[k:], true)
+ s.b = b[len(b):]
+ return true
+}
+
+func decodeCookieArg(dst, src []byte, skipQuotes bool) []byte {
+ for len(src) > 0 && src[0] == ' ' {
+ src = src[1:]
+ }
+ for len(src) > 0 && src[len(src)-1] == ' ' {
+ src = src[:len(src)-1]
+ }
+ if skipQuotes {
+ if len(src) > 1 && src[0] == '"' && src[len(src)-1] == '"' {
+ src = src[1 : len(src)-1]
+ }
+ }
+ return append(dst[:0], src...)
+}
+
+// caseInsensitiveCompare does a case insensitive equality comparison of
+// two []byte. Assumes only letters need to be matched.
+func caseInsensitiveCompare(a, b []byte) bool {
+ if len(a) != len(b) {
+ return false
+ }
+ for i := 0; i < len(a); i++ {
+ if a[i]|0x20 != b[i]|0x20 {
+ return false
+ }
+ }
+ return true
+}
diff --git a/vendor/github.com/valyala/fasthttp/doc.go b/vendor/github.com/valyala/fasthttp/doc.go
new file mode 100644
index 0000000..f2bf58d
--- /dev/null
+++ b/vendor/github.com/valyala/fasthttp/doc.go
@@ -0,0 +1,55 @@
+/*
+Package fasthttp provides fast HTTP server and client API.
+
+Fasthttp provides the following features:
+
+ 1. Optimized for speed. Easily handles more than 100K qps and more than 1M
+ concurrent keep-alive connections on modern hardware.
+
+ 2. Optimized for low memory usage.
+
+ 3. Easy 'Connection: Upgrade' support via RequestCtx.Hijack.
+
+ 4. Server provides the following anti-DoS limits:
+
+ - The number of concurrent connections.
+
+ - The number of concurrent connections per client IP.
+
+ - The number of requests per connection.
+
+ - Request read timeout.
+
+ - Response write timeout.
+
+ - Maximum request header size.
+
+ - Maximum request body size.
+
+ - Maximum request execution time.
+
+ - Maximum keep-alive connection lifetime.
+
+ - Early filtering out non-GET requests.
+
+ 5. A lot of additional useful info is exposed to request handler:
+
+ - Server and client address.
+
+ - Per-request logger.
+
+ - Unique request id.
+
+ - Request start time.
+
+ - Connection start time.
+
+ - Request sequence number for the current connection.
+
+ 6. Client supports automatic retry on idempotent requests' failure.
+
+ 7. Fasthttp API is designed with the ability to extend existing client
+ and server implementations or to write custom client and server
+ implementations from scratch.
+*/
+package fasthttp
diff --git a/vendor/github.com/valyala/fasthttp/fasthttputil/doc.go b/vendor/github.com/valyala/fasthttp/fasthttputil/doc.go
new file mode 100644
index 0000000..9cf69e7
--- /dev/null
+++ b/vendor/github.com/valyala/fasthttp/fasthttputil/doc.go
@@ -0,0 +1,2 @@
+// Package fasthttputil provides utility functions for fasthttp.
+package fasthttputil
diff --git a/vendor/github.com/valyala/fasthttp/fasthttputil/inmemory_listener.go b/vendor/github.com/valyala/fasthttp/fasthttputil/inmemory_listener.go
new file mode 100644
index 0000000..1aaa8e1
--- /dev/null
+++ b/vendor/github.com/valyala/fasthttp/fasthttputil/inmemory_listener.go
@@ -0,0 +1,134 @@
+package fasthttputil
+
+import (
+ "errors"
+ "net"
+ "sync"
+)
+
+// ErrInmemoryListenerClosed indicates that the InmemoryListener is already closed.
+var ErrInmemoryListenerClosed = errors.New("InmemoryListener is already closed: use of closed network connection")
+
+// InmemoryListener provides in-memory dialer<->net.Listener implementation.
+//
+// It may be used either for fast in-process client<->server communications
+// without network stack overhead or for client<->server tests.
+type InmemoryListener struct {
+ lock sync.Mutex
+ closed bool
+ conns chan acceptConn
+ listenerAddr net.Addr
+ addrLock sync.RWMutex
+}
+
+type acceptConn struct {
+ conn net.Conn
+ accepted chan struct{}
+}
+
+// NewInmemoryListener returns new in-memory dialer<->net.Listener.
+func NewInmemoryListener() *InmemoryListener {
+ return &InmemoryListener{
+ conns: make(chan acceptConn, 1024),
+ }
+}
+
+// SetLocalAddr sets the (simulated) local address for the listener.
+func (ln *InmemoryListener) SetLocalAddr(localAddr net.Addr) {
+ ln.addrLock.Lock()
+ defer ln.addrLock.Unlock()
+
+ ln.listenerAddr = localAddr
+}
+
+// Accept implements net.Listener's Accept.
+//
+// It is safe calling Accept from concurrently running goroutines.
+//
+// Accept returns new connection per each Dial call.
+func (ln *InmemoryListener) Accept() (net.Conn, error) {
+ c, ok := <-ln.conns
+ if !ok {
+ return nil, ErrInmemoryListenerClosed
+ }
+ close(c.accepted)
+ return c.conn, nil
+}
+
+// Close implements net.Listener's Close.
+func (ln *InmemoryListener) Close() error {
+ var err error
+
+ ln.lock.Lock()
+ if !ln.closed {
+ close(ln.conns)
+ ln.closed = true
+ } else {
+ err = ErrInmemoryListenerClosed
+ }
+ ln.lock.Unlock()
+ return err
+}
+
+type inmemoryAddr int
+
+func (inmemoryAddr) Network() string {
+ return "inmemory"
+}
+
+func (inmemoryAddr) String() string {
+ return "InmemoryListener"
+}
+
+// Addr implements net.Listener's Addr.
+func (ln *InmemoryListener) Addr() net.Addr {
+ ln.addrLock.RLock()
+ defer ln.addrLock.RUnlock()
+
+ if ln.listenerAddr != nil {
+ return ln.listenerAddr
+ }
+
+ return inmemoryAddr(0)
+}
+
+// Dial creates new client<->server connection.
+// Just like a real Dial it only returns once the server
+// has accepted the connection.
+//
+// It is safe calling Dial from concurrently running goroutines.
+func (ln *InmemoryListener) Dial() (net.Conn, error) {
+ return ln.DialWithLocalAddr(nil)
+}
+
+// DialWithLocalAddr creates new client<->server connection.
+// Just like a real Dial it only returns once the server
+// has accepted the connection. The local address of the
+// client connection can be set with local.
+//
+// It is safe calling Dial from concurrently running goroutines.
+func (ln *InmemoryListener) DialWithLocalAddr(local net.Addr) (net.Conn, error) {
+ pc := NewPipeConns()
+
+ pc.SetAddresses(local, ln.Addr(), ln.Addr(), local)
+
+ cConn := pc.Conn1()
+ sConn := pc.Conn2()
+ ln.lock.Lock()
+ accepted := make(chan struct{})
+ if !ln.closed {
+ ln.conns <- acceptConn{sConn, accepted}
+ // Wait until the connection has been accepted.
+ <-accepted
+ } else {
+ _ = sConn.Close()
+ _ = cConn.Close()
+ cConn = nil
+ }
+ ln.lock.Unlock()
+
+ if cConn == nil {
+ return nil, ErrInmemoryListenerClosed
+ }
+ return cConn, nil
+}
diff --git a/vendor/github.com/valyala/fasthttp/fasthttputil/pipeconns.go b/vendor/github.com/valyala/fasthttp/fasthttputil/pipeconns.go
new file mode 100644
index 0000000..4ec4130
--- /dev/null
+++ b/vendor/github.com/valyala/fasthttp/fasthttputil/pipeconns.go
@@ -0,0 +1,343 @@
+package fasthttputil
+
+import (
+ "errors"
+ "io"
+ "net"
+ "sync"
+ "time"
+)
+
+// NewPipeConns returns new bi-directional connection pipe.
+//
+// PipeConns is NOT safe for concurrent use by multiple goroutines!
+func NewPipeConns() *PipeConns {
+ ch1 := make(chan *byteBuffer, 4)
+ ch2 := make(chan *byteBuffer, 4)
+
+ pc := &PipeConns{
+ stopCh: make(chan struct{}),
+ }
+ pc.c1.rCh = ch1
+ pc.c1.wCh = ch2
+ pc.c2.rCh = ch2
+ pc.c2.wCh = ch1
+ pc.c1.pc = pc
+ pc.c2.pc = pc
+ return pc
+}
+
+// PipeConns provides bi-directional connection pipe,
+// which use in-process memory as a transport.
+//
+// PipeConns must be created by calling NewPipeConns.
+//
+// PipeConns has the following additional features comparing to connections
+// returned from net.Pipe():
+//
+// - It is faster.
+// - It buffers Write calls, so there is no need to have concurrent goroutine
+// calling Read in order to unblock each Write call.
+// - It supports read and write deadlines.
+//
+// PipeConns is NOT safe for concurrent use by multiple goroutines!
+type PipeConns struct {
+ c1 pipeConn
+ c2 pipeConn
+ stopCh chan struct{}
+ stopChLock sync.Mutex
+}
+
+// SetAddresses sets the local and remote addresses for the connection.
+func (pc *PipeConns) SetAddresses(localAddr1, remoteAddr1, localAddr2, remoteAddr2 net.Addr) {
+ pc.c1.addrLock.Lock()
+ defer pc.c1.addrLock.Unlock()
+
+ pc.c2.addrLock.Lock()
+ defer pc.c2.addrLock.Unlock()
+
+ pc.c1.localAddr = localAddr1
+ pc.c1.remoteAddr = remoteAddr1
+
+ pc.c2.localAddr = localAddr2
+ pc.c2.remoteAddr = remoteAddr2
+}
+
+// Conn1 returns the first end of bi-directional pipe.
+//
+// Data written to Conn1 may be read from Conn2.
+// Data written to Conn2 may be read from Conn1.
+func (pc *PipeConns) Conn1() net.Conn {
+ return &pc.c1
+}
+
+// Conn2 returns the second end of bi-directional pipe.
+//
+// Data written to Conn2 may be read from Conn1.
+// Data written to Conn1 may be read from Conn2.
+func (pc *PipeConns) Conn2() net.Conn {
+ return &pc.c2
+}
+
+// Close closes pipe connections.
+func (pc *PipeConns) Close() error {
+ pc.stopChLock.Lock()
+ select {
+ case <-pc.stopCh:
+ default:
+ close(pc.stopCh)
+ }
+ pc.stopChLock.Unlock()
+
+ return nil
+}
+
+type pipeConn struct {
+ b *byteBuffer
+ bb []byte
+
+ rCh chan *byteBuffer
+ wCh chan *byteBuffer
+ pc *PipeConns
+
+ readDeadlineTimer *time.Timer
+ writeDeadlineTimer *time.Timer
+
+ readDeadlineCh <-chan time.Time
+ writeDeadlineCh <-chan time.Time
+
+ readDeadlineChLock sync.Mutex
+
+ localAddr net.Addr
+ remoteAddr net.Addr
+ addrLock sync.RWMutex
+}
+
+func (c *pipeConn) Write(p []byte) (int, error) {
+ b := acquireByteBuffer()
+ b.b = append(b.b[:0], p...)
+
+ select {
+ case <-c.pc.stopCh:
+ releaseByteBuffer(b)
+ return 0, errConnectionClosed
+ default:
+ }
+
+ select {
+ case c.wCh <- b:
+ default:
+ select {
+ case c.wCh <- b:
+ case <-c.writeDeadlineCh:
+ c.writeDeadlineCh = closedDeadlineCh
+ return 0, ErrTimeout
+ case <-c.pc.stopCh:
+ releaseByteBuffer(b)
+ return 0, errConnectionClosed
+ }
+ }
+
+ return len(p), nil
+}
+
+func (c *pipeConn) Read(p []byte) (int, error) {
+ mayBlock := true
+ nn := 0
+ for len(p) > 0 {
+ n, err := c.read(p, mayBlock)
+ nn += n
+ if err != nil {
+ if !mayBlock && err == errWouldBlock {
+ err = nil
+ }
+ return nn, err
+ }
+ p = p[n:]
+ mayBlock = false
+ }
+
+ return nn, nil
+}
+
+func (c *pipeConn) read(p []byte, mayBlock bool) (int, error) {
+ if len(c.bb) == 0 {
+ if err := c.readNextByteBuffer(mayBlock); err != nil {
+ return 0, err
+ }
+ }
+ n := copy(p, c.bb)
+ c.bb = c.bb[n:]
+
+ return n, nil
+}
+
+func (c *pipeConn) readNextByteBuffer(mayBlock bool) error {
+ releaseByteBuffer(c.b)
+ c.b = nil
+
+ select {
+ case c.b = <-c.rCh:
+ default:
+ if !mayBlock {
+ return errWouldBlock
+ }
+ c.readDeadlineChLock.Lock()
+ readDeadlineCh := c.readDeadlineCh
+ c.readDeadlineChLock.Unlock()
+ select {
+ case c.b = <-c.rCh:
+ case <-readDeadlineCh:
+ c.readDeadlineChLock.Lock()
+ c.readDeadlineCh = closedDeadlineCh
+ c.readDeadlineChLock.Unlock()
+ // rCh may contain data when deadline is reached.
+ // Read the data before returning ErrTimeout.
+ select {
+ case c.b = <-c.rCh:
+ default:
+ return ErrTimeout
+ }
+ case <-c.pc.stopCh:
+ // rCh may contain data when stopCh is closed.
+ // Read the data before returning EOF.
+ select {
+ case c.b = <-c.rCh:
+ default:
+ return io.EOF
+ }
+ }
+ }
+
+ c.bb = c.b.b
+ return nil
+}
+
+var (
+ errWouldBlock = errors.New("would block")
+ errConnectionClosed = errors.New("connection closed")
+)
+
+type timeoutError struct{}
+
+func (e *timeoutError) Error() string {
+ return "timeout"
+}
+
+// Only implement the Timeout() function of the net.Error interface.
+// This allows for checks like:
+//
+// if x, ok := err.(interface{ Timeout() bool }); ok && x.Timeout() {
+func (e *timeoutError) Timeout() bool {
+ return true
+}
+
+// ErrTimeout is returned from Read() or Write() on timeout.
+var ErrTimeout = &timeoutError{}
+
+func (c *pipeConn) Close() error {
+ return c.pc.Close()
+}
+
+func (c *pipeConn) LocalAddr() net.Addr {
+ c.addrLock.RLock()
+ defer c.addrLock.RUnlock()
+
+ if c.localAddr != nil {
+ return c.localAddr
+ }
+
+ return pipeAddr(0)
+}
+
+func (c *pipeConn) RemoteAddr() net.Addr {
+ c.addrLock.RLock()
+ defer c.addrLock.RUnlock()
+
+ if c.remoteAddr != nil {
+ return c.remoteAddr
+ }
+
+ return pipeAddr(0)
+}
+
+func (c *pipeConn) SetDeadline(deadline time.Time) error {
+ c.SetReadDeadline(deadline) //nolint:errcheck
+ c.SetWriteDeadline(deadline) //nolint:errcheck
+ return nil
+}
+
+func (c *pipeConn) SetReadDeadline(deadline time.Time) error {
+ if c.readDeadlineTimer == nil {
+ c.readDeadlineTimer = time.NewTimer(time.Hour)
+ }
+ readDeadlineCh := updateTimer(c.readDeadlineTimer, deadline)
+ c.readDeadlineChLock.Lock()
+ c.readDeadlineCh = readDeadlineCh
+ c.readDeadlineChLock.Unlock()
+ return nil
+}
+
+func (c *pipeConn) SetWriteDeadline(deadline time.Time) error {
+ if c.writeDeadlineTimer == nil {
+ c.writeDeadlineTimer = time.NewTimer(time.Hour)
+ }
+ c.writeDeadlineCh = updateTimer(c.writeDeadlineTimer, deadline)
+ return nil
+}
+
+func updateTimer(t *time.Timer, deadline time.Time) <-chan time.Time {
+ if !t.Stop() {
+ select {
+ case <-t.C:
+ default:
+ }
+ }
+ if deadline.IsZero() {
+ return nil
+ }
+ d := time.Until(deadline)
+ if d <= 0 {
+ return closedDeadlineCh
+ }
+ t.Reset(d)
+ return t.C
+}
+
+var closedDeadlineCh = func() <-chan time.Time {
+ ch := make(chan time.Time)
+ close(ch)
+ return ch
+}()
+
+type pipeAddr int
+
+func (pipeAddr) Network() string {
+ return "pipe"
+}
+
+func (pipeAddr) String() string {
+ return "pipe"
+}
+
+type byteBuffer struct {
+ b []byte
+}
+
+func acquireByteBuffer() *byteBuffer {
+ return byteBufferPool.Get().(*byteBuffer)
+}
+
+func releaseByteBuffer(b *byteBuffer) {
+ if b != nil {
+ byteBufferPool.Put(b)
+ }
+}
+
+var byteBufferPool = &sync.Pool{
+ New: func() interface{} {
+ return &byteBuffer{
+ b: make([]byte, 1024),
+ }
+ },
+}
diff --git a/vendor/github.com/valyala/fasthttp/fs.go b/vendor/github.com/valyala/fasthttp/fs.go
new file mode 100644
index 0000000..c231d80
--- /dev/null
+++ b/vendor/github.com/valyala/fasthttp/fs.go
@@ -0,0 +1,1707 @@
+package fasthttp
+
+import (
+ "bytes"
+ "errors"
+ "fmt"
+ "html"
+ "io"
+ "io/fs"
+ "mime"
+ "net/http"
+ "os"
+ "path/filepath"
+ "sort"
+ "strings"
+ "sync"
+ "time"
+
+ "github.com/andybalholm/brotli"
+ "github.com/klauspost/compress/gzip"
+ "github.com/valyala/bytebufferpool"
+)
+
+// ServeFileBytesUncompressed returns HTTP response containing file contents
+// from the given path.
+//
+// Directory contents is returned if path points to directory.
+//
+// ServeFileBytes may be used for saving network traffic when serving files
+// with good compression ratio.
+//
+// See also RequestCtx.SendFileBytes.
+//
+// WARNING: do not pass any user supplied paths to this function!
+// WARNING: if path is based on user input users will be able to request
+// any file on your filesystem! Use fasthttp.FS with a sane Root instead.
+func ServeFileBytesUncompressed(ctx *RequestCtx, path []byte) {
+ ServeFileUncompressed(ctx, b2s(path))
+}
+
+// ServeFileUncompressed returns HTTP response containing file contents
+// from the given path.
+//
+// Directory contents is returned if path points to directory.
+//
+// ServeFile may be used for saving network traffic when serving files
+// with good compression ratio.
+//
+// See also RequestCtx.SendFile.
+//
+// WARNING: do not pass any user supplied paths to this function!
+// WARNING: if path is based on user input users will be able to request
+// any file on your filesystem! Use fasthttp.FS with a sane Root instead.
+func ServeFileUncompressed(ctx *RequestCtx, path string) {
+ ctx.Request.Header.DelBytes(strAcceptEncoding)
+ ServeFile(ctx, path)
+}
+
+// ServeFileBytes returns HTTP response containing compressed file contents
+// from the given path.
+//
+// HTTP response may contain uncompressed file contents in the following cases:
+//
+// - Missing 'Accept-Encoding: gzip' request header.
+// - No write access to directory containing the file.
+//
+// Directory contents is returned if path points to directory.
+//
+// Use ServeFileBytesUncompressed is you don't need serving compressed
+// file contents.
+//
+// See also RequestCtx.SendFileBytes.
+//
+// WARNING: do not pass any user supplied paths to this function!
+// WARNING: if path is based on user input users will be able to request
+// any file on your filesystem! Use fasthttp.FS with a sane Root instead.
+func ServeFileBytes(ctx *RequestCtx, path []byte) {
+ ServeFile(ctx, b2s(path))
+}
+
+// ServeFile returns HTTP response containing compressed file contents
+// from the given path.
+//
+// HTTP response may contain uncompressed file contents in the following cases:
+//
+// - Missing 'Accept-Encoding: gzip' request header.
+// - No write access to directory containing the file.
+//
+// Directory contents is returned if path points to directory.
+//
+// Use ServeFileUncompressed is you don't need serving compressed file contents.
+//
+// See also RequestCtx.SendFile.
+//
+// WARNING: do not pass any user supplied paths to this function!
+// WARNING: if path is based on user input users will be able to request
+// any file on your filesystem! Use fasthttp.FS with a sane Root instead.
+func ServeFile(ctx *RequestCtx, path string) {
+ rootFSOnce.Do(func() {
+ rootFSHandler = rootFS.NewRequestHandler()
+ })
+
+ if len(path) == 0 || !filepath.IsAbs(path) {
+ // extend relative path to absolute path
+ hasTrailingSlash := len(path) > 0 && (path[len(path)-1] == '/' || path[len(path)-1] == '\\')
+
+ var err error
+ path = filepath.FromSlash(path)
+ if path, err = filepath.Abs(path); err != nil {
+ ctx.Logger().Printf("cannot resolve path %q to absolute file path: %v", path, err)
+ ctx.Error("Internal Server Error", StatusInternalServerError)
+ return
+ }
+ if hasTrailingSlash {
+ path += "/"
+ }
+ }
+
+ // convert the path to forward slashes regardless the OS in order to set the URI properly
+ // the handler will convert back to OS path separator before opening the file
+ path = filepath.ToSlash(path)
+
+ ctx.Request.SetRequestURI(path)
+ rootFSHandler(ctx)
+}
+
+var (
+ rootFSOnce sync.Once
+ rootFS = &FS{
+ Root: "",
+ AllowEmptyRoot: true,
+ GenerateIndexPages: true,
+ Compress: true,
+ CompressBrotli: true,
+ AcceptByteRange: true,
+ }
+ rootFSHandler RequestHandler
+)
+
+// ServeFS returns HTTP response containing compressed file contents from the given fs.FS's path.
+//
+// HTTP response may contain uncompressed file contents in the following cases:
+//
+// - Missing 'Accept-Encoding: gzip' request header.
+// - No write access to directory containing the file.
+//
+// Directory contents is returned if path points to directory.
+//
+// See also ServeFile.
+func ServeFS(ctx *RequestCtx, filesystem fs.FS, path string) {
+ f := &FS{
+ FS: filesystem,
+ Root: "",
+ AllowEmptyRoot: true,
+ GenerateIndexPages: true,
+ Compress: true,
+ CompressBrotli: true,
+ AcceptByteRange: true,
+ }
+ handler := f.NewRequestHandler()
+
+ ctx.Request.SetRequestURI(path)
+ handler(ctx)
+}
+
+// PathRewriteFunc must return new request path based on arbitrary ctx
+// info such as ctx.Path().
+//
+// Path rewriter is used in FS for translating the current request
+// to the local filesystem path relative to FS.Root.
+//
+// The returned path must not contain '/../' substrings due to security reasons,
+// since such paths may refer files outside FS.Root.
+//
+// The returned path may refer to ctx members. For example, ctx.Path().
+type PathRewriteFunc func(ctx *RequestCtx) []byte
+
+// NewVHostPathRewriter returns path rewriter, which strips slashesCount
+// leading slashes from the path and prepends the path with request's host,
+// thus simplifying virtual hosting for static files.
+//
+// Examples:
+//
+// - host=foobar.com, slashesCount=0, original path="/foo/bar".
+// Resulting path: "/foobar.com/foo/bar"
+//
+// - host=img.aaa.com, slashesCount=1, original path="/images/123/456.jpg"
+// Resulting path: "/img.aaa.com/123/456.jpg"
+func NewVHostPathRewriter(slashesCount int) PathRewriteFunc {
+ return func(ctx *RequestCtx) []byte {
+ path := stripLeadingSlashes(ctx.Path(), slashesCount)
+ host := ctx.Host()
+ if n := bytes.IndexByte(host, '/'); n >= 0 {
+ host = nil
+ }
+ if len(host) == 0 {
+ host = strInvalidHost
+ }
+ b := bytebufferpool.Get()
+ b.B = append(b.B, '/')
+ b.B = append(b.B, host...)
+ b.B = append(b.B, path...)
+ ctx.URI().SetPathBytes(b.B)
+ bytebufferpool.Put(b)
+
+ return ctx.Path()
+ }
+}
+
+var strInvalidHost = []byte("invalid-host")
+
+// NewPathSlashesStripper returns path rewriter, which strips slashesCount
+// leading slashes from the path.
+//
+// Examples:
+//
+// - slashesCount = 0, original path: "/foo/bar", result: "/foo/bar"
+// - slashesCount = 1, original path: "/foo/bar", result: "/bar"
+// - slashesCount = 2, original path: "/foo/bar", result: ""
+//
+// The returned path rewriter may be used as FS.PathRewrite .
+func NewPathSlashesStripper(slashesCount int) PathRewriteFunc {
+ return func(ctx *RequestCtx) []byte {
+ return stripLeadingSlashes(ctx.Path(), slashesCount)
+ }
+}
+
+// NewPathPrefixStripper returns path rewriter, which removes prefixSize bytes
+// from the path prefix.
+//
+// Examples:
+//
+// - prefixSize = 0, original path: "/foo/bar", result: "/foo/bar"
+// - prefixSize = 3, original path: "/foo/bar", result: "o/bar"
+// - prefixSize = 7, original path: "/foo/bar", result: "r"
+//
+// The returned path rewriter may be used as FS.PathRewrite .
+func NewPathPrefixStripper(prefixSize int) PathRewriteFunc {
+ return func(ctx *RequestCtx) []byte {
+ path := ctx.Path()
+ if len(path) >= prefixSize {
+ path = path[prefixSize:]
+ }
+ return path
+ }
+}
+
+// FS represents settings for request handler serving static files
+// from the local filesystem.
+//
+// It is prohibited copying FS values. Create new values instead.
+type FS struct {
+ noCopy noCopy
+
+ // FS is filesystem to serve files from. eg: embed.FS os.DirFS
+ FS fs.FS
+
+ // Path to the root directory to serve files from.
+ Root string
+
+ // AllowEmptyRoot controls what happens when Root is empty. When false (default) it will default to the
+ // current working directory. An empty root is mostly useful when you want to use absolute paths
+ // on windows that are on different filesystems. On linux setting your Root to "/" already allows you to use
+ // absolute paths on any filesystem.
+ AllowEmptyRoot bool
+
+ // List of index file names to try opening during directory access.
+ //
+ // For example:
+ //
+ // * index.html
+ // * index.htm
+ // * my-super-index.xml
+ //
+ // By default the list is empty.
+ IndexNames []string
+
+ // Index pages for directories without files matching IndexNames
+ // are automatically generated if set.
+ //
+ // Directory index generation may be quite slow for directories
+ // with many files (more than 1K), so it is discouraged enabling
+ // index pages' generation for such directories.
+ //
+ // By default index pages aren't generated.
+ GenerateIndexPages bool
+
+ // Transparently compresses responses if set to true.
+ //
+ // The server tries minimizing CPU usage by caching compressed files.
+ // It adds CompressedFileSuffix suffix to the original file name and
+ // tries saving the resulting compressed file under the new file name.
+ // So it is advisable to give the server write access to Root
+ // and to all inner folders in order to minimize CPU usage when serving
+ // compressed responses.
+ //
+ // Transparent compression is disabled by default.
+ Compress bool
+
+ // Uses brotli encoding and fallbacks to gzip in responses if set to true, uses gzip if set to false.
+ //
+ // This value has sense only if Compress is set.
+ //
+ // Brotli encoding is disabled by default.
+ CompressBrotli bool
+
+ // Path to the compressed root directory to serve files from. If this value
+ // is empty, Root is used.
+ CompressRoot string
+
+ // Enables byte range requests if set to true.
+ //
+ // Byte range requests are disabled by default.
+ AcceptByteRange bool
+
+ // Path rewriting function.
+ //
+ // By default request path is not modified.
+ PathRewrite PathRewriteFunc
+
+ // PathNotFound fires when file is not found in filesystem
+ // this functions tries to replace "Cannot open requested path"
+ // server response giving to the programmer the control of server flow.
+ //
+ // By default PathNotFound returns
+ // "Cannot open requested path"
+ PathNotFound RequestHandler
+
+ // SkipCache if true, will cache no file handler.
+ //
+ // By default is false.
+ SkipCache bool
+
+ // Expiration duration for inactive file handlers.
+ //
+ // FSHandlerCacheDuration is used by default.
+ CacheDuration time.Duration
+
+ // Suffix to add to the name of cached compressed file.
+ //
+ // This value has sense only if Compress is set.
+ //
+ // FSCompressedFileSuffix is used by default.
+ CompressedFileSuffix string
+
+ // Suffixes list to add to compressedFileSuffix depending on encoding
+ //
+ // This value has sense only if Compress is set.
+ //
+ // FSCompressedFileSuffixes is used by default.
+ CompressedFileSuffixes map[string]string
+
+ // If CleanStop is set, the channel can be closed to stop the cleanup handlers
+ // for the FS RequestHandlers created with NewRequestHandler.
+ // NEVER close this channel while the handler is still being used!
+ CleanStop chan struct{}
+
+ once sync.Once
+ h RequestHandler
+}
+
+// FSCompressedFileSuffix is the suffix FS adds to the original file names
+// when trying to store compressed file under the new file name.
+// See FS.Compress for details.
+const FSCompressedFileSuffix = ".fasthttp.gz"
+
+// FSCompressedFileSuffixes is the suffixes FS adds to the original file names depending on encoding
+// when trying to store compressed file under the new file name.
+// See FS.Compress for details.
+var FSCompressedFileSuffixes = map[string]string{
+ "gzip": ".fasthttp.gz",
+ "br": ".fasthttp.br",
+}
+
+// FSHandlerCacheDuration is the default expiration duration for inactive
+// file handlers opened by FS.
+const FSHandlerCacheDuration = 10 * time.Second
+
+// FSHandler returns request handler serving static files from
+// the given root folder.
+//
+// stripSlashes indicates how many leading slashes must be stripped
+// from requested path before searching requested file in the root folder.
+// Examples:
+//
+// - stripSlashes = 0, original path: "/foo/bar", result: "/foo/bar"
+// - stripSlashes = 1, original path: "/foo/bar", result: "/bar"
+// - stripSlashes = 2, original path: "/foo/bar", result: ""
+//
+// The returned request handler automatically generates index pages
+// for directories without index.html.
+//
+// The returned handler caches requested file handles
+// for FSHandlerCacheDuration.
+// Make sure your program has enough 'max open files' limit aka
+// 'ulimit -n' if root folder contains many files.
+//
+// Do not create multiple request handler instances for the same
+// (root, stripSlashes) arguments - just reuse a single instance.
+// Otherwise goroutine leak will occur.
+func FSHandler(root string, stripSlashes int) RequestHandler {
+ fs := &FS{
+ Root: root,
+ IndexNames: []string{"index.html"},
+ GenerateIndexPages: true,
+ AcceptByteRange: true,
+ }
+ if stripSlashes > 0 {
+ fs.PathRewrite = NewPathSlashesStripper(stripSlashes)
+ }
+ return fs.NewRequestHandler()
+}
+
+// NewRequestHandler returns new request handler with the given FS settings.
+//
+// The returned handler caches requested file handles
+// for FS.CacheDuration.
+// Make sure your program has enough 'max open files' limit aka
+// 'ulimit -n' if FS.Root folder contains many files.
+//
+// Do not create multiple request handlers from a single FS instance -
+// just reuse a single request handler.
+func (fs *FS) NewRequestHandler() RequestHandler {
+ fs.once.Do(fs.initRequestHandler)
+ return fs.h
+}
+
+func (fs *FS) normalizeRoot(root string) string {
+ // fs.FS uses relative paths, that paths are slash-separated on all systems, even Windows.
+ if fs.FS == nil {
+ // Serve files from the current working directory if Root is empty or if Root is a relative path.
+ if (!fs.AllowEmptyRoot && len(root) == 0) || (len(root) > 0 && !filepath.IsAbs(root)) {
+ path, err := os.Getwd()
+ if err != nil {
+ path = "."
+ }
+ root = path + "/" + root
+ }
+
+ // convert the root directory slashes to the native format
+ root = filepath.FromSlash(root)
+ }
+
+ // strip trailing slashes from the root path
+ for len(root) > 0 && root[len(root)-1] == os.PathSeparator {
+ root = root[:len(root)-1]
+ }
+ return root
+}
+
+func (fs *FS) initRequestHandler() {
+ root := fs.normalizeRoot(fs.Root)
+
+ compressRoot := fs.CompressRoot
+ if len(compressRoot) == 0 {
+ compressRoot = root
+ } else {
+ compressRoot = fs.normalizeRoot(compressRoot)
+ }
+
+ compressedFileSuffixes := fs.CompressedFileSuffixes
+ if len(compressedFileSuffixes["br"]) == 0 || len(compressedFileSuffixes["gzip"]) == 0 ||
+ compressedFileSuffixes["br"] == compressedFileSuffixes["gzip"] {
+ // Copy global map
+ compressedFileSuffixes = make(map[string]string, len(FSCompressedFileSuffixes))
+ for k, v := range FSCompressedFileSuffixes {
+ compressedFileSuffixes[k] = v
+ }
+ }
+
+ if len(fs.CompressedFileSuffix) > 0 {
+ compressedFileSuffixes["gzip"] = fs.CompressedFileSuffix
+ compressedFileSuffixes["br"] = FSCompressedFileSuffixes["br"]
+ }
+
+ h := &fsHandler{
+ filesystem: fs.FS,
+ root: root,
+ indexNames: fs.IndexNames,
+ pathRewrite: fs.PathRewrite,
+ generateIndexPages: fs.GenerateIndexPages,
+ compress: fs.Compress,
+ compressBrotli: fs.CompressBrotli,
+ compressRoot: compressRoot,
+ pathNotFound: fs.PathNotFound,
+ acceptByteRange: fs.AcceptByteRange,
+ compressedFileSuffixes: compressedFileSuffixes,
+ }
+
+ h.cacheManager = newCacheManager(fs)
+
+ if h.filesystem == nil {
+ h.filesystem = &osFS{} // It provides os.Open and os.Stat
+ }
+
+ fs.h = h.handleRequest
+}
+
+type fsHandler struct {
+ filesystem fs.FS
+ root string
+ indexNames []string
+ pathRewrite PathRewriteFunc
+ pathNotFound RequestHandler
+ generateIndexPages bool
+ compress bool
+ compressBrotli bool
+ compressRoot string
+ acceptByteRange bool
+ compressedFileSuffixes map[string]string
+
+ cacheManager cacheManager
+
+ smallFileReaderPool sync.Pool
+}
+
+type fsFile struct {
+ h *fsHandler
+ f fs.File
+ filename string // fs.FileInfo.Name() return filename, isn't filepath.
+ dirIndex []byte
+ contentType string
+ contentLength int
+ compressed bool
+
+ lastModified time.Time
+ lastModifiedStr []byte
+
+ t time.Time
+ readersCount int
+
+ bigFiles []*bigFileReader
+ bigFilesLock sync.Mutex
+}
+
+func (ff *fsFile) NewReader() (io.Reader, error) {
+ if ff.isBig() {
+ r, err := ff.bigFileReader()
+ if err != nil {
+ ff.decReadersCount()
+ }
+ return r, err
+ }
+ return ff.smallFileReader()
+}
+
+func (ff *fsFile) smallFileReader() (io.Reader, error) {
+ v := ff.h.smallFileReaderPool.Get()
+ if v == nil {
+ v = &fsSmallFileReader{}
+ }
+ r := v.(*fsSmallFileReader)
+ r.ff = ff
+ r.endPos = ff.contentLength
+ if r.startPos > 0 {
+ return nil, errors.New("bug: fsSmallFileReader with non-nil startPos found in the pool")
+ }
+ return r, nil
+}
+
+// files bigger than this size are sent with sendfile
+const maxSmallFileSize = 2 * 4096
+
+func (ff *fsFile) isBig() bool {
+ if _, ok := ff.h.filesystem.(*osFS); !ok { // fs.FS only uses bigFileReader, memory cache uses fsSmallFileReader
+ return ff.f != nil
+ }
+ return ff.contentLength > maxSmallFileSize && len(ff.dirIndex) == 0
+}
+
+func (ff *fsFile) bigFileReader() (io.Reader, error) {
+ if ff.f == nil {
+ return nil, errors.New("bug: ff.f must be non-nil in bigFileReader")
+ }
+
+ var r io.Reader
+
+ ff.bigFilesLock.Lock()
+ n := len(ff.bigFiles)
+ if n > 0 {
+ r = ff.bigFiles[n-1]
+ ff.bigFiles = ff.bigFiles[:n-1]
+ }
+ ff.bigFilesLock.Unlock()
+
+ if r != nil {
+ return r, nil
+ }
+
+ f, err := ff.h.filesystem.Open(ff.filename)
+ if err != nil {
+ return nil, fmt.Errorf("cannot open already opened file: %w", err)
+ }
+ return &bigFileReader{
+ f: f,
+ ff: ff,
+ r: f,
+ }, nil
+}
+
+func (ff *fsFile) Release() {
+ if ff.f != nil {
+ _ = ff.f.Close()
+
+ if ff.isBig() {
+ ff.bigFilesLock.Lock()
+ for _, r := range ff.bigFiles {
+ _ = r.f.Close()
+ }
+ ff.bigFilesLock.Unlock()
+ }
+ }
+}
+
+func (ff *fsFile) decReadersCount() {
+ ff.h.cacheManager.WithLock(func() {
+ ff.readersCount--
+ if ff.readersCount < 0 {
+ ff.readersCount = 0
+ }
+ })
+}
+
+// bigFileReader attempts to trigger sendfile
+// for sending big files over the wire.
+type bigFileReader struct {
+ f fs.File
+ ff *fsFile
+ r io.Reader
+ lr io.LimitedReader
+}
+
+func (r *bigFileReader) UpdateByteRange(startPos, endPos int) error {
+ seeker, ok := r.f.(io.Seeker)
+ if !ok {
+ return errors.New("must implement io.Seeker")
+ }
+ if _, err := seeker.Seek(int64(startPos), io.SeekStart); err != nil {
+ return err
+ }
+ r.r = &r.lr
+ r.lr.R = r.f
+ r.lr.N = int64(endPos - startPos + 1)
+ return nil
+}
+
+func (r *bigFileReader) Read(p []byte) (int, error) {
+ return r.r.Read(p)
+}
+
+func (r *bigFileReader) WriteTo(w io.Writer) (int64, error) {
+ if rf, ok := w.(io.ReaderFrom); ok {
+ // fast path. Send file must be triggered
+ return rf.ReadFrom(r.r)
+ }
+
+ // slow path
+ return copyZeroAlloc(w, r.r)
+}
+
+func (r *bigFileReader) Close() error {
+ r.r = r.f
+ seeker, ok := r.f.(io.Seeker)
+ if !ok {
+ _ = r.f.Close()
+ return errors.New("must implement io.Seeker")
+ }
+ n, err := seeker.Seek(0, io.SeekStart)
+ if err == nil {
+ if n == 0 {
+ ff := r.ff
+ ff.bigFilesLock.Lock()
+ ff.bigFiles = append(ff.bigFiles, r)
+ ff.bigFilesLock.Unlock()
+ } else {
+ _ = r.f.Close()
+ err = errors.New("bug: File.Seek(0, io.SeekStart) returned (non-zero, nil)")
+ }
+ } else {
+ _ = r.f.Close()
+ }
+ r.ff.decReadersCount()
+ return err
+}
+
+type fsSmallFileReader struct {
+ ff *fsFile
+ startPos int
+ endPos int
+}
+
+func (r *fsSmallFileReader) Close() error {
+ ff := r.ff
+ ff.decReadersCount()
+ r.ff = nil
+ r.startPos = 0
+ r.endPos = 0
+ ff.h.smallFileReaderPool.Put(r)
+ return nil
+}
+
+func (r *fsSmallFileReader) UpdateByteRange(startPos, endPos int) error {
+ r.startPos = startPos
+ r.endPos = endPos + 1
+ return nil
+}
+
+func (r *fsSmallFileReader) Read(p []byte) (int, error) {
+ tailLen := r.endPos - r.startPos
+ if tailLen <= 0 {
+ return 0, io.EOF
+ }
+ if len(p) > tailLen {
+ p = p[:tailLen]
+ }
+
+ ff := r.ff
+ if ff.f != nil {
+ ra, ok := ff.f.(io.ReaderAt)
+ if !ok {
+ return 0, errors.New("must implement io.ReaderAt")
+ }
+ n, err := ra.ReadAt(p, int64(r.startPos))
+ r.startPos += n
+ return n, err
+ }
+
+ n := copy(p, ff.dirIndex[r.startPos:])
+ r.startPos += n
+ return n, nil
+}
+
+func (r *fsSmallFileReader) WriteTo(w io.Writer) (int64, error) {
+ ff := r.ff
+
+ var n int
+ var err error
+ if ff.f == nil {
+ n, err = w.Write(ff.dirIndex[r.startPos:r.endPos])
+ return int64(n), err
+ }
+
+ if rf, ok := w.(io.ReaderFrom); ok {
+ return rf.ReadFrom(r)
+ }
+
+ curPos := r.startPos
+ bufv := copyBufPool.Get()
+ buf := bufv.([]byte)
+ for err == nil {
+ tailLen := r.endPos - curPos
+ if tailLen <= 0 {
+ break
+ }
+ if len(buf) > tailLen {
+ buf = buf[:tailLen]
+ }
+ ra, ok := ff.f.(io.ReaderAt)
+ if !ok {
+ return 0, errors.New("must implement io.ReaderAt")
+ }
+ n, err = ra.ReadAt(buf, int64(curPos))
+ nw, errw := w.Write(buf[:n])
+ curPos += nw
+ if errw == nil && nw != n {
+ errw = errors.New("bug: Write(p) returned (n, nil), where n != len(p)")
+ }
+ if err == nil {
+ err = errw
+ }
+ }
+ copyBufPool.Put(bufv)
+
+ if err == io.EOF {
+ err = nil
+ }
+ return int64(curPos - r.startPos), err
+}
+
+type cacheManager interface {
+ WithLock(work func())
+ GetFileFromCache(cacheKind CacheKind, path string) (*fsFile, bool)
+ SetFileToCache(cacheKind CacheKind, path string, ff *fsFile) *fsFile
+}
+
+var (
+ _ cacheManager = (*inMemoryCacheManager)(nil)
+ _ cacheManager = (*noopCacheManager)(nil)
+)
+
+type CacheKind uint8
+
+const (
+ defaultCacheKind CacheKind = iota
+ brotliCacheKind
+ gzipCacheKind
+)
+
+func newCacheManager(fs *FS) cacheManager {
+ if fs.SkipCache {
+ return &noopCacheManager{}
+ }
+
+ cacheDuration := fs.CacheDuration
+ if cacheDuration <= 0 {
+ cacheDuration = FSHandlerCacheDuration
+ }
+
+ instance := &inMemoryCacheManager{
+ cacheDuration: cacheDuration,
+ cache: make(map[string]*fsFile),
+ cacheBrotli: make(map[string]*fsFile),
+ cacheGzip: make(map[string]*fsFile),
+ }
+
+ go instance.handleCleanCache(fs.CleanStop)
+
+ return instance
+}
+
+type noopCacheManager struct {
+ cacheLock sync.Mutex
+}
+
+func (n *noopCacheManager) WithLock(work func()) {
+ n.cacheLock.Lock()
+
+ work()
+
+ n.cacheLock.Unlock()
+}
+
+func (*noopCacheManager) GetFileFromCache(cacheKind CacheKind, path string) (*fsFile, bool) {
+ return nil, false
+}
+
+func (*noopCacheManager) SetFileToCache(cacheKind CacheKind, path string, ff *fsFile) *fsFile {
+ return ff
+}
+
+type inMemoryCacheManager struct {
+ cacheDuration time.Duration
+ cache map[string]*fsFile
+ cacheBrotli map[string]*fsFile
+ cacheGzip map[string]*fsFile
+ cacheLock sync.Mutex
+}
+
+func (cm *inMemoryCacheManager) WithLock(work func()) {
+ cm.cacheLock.Lock()
+
+ work()
+
+ cm.cacheLock.Unlock()
+}
+
+func (cm *inMemoryCacheManager) getFsCache(cacheKind CacheKind) map[string]*fsFile {
+ fileCache := cm.cache
+ switch cacheKind {
+ case brotliCacheKind:
+ fileCache = cm.cacheBrotli
+ case gzipCacheKind:
+ fileCache = cm.cacheGzip
+ }
+
+ return fileCache
+}
+
+func (cm *inMemoryCacheManager) GetFileFromCache(cacheKind CacheKind, path string) (*fsFile, bool) {
+ fileCache := cm.getFsCache(cacheKind)
+
+ cm.cacheLock.Lock()
+ ff, ok := fileCache[path]
+ if ok {
+ ff.readersCount++
+ }
+ cm.cacheLock.Unlock()
+
+ return ff, ok
+}
+
+func (cm *inMemoryCacheManager) SetFileToCache(cacheKind CacheKind, path string, ff *fsFile) *fsFile {
+ fileCache := cm.getFsCache(cacheKind)
+
+ cm.cacheLock.Lock()
+ ff1, ok := fileCache[path]
+ if !ok {
+ fileCache[path] = ff
+ ff.readersCount++
+ } else {
+ ff1.readersCount++
+ }
+ cm.cacheLock.Unlock()
+
+ if ok {
+ // The file has been already opened by another
+ // goroutine, so close the current file and use
+ // the file opened by another goroutine instead.
+ ff.Release()
+ ff = ff1
+ }
+
+ return ff
+}
+
+func (cm *inMemoryCacheManager) handleCleanCache(cleanStop chan struct{}) {
+ var pendingFiles []*fsFile
+
+ clean := func() {
+ pendingFiles = cm.cleanCache(pendingFiles)
+ }
+
+ if cleanStop != nil {
+ t := time.NewTicker(cm.cacheDuration / 2)
+ for {
+ select {
+ case <-t.C:
+ clean()
+ case _, stillOpen := <-cleanStop:
+ // Ignore values send on the channel, only stop when it is closed.
+ if !stillOpen {
+ t.Stop()
+ return
+ }
+ }
+ }
+ }
+ for {
+ time.Sleep(cm.cacheDuration / 2)
+ clean()
+ }
+}
+
+func (cm *inMemoryCacheManager) cleanCache(pendingFiles []*fsFile) []*fsFile {
+ var filesToRelease []*fsFile
+
+ cm.cacheLock.Lock()
+
+ // Close files which couldn't be closed before due to non-zero
+ // readers count on the previous run.
+ var remainingFiles []*fsFile
+ for _, ff := range pendingFiles {
+ if ff.readersCount > 0 {
+ remainingFiles = append(remainingFiles, ff)
+ } else {
+ filesToRelease = append(filesToRelease, ff)
+ }
+ }
+ pendingFiles = remainingFiles
+
+ pendingFiles, filesToRelease = cleanCacheNolock(cm.cache, pendingFiles, filesToRelease, cm.cacheDuration)
+ pendingFiles, filesToRelease = cleanCacheNolock(cm.cacheBrotli, pendingFiles, filesToRelease, cm.cacheDuration)
+ pendingFiles, filesToRelease = cleanCacheNolock(cm.cacheGzip, pendingFiles, filesToRelease, cm.cacheDuration)
+
+ cm.cacheLock.Unlock()
+
+ for _, ff := range filesToRelease {
+ ff.Release()
+ }
+
+ return pendingFiles
+}
+
+func cleanCacheNolock(cache map[string]*fsFile, pendingFiles, filesToRelease []*fsFile, cacheDuration time.Duration) ([]*fsFile, []*fsFile) {
+ t := time.Now()
+ for k, ff := range cache {
+ if t.Sub(ff.t) > cacheDuration {
+ if ff.readersCount > 0 {
+ // There are pending readers on stale file handle,
+ // so we cannot close it. Put it into pendingFiles
+ // so it will be closed later.
+ pendingFiles = append(pendingFiles, ff)
+ } else {
+ filesToRelease = append(filesToRelease, ff)
+ }
+ delete(cache, k)
+ }
+ }
+ return pendingFiles, filesToRelease
+}
+
+func (h *fsHandler) pathToFilePath(path string) string {
+ if _, ok := h.filesystem.(*osFS); !ok {
+ if len(path) < 1 {
+ return path
+ }
+ return path[1:]
+ }
+ return filepath.FromSlash(h.root + path)
+}
+
+func (h *fsHandler) filePathToCompressed(filePath string) string {
+ if h.root == h.compressRoot {
+ return filePath
+ }
+ if !strings.HasPrefix(filePath, h.root) {
+ return filePath
+ }
+ return filepath.FromSlash(h.compressRoot + filePath[len(h.root):])
+}
+
+func (h *fsHandler) handleRequest(ctx *RequestCtx) {
+ var path []byte
+ if h.pathRewrite != nil {
+ path = h.pathRewrite(ctx)
+ } else {
+ path = ctx.Path()
+ }
+ hasTrailingSlash := len(path) > 0 && path[len(path)-1] == '/'
+ path = stripTrailingSlashes(path)
+
+ if n := bytes.IndexByte(path, 0); n >= 0 {
+ ctx.Logger().Printf("cannot serve path with nil byte at position %d: %q", n, path)
+ ctx.Error("Are you a hacker?", StatusBadRequest)
+ return
+ }
+ if h.pathRewrite != nil {
+ // There is no need to check for '/../' if path = ctx.Path(),
+ // since ctx.Path must normalize and sanitize the path.
+
+ if n := bytes.Index(path, strSlashDotDotSlash); n >= 0 {
+ ctx.Logger().Printf("cannot serve path with '/../' at position %d due to security reasons: %q", n, path)
+ ctx.Error("Internal Server Error", StatusInternalServerError)
+ return
+ }
+ }
+
+ mustCompress := false
+ fileCacheKind := defaultCacheKind
+ fileEncoding := ""
+ byteRange := ctx.Request.Header.peek(strRange)
+ if len(byteRange) == 0 && h.compress {
+ if h.compressBrotli && ctx.Request.Header.HasAcceptEncodingBytes(strBr) {
+ mustCompress = true
+ fileCacheKind = brotliCacheKind
+ fileEncoding = "br"
+ } else if ctx.Request.Header.HasAcceptEncodingBytes(strGzip) {
+ mustCompress = true
+ fileCacheKind = gzipCacheKind
+ fileEncoding = "gzip"
+ }
+ }
+
+ pathStr := string(path)
+
+ ff, ok := h.cacheManager.GetFileFromCache(fileCacheKind, pathStr)
+ if !ok {
+ filePath := h.pathToFilePath(pathStr)
+
+ var err error
+ ff, err = h.openFSFile(filePath, mustCompress, fileEncoding)
+ if mustCompress && err == errNoCreatePermission {
+ ctx.Logger().Printf("insufficient permissions for saving compressed file for %q. Serving uncompressed file. "+
+ "Allow write access to the directory with this file in order to improve fasthttp performance", filePath)
+ mustCompress = false
+ ff, err = h.openFSFile(filePath, mustCompress, fileEncoding)
+ }
+ if err == errDirIndexRequired {
+ if !hasTrailingSlash {
+ ctx.RedirectBytes(append(path, '/'), StatusFound)
+ return
+ }
+ ff, err = h.openIndexFile(ctx, filePath, mustCompress, fileEncoding)
+ if err != nil {
+ ctx.Logger().Printf("cannot open dir index %q: %v", filePath, err)
+ ctx.Error("Directory index is forbidden", StatusForbidden)
+ return
+ }
+ } else if err != nil {
+ ctx.Logger().Printf("cannot open file %q: %v", filePath, err)
+ if h.pathNotFound == nil {
+ ctx.Error("Cannot open requested path", StatusNotFound)
+ } else {
+ ctx.SetStatusCode(StatusNotFound)
+ h.pathNotFound(ctx)
+ }
+ return
+ }
+
+ ff = h.cacheManager.SetFileToCache(fileCacheKind, pathStr, ff)
+ }
+
+ if !ctx.IfModifiedSince(ff.lastModified) {
+ ff.decReadersCount()
+ ctx.NotModified()
+ return
+ }
+
+ r, err := ff.NewReader()
+ if err != nil {
+ ctx.Logger().Printf("cannot obtain file reader for path=%q: %v", path, err)
+ ctx.Error("Internal Server Error", StatusInternalServerError)
+ return
+ }
+
+ hdr := &ctx.Response.Header
+ if ff.compressed {
+ if fileEncoding == "br" {
+ hdr.SetContentEncodingBytes(strBr)
+ } else if fileEncoding == "gzip" {
+ hdr.SetContentEncodingBytes(strGzip)
+ }
+ }
+
+ statusCode := StatusOK
+ contentLength := ff.contentLength
+ if h.acceptByteRange {
+ hdr.setNonSpecial(strAcceptRanges, strBytes)
+ if len(byteRange) > 0 {
+ startPos, endPos, err := ParseByteRange(byteRange, contentLength)
+ if err != nil {
+ _ = r.(io.Closer).Close()
+ ctx.Logger().Printf("cannot parse byte range %q for path=%q: %v", byteRange, path, err)
+ ctx.Error("Range Not Satisfiable", StatusRequestedRangeNotSatisfiable)
+ return
+ }
+
+ if err = r.(byteRangeUpdater).UpdateByteRange(startPos, endPos); err != nil {
+ _ = r.(io.Closer).Close()
+ ctx.Logger().Printf("cannot seek byte range %q for path=%q: %v", byteRange, path, err)
+ ctx.Error("Internal Server Error", StatusInternalServerError)
+ return
+ }
+
+ hdr.SetContentRange(startPos, endPos, contentLength)
+ contentLength = endPos - startPos + 1
+ statusCode = StatusPartialContent
+ }
+ }
+
+ hdr.setNonSpecial(strLastModified, ff.lastModifiedStr)
+ if !ctx.IsHead() {
+ ctx.SetBodyStream(r, contentLength)
+ } else {
+ ctx.Response.ResetBody()
+ ctx.Response.SkipBody = true
+ ctx.Response.Header.SetContentLength(contentLength)
+ if rc, ok := r.(io.Closer); ok {
+ if err := rc.Close(); err != nil {
+ ctx.Logger().Printf("cannot close file reader: %v", err)
+ ctx.Error("Internal Server Error", StatusInternalServerError)
+ return
+ }
+ }
+ }
+ hdr.noDefaultContentType = true
+ if len(hdr.ContentType()) == 0 {
+ ctx.SetContentType(ff.contentType)
+ }
+ ctx.SetStatusCode(statusCode)
+}
+
+type byteRangeUpdater interface {
+ UpdateByteRange(startPos, endPos int) error
+}
+
+// ParseByteRange parses 'Range: bytes=...' header value.
+//
+// It follows https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.35 .
+func ParseByteRange(byteRange []byte, contentLength int) (startPos, endPos int, err error) {
+ b := byteRange
+ if !bytes.HasPrefix(b, strBytes) {
+ return 0, 0, fmt.Errorf("unsupported range units: %q. Expecting %q", byteRange, strBytes)
+ }
+
+ b = b[len(strBytes):]
+ if len(b) == 0 || b[0] != '=' {
+ return 0, 0, fmt.Errorf("missing byte range in %q", byteRange)
+ }
+ b = b[1:]
+
+ n := bytes.IndexByte(b, '-')
+ if n < 0 {
+ return 0, 0, fmt.Errorf("missing the end position of byte range in %q", byteRange)
+ }
+
+ if n == 0 {
+ v, err := ParseUint(b[n+1:])
+ if err != nil {
+ return 0, 0, err
+ }
+ startPos := contentLength - v
+ if startPos < 0 {
+ startPos = 0
+ }
+ return startPos, contentLength - 1, nil
+ }
+
+ if startPos, err = ParseUint(b[:n]); err != nil {
+ return 0, 0, err
+ }
+ if startPos >= contentLength {
+ return 0, 0, fmt.Errorf("the start position of byte range cannot exceed %d. byte range %q", contentLength-1, byteRange)
+ }
+
+ b = b[n+1:]
+ if len(b) == 0 {
+ return startPos, contentLength - 1, nil
+ }
+
+ if endPos, err = ParseUint(b); err != nil {
+ return 0, 0, err
+ }
+ if endPos >= contentLength {
+ endPos = contentLength - 1
+ }
+ if endPos < startPos {
+ return 0, 0, fmt.Errorf("the start position of byte range cannot exceed the end position. byte range %q", byteRange)
+ }
+ return startPos, endPos, nil
+}
+
+func (h *fsHandler) openIndexFile(ctx *RequestCtx, dirPath string, mustCompress bool, fileEncoding string) (*fsFile, error) {
+ for _, indexName := range h.indexNames {
+ indexFilePath := dirPath + "/" + indexName
+ ff, err := h.openFSFile(indexFilePath, mustCompress, fileEncoding)
+ if err == nil {
+ return ff, nil
+ }
+ if !errors.Is(err, fs.ErrNotExist) {
+ return nil, fmt.Errorf("cannot open file %q: %w", indexFilePath, err)
+ }
+ }
+
+ if !h.generateIndexPages {
+ return nil, fmt.Errorf("cannot access directory without index page. Directory %q", dirPath)
+ }
+
+ return h.createDirIndex(ctx, dirPath, mustCompress, fileEncoding)
+}
+
+var (
+ errDirIndexRequired = errors.New("directory index required")
+ errNoCreatePermission = errors.New("no 'create file' permissions")
+)
+
+func (h *fsHandler) createDirIndex(ctx *RequestCtx, dirPath string, mustCompress bool, fileEncoding string) (*fsFile, error) {
+ w := &bytebufferpool.ByteBuffer{}
+
+ base := ctx.URI()
+
+ basePathEscaped := html.EscapeString(string(base.Path()))
+ _, _ = fmt.Fprintf(w, "%s", basePathEscaped)
+ _, _ = fmt.Fprintf(w, "%s
", basePathEscaped)
+ _, _ = fmt.Fprintf(w, "")
+
+ if len(basePathEscaped) > 1 {
+ var parentURI URI
+ base.CopyTo(&parentURI)
+ parentURI.Update(string(base.Path()) + "/..")
+ parentPathEscaped := html.EscapeString(string(parentURI.Path()))
+ _, _ = fmt.Fprintf(w, `- ..
`, parentPathEscaped)
+ }
+
+ dirEntries, err := fs.ReadDir(h.filesystem, dirPath)
+ if err != nil {
+ return nil, err
+ }
+
+ fm := make(map[string]fs.FileInfo, len(dirEntries))
+ filenames := make([]string, 0, len(dirEntries))
+nestedContinue:
+ for _, de := range dirEntries {
+ name := de.Name()
+ for _, cfs := range h.compressedFileSuffixes {
+ if strings.HasSuffix(name, cfs) {
+ // Do not show compressed files on index page.
+ continue nestedContinue
+ }
+ }
+ fi, err := de.Info()
+ if err != nil {
+ ctx.Logger().Printf("cannot fetch information from dir entry %q: %v, skip", name, err)
+
+ continue nestedContinue
+ }
+
+ fm[name] = fi
+ filenames = append(filenames, name)
+ }
+
+ var u URI
+ base.CopyTo(&u)
+ u.Update(string(u.Path()) + "/")
+
+ sort.Strings(filenames)
+ for _, name := range filenames {
+ u.Update(name)
+ pathEscaped := html.EscapeString(string(u.Path()))
+ fi := fm[name]
+ auxStr := "dir"
+ className := "dir"
+ if !fi.IsDir() {
+ auxStr = fmt.Sprintf("file, %d bytes", fi.Size())
+ className = "file"
+ }
+ _, _ = fmt.Fprintf(w, `- %s, %s, last modified %s
`,
+ pathEscaped, className, html.EscapeString(name), auxStr, fsModTime(fi.ModTime()))
+ }
+
+ _, _ = fmt.Fprintf(w, "
")
+
+ if mustCompress {
+ var zbuf bytebufferpool.ByteBuffer
+ if fileEncoding == "br" {
+ zbuf.B = AppendBrotliBytesLevel(zbuf.B, w.B, CompressDefaultCompression)
+ } else if fileEncoding == "gzip" {
+ zbuf.B = AppendGzipBytesLevel(zbuf.B, w.B, CompressDefaultCompression)
+ }
+ w = &zbuf
+ }
+
+ dirIndex := w.B
+ lastModified := time.Now()
+ ff := &fsFile{
+ h: h,
+ dirIndex: dirIndex,
+ contentType: "text/html; charset=utf-8",
+ contentLength: len(dirIndex),
+ compressed: mustCompress,
+ lastModified: lastModified,
+ lastModifiedStr: AppendHTTPDate(nil, lastModified),
+
+ t: lastModified,
+ }
+ return ff, nil
+}
+
+const (
+ fsMinCompressRatio = 0.8
+ fsMaxCompressibleFileSize = 8 * 1024 * 1024
+)
+
+func (h *fsHandler) compressAndOpenFSFile(filePath string, fileEncoding string) (*fsFile, error) {
+ f, err := h.filesystem.Open(filePath)
+ if err != nil {
+ return nil, err
+ }
+
+ fileInfo, err := f.Stat()
+ if err != nil {
+ _ = f.Close()
+ return nil, fmt.Errorf("cannot obtain info for file %q: %w", filePath, err)
+ }
+
+ if fileInfo.IsDir() {
+ _ = f.Close()
+ return nil, errDirIndexRequired
+ }
+
+ if strings.HasSuffix(filePath, h.compressedFileSuffixes[fileEncoding]) ||
+ fileInfo.Size() > fsMaxCompressibleFileSize ||
+ !isFileCompressible(f, fsMinCompressRatio) {
+ return h.newFSFile(f, fileInfo, false, filePath, "")
+ }
+
+ compressedFilePath := h.filePathToCompressed(filePath)
+
+ if _, ok := h.filesystem.(*osFS); !ok {
+ return h.newCompressedFSFileCache(f, fileInfo, compressedFilePath, fileEncoding)
+ }
+
+ if compressedFilePath != filePath {
+ if err := os.MkdirAll(filepath.Dir(compressedFilePath), os.ModePerm); err != nil {
+ return nil, err
+ }
+ }
+ compressedFilePath += h.compressedFileSuffixes[fileEncoding]
+
+ absPath, err := filepath.Abs(compressedFilePath)
+ if err != nil {
+ _ = f.Close()
+ return nil, fmt.Errorf("cannot determine absolute path for %q: %v", compressedFilePath, err)
+ }
+
+ flock := getFileLock(absPath)
+ flock.Lock()
+ ff, err := h.compressFileNolock(f, fileInfo, filePath, compressedFilePath, fileEncoding)
+ flock.Unlock()
+
+ return ff, err
+}
+
+func (h *fsHandler) compressFileNolock(f fs.File, fileInfo fs.FileInfo, filePath, compressedFilePath string, fileEncoding string) (*fsFile, error) {
+ // Attempt to open compressed file created by another concurrent
+ // goroutine.
+ // It is safe opening such a file, since the file creation
+ // is guarded by file mutex - see getFileLock call.
+ if _, err := os.Stat(compressedFilePath); err == nil {
+ _ = f.Close()
+ return h.newCompressedFSFile(compressedFilePath, fileEncoding)
+ }
+
+ // Create temporary file, so concurrent goroutines don't use
+ // it until it is created.
+ tmpFilePath := compressedFilePath + ".tmp"
+ zf, err := os.Create(tmpFilePath)
+ if err != nil {
+ _ = f.Close()
+ if !errors.Is(err, fs.ErrPermission) {
+ return nil, fmt.Errorf("cannot create temporary file %q: %w", tmpFilePath, err)
+ }
+ return nil, errNoCreatePermission
+ }
+ if fileEncoding == "br" {
+ zw := acquireStacklessBrotliWriter(zf, CompressDefaultCompression)
+ _, err = copyZeroAlloc(zw, f)
+ if err1 := zw.Flush(); err == nil {
+ err = err1
+ }
+ releaseStacklessBrotliWriter(zw, CompressDefaultCompression)
+ } else if fileEncoding == "gzip" {
+ zw := acquireStacklessGzipWriter(zf, CompressDefaultCompression)
+ _, err = copyZeroAlloc(zw, f)
+ if err1 := zw.Flush(); err == nil {
+ err = err1
+ }
+ releaseStacklessGzipWriter(zw, CompressDefaultCompression)
+ }
+ _ = zf.Close()
+ _ = f.Close()
+ if err != nil {
+ return nil, fmt.Errorf("error when compressing file %q to %q: %w", filePath, tmpFilePath, err)
+ }
+ if err = os.Chtimes(tmpFilePath, time.Now(), fileInfo.ModTime()); err != nil {
+ return nil, fmt.Errorf("cannot change modification time to %v for tmp file %q: %v",
+ fileInfo.ModTime(), tmpFilePath, err)
+ }
+ if err = os.Rename(tmpFilePath, compressedFilePath); err != nil {
+ return nil, fmt.Errorf("cannot move compressed file from %q to %q: %w", tmpFilePath, compressedFilePath, err)
+ }
+ return h.newCompressedFSFile(compressedFilePath, fileEncoding)
+}
+
+// newCompressedFSFileCache use memory cache compressed files
+func (h *fsHandler) newCompressedFSFileCache(f fs.File, fileInfo fs.FileInfo, filePath, fileEncoding string) (*fsFile, error) {
+ var (
+ w = &bytebufferpool.ByteBuffer{}
+ err error
+ )
+
+ if fileEncoding == "br" {
+ zw := acquireStacklessBrotliWriter(w, CompressDefaultCompression)
+ _, err = copyZeroAlloc(zw, f)
+ if err1 := zw.Flush(); err == nil {
+ err = err1
+ }
+ releaseStacklessBrotliWriter(zw, CompressDefaultCompression)
+ } else if fileEncoding == "gzip" {
+ zw := acquireStacklessGzipWriter(w, CompressDefaultCompression)
+ _, err = copyZeroAlloc(zw, f)
+ if err1 := zw.Flush(); err == nil {
+ err = err1
+ }
+ releaseStacklessGzipWriter(zw, CompressDefaultCompression)
+ }
+ defer func() { _ = f.Close() }()
+
+ if err != nil {
+ return nil, fmt.Errorf("error when compressing file %q: %w", filePath, err)
+ }
+
+ seeker, ok := f.(io.Seeker)
+ if !ok {
+ return nil, errors.New("not implemented io.Seeker")
+ }
+ if _, err = seeker.Seek(0, io.SeekStart); err != nil {
+ return nil, err
+ }
+
+ ext := fileExtension(fileInfo.Name(), false, h.compressedFileSuffixes[fileEncoding])
+ contentType := mime.TypeByExtension(ext)
+ if len(contentType) == 0 {
+ data, err := readFileHeader(f, false, fileEncoding)
+ if err != nil {
+ return nil, fmt.Errorf("cannot read header of the file %q: %w", fileInfo.Name(), err)
+ }
+ contentType = http.DetectContentType(data)
+ }
+
+ dirIndex := w.B
+ lastModified := fileInfo.ModTime()
+ ff := &fsFile{
+ h: h,
+ dirIndex: dirIndex,
+ contentType: contentType,
+ contentLength: len(dirIndex),
+ compressed: true,
+ lastModified: lastModified,
+ lastModifiedStr: AppendHTTPDate(nil, lastModified),
+
+ t: time.Now(),
+ }
+
+ return ff, nil
+}
+
+func (h *fsHandler) newCompressedFSFile(filePath string, fileEncoding string) (*fsFile, error) {
+ f, err := h.filesystem.Open(filePath)
+ if err != nil {
+ return nil, fmt.Errorf("cannot open compressed file %q: %w", filePath, err)
+ }
+ fileInfo, err := f.Stat()
+ if err != nil {
+ _ = f.Close()
+ return nil, fmt.Errorf("cannot obtain info for compressed file %q: %w", filePath, err)
+ }
+ return h.newFSFile(f, fileInfo, true, filePath, fileEncoding)
+}
+
+func (h *fsHandler) openFSFile(filePath string, mustCompress bool, fileEncoding string) (*fsFile, error) {
+ filePathOriginal := filePath
+ if mustCompress {
+ filePath += h.compressedFileSuffixes[fileEncoding]
+ }
+
+ f, err := h.filesystem.Open(filePath)
+ if err != nil {
+ if mustCompress && errors.Is(err, fs.ErrNotExist) {
+ return h.compressAndOpenFSFile(filePathOriginal, fileEncoding)
+ }
+ return nil, err
+ }
+
+ fileInfo, err := f.Stat()
+ if err != nil {
+ _ = f.Close()
+ return nil, fmt.Errorf("cannot obtain info for file %q: %w", filePath, err)
+ }
+
+ if fileInfo.IsDir() {
+ _ = f.Close()
+ if mustCompress {
+ return nil, fmt.Errorf("directory with unexpected suffix found: %q. Suffix: %q",
+ filePath, h.compressedFileSuffixes[fileEncoding])
+ }
+ return nil, errDirIndexRequired
+ }
+
+ if mustCompress {
+ fileInfoOriginal, err := fs.Stat(h.filesystem, filePathOriginal)
+ if err != nil {
+ _ = f.Close()
+ return nil, fmt.Errorf("cannot obtain info for original file %q: %w", filePathOriginal, err)
+ }
+
+ // Only re-create the compressed file if there was more than a second between the mod times.
+ // On macOS the gzip seems to truncate the nanoseconds in the mod time causing the original file
+ // to look newer than the gzipped file.
+ if fileInfoOriginal.ModTime().Sub(fileInfo.ModTime()) >= time.Second {
+ // The compressed file became stale. Re-create it.
+ _ = f.Close()
+ _ = os.Remove(filePath)
+ return h.compressAndOpenFSFile(filePathOriginal, fileEncoding)
+ }
+ }
+
+ return h.newFSFile(f, fileInfo, mustCompress, filePath, fileEncoding)
+}
+
+func (h *fsHandler) newFSFile(f fs.File, fileInfo fs.FileInfo, compressed bool, filePath, fileEncoding string) (*fsFile, error) {
+ n := fileInfo.Size()
+ contentLength := int(n)
+ if n != int64(contentLength) {
+ _ = f.Close()
+ return nil, fmt.Errorf("too big file: %d bytes", n)
+ }
+
+ // detect content-type
+ ext := fileExtension(fileInfo.Name(), compressed, h.compressedFileSuffixes[fileEncoding])
+ contentType := mime.TypeByExtension(ext)
+ if len(contentType) == 0 {
+ data, err := readFileHeader(f, compressed, fileEncoding)
+ if err != nil {
+ return nil, fmt.Errorf("cannot read header of the file %q: %w", fileInfo.Name(), err)
+ }
+ contentType = http.DetectContentType(data)
+ }
+
+ lastModified := fileInfo.ModTime()
+ ff := &fsFile{
+ h: h,
+ f: f,
+ filename: filePath,
+ contentType: contentType,
+ contentLength: contentLength,
+ compressed: compressed,
+ lastModified: lastModified,
+ lastModifiedStr: AppendHTTPDate(nil, lastModified),
+
+ t: time.Now(),
+ }
+ return ff, nil
+}
+
+func readFileHeader(f io.Reader, compressed bool, fileEncoding string) ([]byte, error) {
+ r := f
+ var (
+ br *brotli.Reader
+ zr *gzip.Reader
+ )
+ if compressed {
+ var err error
+ if fileEncoding == "br" {
+ if br, err = acquireBrotliReader(f); err != nil {
+ return nil, err
+ }
+ r = br
+ } else if fileEncoding == "gzip" {
+ if zr, err = acquireGzipReader(f); err != nil {
+ return nil, err
+ }
+ r = zr
+ }
+ }
+
+ lr := &io.LimitedReader{
+ R: r,
+ N: 512,
+ }
+ data, err := io.ReadAll(lr)
+ seeker, ok := f.(io.Seeker)
+ if !ok {
+ return nil, errors.New("must implement io.Seeker")
+ }
+ if _, err := seeker.Seek(0, io.SeekStart); err != nil {
+ return nil, err
+ }
+
+ if br != nil {
+ releaseBrotliReader(br)
+ }
+
+ if zr != nil {
+ releaseGzipReader(zr)
+ }
+
+ return data, err
+}
+
+func stripLeadingSlashes(path []byte, stripSlashes int) []byte {
+ for stripSlashes > 0 && len(path) > 0 {
+ if path[0] != '/' {
+ // developer sanity-check
+ panic("BUG: path must start with slash")
+ }
+ n := bytes.IndexByte(path[1:], '/')
+ if n < 0 {
+ path = path[:0]
+ break
+ }
+ path = path[n+1:]
+ stripSlashes--
+ }
+ return path
+}
+
+func stripTrailingSlashes(path []byte) []byte {
+ for len(path) > 0 && path[len(path)-1] == '/' {
+ path = path[:len(path)-1]
+ }
+ return path
+}
+
+func fileExtension(path string, compressed bool, compressedFileSuffix string) string {
+ if compressed && strings.HasSuffix(path, compressedFileSuffix) {
+ path = path[:len(path)-len(compressedFileSuffix)]
+ }
+ n := strings.LastIndexByte(path, '.')
+ if n < 0 {
+ return ""
+ }
+ return path[n:]
+}
+
+// FileLastModified returns last modified time for the file.
+func FileLastModified(path string) (time.Time, error) {
+ f, err := os.Open(path)
+ if err != nil {
+ return zeroTime, err
+ }
+ fileInfo, err := f.Stat()
+ _ = f.Close()
+ if err != nil {
+ return zeroTime, err
+ }
+ return fsModTime(fileInfo.ModTime()), nil
+}
+
+func fsModTime(t time.Time) time.Time {
+ return t.In(time.UTC).Truncate(time.Second)
+}
+
+var filesLockMap sync.Map
+
+func getFileLock(absPath string) *sync.Mutex {
+ v, _ := filesLockMap.LoadOrStore(absPath, &sync.Mutex{})
+ filelock := v.(*sync.Mutex)
+ return filelock
+}
+
+var _ fs.FS = (*osFS)(nil)
+
+type osFS struct{}
+
+func (o *osFS) Open(name string) (fs.File, error) { return os.Open(name) }
+func (o *osFS) Stat(name string) (fs.FileInfo, error) { return os.Stat(name) }
diff --git a/vendor/github.com/valyala/fasthttp/header.go b/vendor/github.com/valyala/fasthttp/header.go
new file mode 100644
index 0000000..e295fb7
--- /dev/null
+++ b/vendor/github.com/valyala/fasthttp/header.go
@@ -0,0 +1,3441 @@
+package fasthttp
+
+import (
+ "bufio"
+ "bytes"
+ "errors"
+ "fmt"
+ "io"
+ "sync"
+ "sync/atomic"
+ "time"
+)
+
+const (
+ rChar = byte('\r')
+ nChar = byte('\n')
+)
+
+// ResponseHeader represents HTTP response header.
+//
+// It is forbidden copying ResponseHeader instances.
+// Create new instances instead and use CopyTo.
+//
+// ResponseHeader instance MUST NOT be used from concurrently running
+// goroutines.
+type ResponseHeader struct {
+ noCopy noCopy
+
+ disableNormalizing bool
+ noHTTP11 bool
+ connectionClose bool
+ noDefaultContentType bool
+ noDefaultDate bool
+
+ statusCode int
+ statusMessage []byte
+ protocol []byte
+ contentLength int
+ contentLengthBytes []byte
+ secureErrorLogMessage bool
+
+ contentType []byte
+ contentEncoding []byte
+ server []byte
+ mulHeader [][]byte
+
+ h []argsKV
+ trailer []argsKV
+ bufKV argsKV
+
+ cookies []argsKV
+}
+
+// RequestHeader represents HTTP request header.
+//
+// It is forbidden copying RequestHeader instances.
+// Create new instances instead and use CopyTo.
+//
+// RequestHeader instance MUST NOT be used from concurrently running
+// goroutines.
+type RequestHeader struct {
+ noCopy noCopy
+
+ disableNormalizing bool
+ noHTTP11 bool
+ connectionClose bool
+ noDefaultContentType bool
+ disableSpecialHeader bool
+
+ // These two fields have been moved close to other bool fields
+ // for reducing RequestHeader object size.
+ cookiesCollected bool
+
+ contentLength int
+ contentLengthBytes []byte
+ secureErrorLogMessage bool
+
+ method []byte
+ requestURI []byte
+ proto []byte
+ host []byte
+ contentType []byte
+ userAgent []byte
+ mulHeader [][]byte
+
+ h []argsKV
+ trailer []argsKV
+ bufKV argsKV
+
+ cookies []argsKV
+
+ // stores an immutable copy of headers as they were received from the
+ // wire.
+ rawHeaders []byte
+}
+
+// SetContentRange sets 'Content-Range: bytes startPos-endPos/contentLength'
+// header.
+func (h *ResponseHeader) SetContentRange(startPos, endPos, contentLength int) {
+ b := h.bufKV.value[:0]
+ b = append(b, strBytes...)
+ b = append(b, ' ')
+ b = AppendUint(b, startPos)
+ b = append(b, '-')
+ b = AppendUint(b, endPos)
+ b = append(b, '/')
+ b = AppendUint(b, contentLength)
+ h.bufKV.value = b
+
+ h.setNonSpecial(strContentRange, h.bufKV.value)
+}
+
+// SetByteRange sets 'Range: bytes=startPos-endPos' header.
+//
+// - If startPos is negative, then 'bytes=-startPos' value is set.
+// - If endPos is negative, then 'bytes=startPos-' value is set.
+func (h *RequestHeader) SetByteRange(startPos, endPos int) {
+ b := h.bufKV.value[:0]
+ b = append(b, strBytes...)
+ b = append(b, '=')
+ if startPos >= 0 {
+ b = AppendUint(b, startPos)
+ } else {
+ endPos = -startPos
+ }
+ b = append(b, '-')
+ if endPos >= 0 {
+ b = AppendUint(b, endPos)
+ }
+ h.bufKV.value = b
+
+ h.setNonSpecial(strRange, h.bufKV.value)
+}
+
+// StatusCode returns response status code.
+func (h *ResponseHeader) StatusCode() int {
+ if h.statusCode == 0 {
+ return StatusOK
+ }
+ return h.statusCode
+}
+
+// SetStatusCode sets response status code.
+func (h *ResponseHeader) SetStatusCode(statusCode int) {
+ h.statusCode = statusCode
+}
+
+// StatusMessage returns response status message.
+func (h *ResponseHeader) StatusMessage() []byte {
+ return h.statusMessage
+}
+
+// SetStatusMessage sets response status message bytes.
+func (h *ResponseHeader) SetStatusMessage(statusMessage []byte) {
+ h.statusMessage = append(h.statusMessage[:0], statusMessage...)
+}
+
+// Protocol returns response protocol bytes.
+func (h *ResponseHeader) Protocol() []byte {
+ if len(h.protocol) > 0 {
+ return h.protocol
+ }
+ return strHTTP11
+}
+
+// SetProtocol sets response protocol bytes.
+func (h *ResponseHeader) SetProtocol(protocol []byte) {
+ h.protocol = append(h.protocol[:0], protocol...)
+}
+
+// SetLastModified sets 'Last-Modified' header to the given value.
+func (h *ResponseHeader) SetLastModified(t time.Time) {
+ h.bufKV.value = AppendHTTPDate(h.bufKV.value[:0], t)
+ h.setNonSpecial(strLastModified, h.bufKV.value)
+}
+
+// ConnectionClose returns true if 'Connection: close' header is set.
+func (h *ResponseHeader) ConnectionClose() bool {
+ return h.connectionClose
+}
+
+// SetConnectionClose sets 'Connection: close' header.
+func (h *ResponseHeader) SetConnectionClose() {
+ h.connectionClose = true
+}
+
+// ResetConnectionClose clears 'Connection: close' header if it exists.
+func (h *ResponseHeader) ResetConnectionClose() {
+ if h.connectionClose {
+ h.connectionClose = false
+ h.h = delAllArgsBytes(h.h, strConnection)
+ }
+}
+
+// ConnectionClose returns true if 'Connection: close' header is set.
+func (h *RequestHeader) ConnectionClose() bool {
+ return h.connectionClose
+}
+
+// SetConnectionClose sets 'Connection: close' header.
+func (h *RequestHeader) SetConnectionClose() {
+ h.connectionClose = true
+}
+
+// ResetConnectionClose clears 'Connection: close' header if it exists.
+func (h *RequestHeader) ResetConnectionClose() {
+ if h.connectionClose {
+ h.connectionClose = false
+ h.h = delAllArgsBytes(h.h, strConnection)
+ }
+}
+
+// ConnectionUpgrade returns true if 'Connection: Upgrade' header is set.
+func (h *ResponseHeader) ConnectionUpgrade() bool {
+ return hasHeaderValue(h.Peek(HeaderConnection), strUpgrade)
+}
+
+// ConnectionUpgrade returns true if 'Connection: Upgrade' header is set.
+func (h *RequestHeader) ConnectionUpgrade() bool {
+ return hasHeaderValue(h.Peek(HeaderConnection), strUpgrade)
+}
+
+// PeekCookie is able to returns cookie by a given key from response.
+func (h *ResponseHeader) PeekCookie(key string) []byte {
+ return peekArgStr(h.cookies, key)
+}
+
+// ContentLength returns Content-Length header value.
+//
+// It may be negative:
+// -1 means Transfer-Encoding: chunked.
+// -2 means Transfer-Encoding: identity.
+func (h *ResponseHeader) ContentLength() int {
+ return h.contentLength
+}
+
+// SetContentLength sets Content-Length header value.
+//
+// Content-Length may be negative:
+// -1 means Transfer-Encoding: chunked.
+// -2 means Transfer-Encoding: identity.
+func (h *ResponseHeader) SetContentLength(contentLength int) {
+ if h.mustSkipContentLength() {
+ return
+ }
+ h.contentLength = contentLength
+ if contentLength >= 0 {
+ h.contentLengthBytes = AppendUint(h.contentLengthBytes[:0], contentLength)
+ h.h = delAllArgsBytes(h.h, strTransferEncoding)
+ } else {
+ h.contentLengthBytes = h.contentLengthBytes[:0]
+ value := strChunked
+ if contentLength == -2 {
+ h.SetConnectionClose()
+ value = strIdentity
+ }
+ h.h = setArgBytes(h.h, strTransferEncoding, value, argsHasValue)
+ }
+}
+
+func (h *ResponseHeader) mustSkipContentLength() bool {
+ // From http/1.1 specs:
+ // All 1xx (informational), 204 (no content), and 304 (not modified) responses MUST NOT include a message-body
+ statusCode := h.StatusCode()
+
+ // Fast path.
+ if statusCode < 100 || statusCode == StatusOK {
+ return false
+ }
+
+ // Slow path.
+ return statusCode == StatusNotModified || statusCode == StatusNoContent || statusCode < 200
+}
+
+// ContentLength returns Content-Length header value.
+//
+// It may be negative:
+// -1 means Transfer-Encoding: chunked.
+func (h *RequestHeader) ContentLength() int {
+ return h.realContentLength()
+}
+
+// realContentLength returns the actual Content-Length set in the request,
+// including positive lengths for GET/HEAD requests.
+func (h *RequestHeader) realContentLength() int {
+ return h.contentLength
+}
+
+// SetContentLength sets Content-Length header value.
+//
+// Negative content-length sets 'Transfer-Encoding: chunked' header.
+func (h *RequestHeader) SetContentLength(contentLength int) {
+ h.contentLength = contentLength
+ if contentLength >= 0 {
+ h.contentLengthBytes = AppendUint(h.contentLengthBytes[:0], contentLength)
+ h.h = delAllArgsBytes(h.h, strTransferEncoding)
+ } else {
+ h.contentLengthBytes = h.contentLengthBytes[:0]
+ h.h = setArgBytes(h.h, strTransferEncoding, strChunked, argsHasValue)
+ }
+}
+
+func (h *ResponseHeader) isCompressibleContentType() bool {
+ contentType := h.ContentType()
+ return bytes.HasPrefix(contentType, strTextSlash) ||
+ bytes.HasPrefix(contentType, strApplicationSlash) ||
+ bytes.HasPrefix(contentType, strImageSVG) ||
+ bytes.HasPrefix(contentType, strImageIcon) ||
+ bytes.HasPrefix(contentType, strFontSlash) ||
+ bytes.HasPrefix(contentType, strMultipartSlash)
+}
+
+// ContentType returns Content-Type header value.
+func (h *ResponseHeader) ContentType() []byte {
+ contentType := h.contentType
+ if !h.noDefaultContentType && len(h.contentType) == 0 {
+ contentType = defaultContentType
+ }
+ return contentType
+}
+
+// SetContentType sets Content-Type header value.
+func (h *ResponseHeader) SetContentType(contentType string) {
+ h.contentType = append(h.contentType[:0], contentType...)
+}
+
+// SetContentTypeBytes sets Content-Type header value.
+func (h *ResponseHeader) SetContentTypeBytes(contentType []byte) {
+ h.contentType = append(h.contentType[:0], contentType...)
+}
+
+// ContentEncoding returns Content-Encoding header value.
+func (h *ResponseHeader) ContentEncoding() []byte {
+ return h.contentEncoding
+}
+
+// SetContentEncoding sets Content-Encoding header value.
+func (h *ResponseHeader) SetContentEncoding(contentEncoding string) {
+ h.contentEncoding = append(h.contentEncoding[:0], contentEncoding...)
+}
+
+// SetContentEncodingBytes sets Content-Encoding header value.
+func (h *ResponseHeader) SetContentEncodingBytes(contentEncoding []byte) {
+ h.contentEncoding = append(h.contentEncoding[:0], contentEncoding...)
+}
+
+// addVaryBytes add value to the 'Vary' header if it's not included
+func (h *ResponseHeader) addVaryBytes(value []byte) {
+ v := h.peek(strVary)
+ if len(v) == 0 {
+ // 'Vary' is not set
+ h.SetBytesV(HeaderVary, value)
+ } else if !bytes.Contains(v, value) {
+ // 'Vary' is set and not contains target value
+ h.SetBytesV(HeaderVary, append(append(v, ','), value...))
+ } // else: 'Vary' is set and contains target value
+}
+
+// Server returns Server header value.
+func (h *ResponseHeader) Server() []byte {
+ return h.server
+}
+
+// SetServer sets Server header value.
+func (h *ResponseHeader) SetServer(server string) {
+ h.server = append(h.server[:0], server...)
+}
+
+// SetServerBytes sets Server header value.
+func (h *ResponseHeader) SetServerBytes(server []byte) {
+ h.server = append(h.server[:0], server...)
+}
+
+// ContentType returns Content-Type header value.
+func (h *RequestHeader) ContentType() []byte {
+ if h.disableSpecialHeader {
+ return peekArgBytes(h.h, []byte(HeaderContentType))
+ }
+ return h.contentType
+}
+
+// SetContentType sets Content-Type header value.
+func (h *RequestHeader) SetContentType(contentType string) {
+ h.contentType = append(h.contentType[:0], contentType...)
+}
+
+// SetContentTypeBytes sets Content-Type header value.
+func (h *RequestHeader) SetContentTypeBytes(contentType []byte) {
+ h.contentType = append(h.contentType[:0], contentType...)
+}
+
+// ContentEncoding returns Content-Encoding header value.
+func (h *RequestHeader) ContentEncoding() []byte {
+ return peekArgBytes(h.h, strContentEncoding)
+}
+
+// SetContentEncoding sets Content-Encoding header value.
+func (h *RequestHeader) SetContentEncoding(contentEncoding string) {
+ h.SetBytesK(strContentEncoding, contentEncoding)
+}
+
+// SetContentEncodingBytes sets Content-Encoding header value.
+func (h *RequestHeader) SetContentEncodingBytes(contentEncoding []byte) {
+ h.setNonSpecial(strContentEncoding, contentEncoding)
+}
+
+// SetMultipartFormBoundary sets the following Content-Type:
+// 'multipart/form-data; boundary=...'
+// where ... is substituted by the given boundary.
+func (h *RequestHeader) SetMultipartFormBoundary(boundary string) {
+ b := h.bufKV.value[:0]
+ b = append(b, strMultipartFormData...)
+ b = append(b, ';', ' ')
+ b = append(b, strBoundary...)
+ b = append(b, '=')
+ b = append(b, boundary...)
+ h.bufKV.value = b
+
+ h.SetContentTypeBytes(h.bufKV.value)
+}
+
+// SetMultipartFormBoundaryBytes sets the following Content-Type:
+// 'multipart/form-data; boundary=...'
+// where ... is substituted by the given boundary.
+func (h *RequestHeader) SetMultipartFormBoundaryBytes(boundary []byte) {
+ b := h.bufKV.value[:0]
+ b = append(b, strMultipartFormData...)
+ b = append(b, ';', ' ')
+ b = append(b, strBoundary...)
+ b = append(b, '=')
+ b = append(b, boundary...)
+ h.bufKV.value = b
+
+ h.SetContentTypeBytes(h.bufKV.value)
+}
+
+// SetTrailer sets header Trailer value for chunked response
+// to indicate which headers will be sent after the body.
+//
+// Use Set to set the trailer header later.
+//
+// Trailers are only supported with chunked transfer.
+// Trailers allow the sender to include additional headers at the end of chunked messages.
+//
+// The following trailers are forbidden:
+// 1. necessary for message framing (e.g., Transfer-Encoding and Content-Length),
+// 2. routing (e.g., Host),
+// 3. request modifiers (e.g., controls and conditionals in Section 5 of [RFC7231]),
+// 4. authentication (e.g., see [RFC7235] and [RFC6265]),
+// 5. response control data (e.g., see Section 7.1 of [RFC7231]),
+// 6. determining how to process the payload (e.g., Content-Encoding, Content-Type, Content-Range, and Trailer)
+//
+// Return ErrBadTrailer if contain any forbidden trailers.
+func (h *ResponseHeader) SetTrailer(trailer string) error {
+ return h.SetTrailerBytes(s2b(trailer))
+}
+
+// SetTrailerBytes sets Trailer header value for chunked response
+// to indicate which headers will be sent after the body.
+//
+// Use Set to set the trailer header later.
+//
+// Trailers are only supported with chunked transfer.
+// Trailers allow the sender to include additional headers at the end of chunked messages.
+//
+// The following trailers are forbidden:
+// 1. necessary for message framing (e.g., Transfer-Encoding and Content-Length),
+// 2. routing (e.g., Host),
+// 3. request modifiers (e.g., controls and conditionals in Section 5 of [RFC7231]),
+// 4. authentication (e.g., see [RFC7235] and [RFC6265]),
+// 5. response control data (e.g., see Section 7.1 of [RFC7231]),
+// 6. determining how to process the payload (e.g., Content-Encoding, Content-Type, Content-Range, and Trailer)
+//
+// Return ErrBadTrailer if contain any forbidden trailers.
+func (h *ResponseHeader) SetTrailerBytes(trailer []byte) error {
+ h.trailer = h.trailer[:0]
+ return h.AddTrailerBytes(trailer)
+}
+
+// AddTrailer add Trailer header value for chunked response
+// to indicate which headers will be sent after the body.
+//
+// Use Set to set the trailer header later.
+//
+// Trailers are only supported with chunked transfer.
+// Trailers allow the sender to include additional headers at the end of chunked messages.
+//
+// The following trailers are forbidden:
+// 1. necessary for message framing (e.g., Transfer-Encoding and Content-Length),
+// 2. routing (e.g., Host),
+// 3. request modifiers (e.g., controls and conditionals in Section 5 of [RFC7231]),
+// 4. authentication (e.g., see [RFC7235] and [RFC6265]),
+// 5. response control data (e.g., see Section 7.1 of [RFC7231]),
+// 6. determining how to process the payload (e.g., Content-Encoding, Content-Type, Content-Range, and Trailer)
+//
+// Return ErrBadTrailer if contain any forbidden trailers.
+func (h *ResponseHeader) AddTrailer(trailer string) error {
+ return h.AddTrailerBytes(s2b(trailer))
+}
+
+var ErrBadTrailer = errors.New("contain forbidden trailer")
+
+// AddTrailerBytes add Trailer header value for chunked response
+// to indicate which headers will be sent after the body.
+//
+// Use Set to set the trailer header later.
+//
+// Trailers are only supported with chunked transfer.
+// Trailers allow the sender to include additional headers at the end of chunked messages.
+//
+// The following trailers are forbidden:
+// 1. necessary for message framing (e.g., Transfer-Encoding and Content-Length),
+// 2. routing (e.g., Host),
+// 3. request modifiers (e.g., controls and conditionals in Section 5 of [RFC7231]),
+// 4. authentication (e.g., see [RFC7235] and [RFC6265]),
+// 5. response control data (e.g., see Section 7.1 of [RFC7231]),
+// 6. determining how to process the payload (e.g., Content-Encoding, Content-Type, Content-Range, and Trailer)
+//
+// Return ErrBadTrailer if contain any forbidden trailers.
+func (h *ResponseHeader) AddTrailerBytes(trailer []byte) error {
+ var err error
+ for i := -1; i+1 < len(trailer); {
+ trailer = trailer[i+1:]
+ i = bytes.IndexByte(trailer, ',')
+ if i < 0 {
+ i = len(trailer)
+ }
+ key := trailer[:i]
+ for len(key) > 0 && key[0] == ' ' {
+ key = key[1:]
+ }
+ for len(key) > 0 && key[len(key)-1] == ' ' {
+ key = key[:len(key)-1]
+ }
+ // Forbidden by RFC 7230, section 4.1.2
+ if isBadTrailer(key) {
+ err = ErrBadTrailer
+ continue
+ }
+ h.bufKV.key = append(h.bufKV.key[:0], key...)
+ normalizeHeaderKey(h.bufKV.key, h.disableNormalizing)
+ h.trailer = appendArgBytes(h.trailer, h.bufKV.key, nil, argsNoValue)
+ }
+
+ return err
+}
+
+// MultipartFormBoundary returns boundary part
+// from 'multipart/form-data; boundary=...' Content-Type.
+func (h *RequestHeader) MultipartFormBoundary() []byte {
+ b := h.ContentType()
+ if !bytes.HasPrefix(b, strMultipartFormData) {
+ return nil
+ }
+ b = b[len(strMultipartFormData):]
+ if len(b) == 0 || b[0] != ';' {
+ return nil
+ }
+
+ var n int
+ for len(b) > 0 {
+ n++
+ for len(b) > n && b[n] == ' ' {
+ n++
+ }
+ b = b[n:]
+ if !bytes.HasPrefix(b, strBoundary) {
+ if n = bytes.IndexByte(b, ';'); n < 0 {
+ return nil
+ }
+ continue
+ }
+
+ b = b[len(strBoundary):]
+ if len(b) == 0 || b[0] != '=' {
+ return nil
+ }
+ b = b[1:]
+ if n = bytes.IndexByte(b, ';'); n >= 0 {
+ b = b[:n]
+ }
+ if len(b) > 1 && b[0] == '"' && b[len(b)-1] == '"' {
+ b = b[1 : len(b)-1]
+ }
+ return b
+ }
+ return nil
+}
+
+// Host returns Host header value.
+func (h *RequestHeader) Host() []byte {
+ if h.disableSpecialHeader {
+ return peekArgBytes(h.h, []byte(HeaderHost))
+ }
+ return h.host
+}
+
+// SetHost sets Host header value.
+func (h *RequestHeader) SetHost(host string) {
+ h.host = append(h.host[:0], host...)
+}
+
+// SetHostBytes sets Host header value.
+func (h *RequestHeader) SetHostBytes(host []byte) {
+ h.host = append(h.host[:0], host...)
+}
+
+// UserAgent returns User-Agent header value.
+func (h *RequestHeader) UserAgent() []byte {
+ if h.disableSpecialHeader {
+ return peekArgBytes(h.h, []byte(HeaderUserAgent))
+ }
+ return h.userAgent
+}
+
+// SetUserAgent sets User-Agent header value.
+func (h *RequestHeader) SetUserAgent(userAgent string) {
+ h.userAgent = append(h.userAgent[:0], userAgent...)
+}
+
+// SetUserAgentBytes sets User-Agent header value.
+func (h *RequestHeader) SetUserAgentBytes(userAgent []byte) {
+ h.userAgent = append(h.userAgent[:0], userAgent...)
+}
+
+// Referer returns Referer header value.
+func (h *RequestHeader) Referer() []byte {
+ return peekArgBytes(h.h, strReferer)
+}
+
+// SetReferer sets Referer header value.
+func (h *RequestHeader) SetReferer(referer string) {
+ h.SetBytesK(strReferer, referer)
+}
+
+// SetRefererBytes sets Referer header value.
+func (h *RequestHeader) SetRefererBytes(referer []byte) {
+ h.setNonSpecial(strReferer, referer)
+}
+
+// Method returns HTTP request method.
+func (h *RequestHeader) Method() []byte {
+ if len(h.method) == 0 {
+ return []byte(MethodGet)
+ }
+ return h.method
+}
+
+// SetMethod sets HTTP request method.
+func (h *RequestHeader) SetMethod(method string) {
+ h.method = append(h.method[:0], method...)
+}
+
+// SetMethodBytes sets HTTP request method.
+func (h *RequestHeader) SetMethodBytes(method []byte) {
+ h.method = append(h.method[:0], method...)
+}
+
+// Protocol returns HTTP protocol.
+func (h *RequestHeader) Protocol() []byte {
+ if len(h.proto) == 0 {
+ return strHTTP11
+ }
+ return h.proto
+}
+
+// SetProtocol sets HTTP request protocol.
+func (h *RequestHeader) SetProtocol(method string) {
+ h.proto = append(h.proto[:0], method...)
+ h.noHTTP11 = !bytes.Equal(h.proto, strHTTP11)
+}
+
+// SetProtocolBytes sets HTTP request protocol.
+func (h *RequestHeader) SetProtocolBytes(method []byte) {
+ h.proto = append(h.proto[:0], method...)
+ h.noHTTP11 = !bytes.Equal(h.proto, strHTTP11)
+}
+
+// RequestURI returns RequestURI from the first HTTP request line.
+func (h *RequestHeader) RequestURI() []byte {
+ requestURI := h.requestURI
+ if len(requestURI) == 0 {
+ requestURI = strSlash
+ }
+ return requestURI
+}
+
+// SetRequestURI sets RequestURI for the first HTTP request line.
+// RequestURI must be properly encoded.
+// Use URI.RequestURI for constructing proper RequestURI if unsure.
+func (h *RequestHeader) SetRequestURI(requestURI string) {
+ h.requestURI = append(h.requestURI[:0], requestURI...)
+}
+
+// SetRequestURIBytes sets RequestURI for the first HTTP request line.
+// RequestURI must be properly encoded.
+// Use URI.RequestURI for constructing proper RequestURI if unsure.
+func (h *RequestHeader) SetRequestURIBytes(requestURI []byte) {
+ h.requestURI = append(h.requestURI[:0], requestURI...)
+}
+
+// SetTrailer sets Trailer header value for chunked request
+// to indicate which headers will be sent after the body.
+//
+// Use Set to set the trailer header later.
+//
+// Trailers are only supported with chunked transfer.
+// Trailers allow the sender to include additional headers at the end of chunked messages.
+//
+// The following trailers are forbidden:
+// 1. necessary for message framing (e.g., Transfer-Encoding and Content-Length),
+// 2. routing (e.g., Host),
+// 3. request modifiers (e.g., controls and conditionals in Section 5 of [RFC7231]),
+// 4. authentication (e.g., see [RFC7235] and [RFC6265]),
+// 5. response control data (e.g., see Section 7.1 of [RFC7231]),
+// 6. determining how to process the payload (e.g., Content-Encoding, Content-Type, Content-Range, and Trailer)
+//
+// Return ErrBadTrailer if contain any forbidden trailers.
+func (h *RequestHeader) SetTrailer(trailer string) error {
+ return h.SetTrailerBytes(s2b(trailer))
+}
+
+// SetTrailerBytes sets Trailer header value for chunked request
+// to indicate which headers will be sent after the body.
+//
+// Use Set to set the trailer header later.
+//
+// Trailers are only supported with chunked transfer.
+// Trailers allow the sender to include additional headers at the end of chunked messages.
+//
+// The following trailers are forbidden:
+// 1. necessary for message framing (e.g., Transfer-Encoding and Content-Length),
+// 2. routing (e.g., Host),
+// 3. request modifiers (e.g., controls and conditionals in Section 5 of [RFC7231]),
+// 4. authentication (e.g., see [RFC7235] and [RFC6265]),
+// 5. response control data (e.g., see Section 7.1 of [RFC7231]),
+// 6. determining how to process the payload (e.g., Content-Encoding, Content-Type, Content-Range, and Trailer)
+//
+// Return ErrBadTrailer if contain any forbidden trailers.
+func (h *RequestHeader) SetTrailerBytes(trailer []byte) error {
+ h.trailer = h.trailer[:0]
+ return h.AddTrailerBytes(trailer)
+}
+
+// AddTrailer add Trailer header value for chunked request
+// to indicate which headers will be sent after the body.
+//
+// Use Set to set the trailer header later.
+//
+// Trailers are only supported with chunked transfer.
+// Trailers allow the sender to include additional headers at the end of chunked messages.
+//
+// The following trailers are forbidden:
+// 1. necessary for message framing (e.g., Transfer-Encoding and Content-Length),
+// 2. routing (e.g., Host),
+// 3. request modifiers (e.g., controls and conditionals in Section 5 of [RFC7231]),
+// 4. authentication (e.g., see [RFC7235] and [RFC6265]),
+// 5. response control data (e.g., see Section 7.1 of [RFC7231]),
+// 6. determining how to process the payload (e.g., Content-Encoding, Content-Type, Content-Range, and Trailer)
+//
+// Return ErrBadTrailer if contain any forbidden trailers.
+func (h *RequestHeader) AddTrailer(trailer string) error {
+ return h.AddTrailerBytes(s2b(trailer))
+}
+
+// AddTrailerBytes add Trailer header value for chunked request
+// to indicate which headers will be sent after the body.
+//
+// Use Set to set the trailer header later.
+//
+// Trailers are only supported with chunked transfer.
+// Trailers allow the sender to include additional headers at the end of chunked messages.
+//
+// The following trailers are forbidden:
+// 1. necessary for message framing (e.g., Transfer-Encoding and Content-Length),
+// 2. routing (e.g., Host),
+// 3. request modifiers (e.g., controls and conditionals in Section 5 of [RFC7231]),
+// 4. authentication (e.g., see [RFC7235] and [RFC6265]),
+// 5. response control data (e.g., see Section 7.1 of [RFC7231]),
+// 6. determining how to process the payload (e.g., Content-Encoding, Content-Type, Content-Range, and Trailer)
+//
+// Return ErrBadTrailer if contain any forbidden trailers.
+func (h *RequestHeader) AddTrailerBytes(trailer []byte) error {
+ var err error
+ for i := -1; i+1 < len(trailer); {
+ trailer = trailer[i+1:]
+ i = bytes.IndexByte(trailer, ',')
+ if i < 0 {
+ i = len(trailer)
+ }
+ key := trailer[:i]
+ for len(key) > 0 && key[0] == ' ' {
+ key = key[1:]
+ }
+ for len(key) > 0 && key[len(key)-1] == ' ' {
+ key = key[:len(key)-1]
+ }
+ // Forbidden by RFC 7230, section 4.1.2
+ if isBadTrailer(key) {
+ err = ErrBadTrailer
+ continue
+ }
+ h.bufKV.key = append(h.bufKV.key[:0], key...)
+ normalizeHeaderKey(h.bufKV.key, h.disableNormalizing)
+ h.trailer = appendArgBytes(h.trailer, h.bufKV.key, nil, argsNoValue)
+ }
+
+ return err
+}
+
+// IsGet returns true if request method is GET.
+func (h *RequestHeader) IsGet() bool {
+ return string(h.Method()) == MethodGet
+}
+
+// IsPost returns true if request method is POST.
+func (h *RequestHeader) IsPost() bool {
+ return string(h.Method()) == MethodPost
+}
+
+// IsPut returns true if request method is PUT.
+func (h *RequestHeader) IsPut() bool {
+ return string(h.Method()) == MethodPut
+}
+
+// IsHead returns true if request method is HEAD.
+func (h *RequestHeader) IsHead() bool {
+ return string(h.Method()) == MethodHead
+}
+
+// IsDelete returns true if request method is DELETE.
+func (h *RequestHeader) IsDelete() bool {
+ return string(h.Method()) == MethodDelete
+}
+
+// IsConnect returns true if request method is CONNECT.
+func (h *RequestHeader) IsConnect() bool {
+ return string(h.Method()) == MethodConnect
+}
+
+// IsOptions returns true if request method is OPTIONS.
+func (h *RequestHeader) IsOptions() bool {
+ return string(h.Method()) == MethodOptions
+}
+
+// IsTrace returns true if request method is TRACE.
+func (h *RequestHeader) IsTrace() bool {
+ return string(h.Method()) == MethodTrace
+}
+
+// IsPatch returns true if request method is PATCH.
+func (h *RequestHeader) IsPatch() bool {
+ return string(h.Method()) == MethodPatch
+}
+
+// IsHTTP11 returns true if the request is HTTP/1.1.
+func (h *RequestHeader) IsHTTP11() bool {
+ return !h.noHTTP11
+}
+
+// IsHTTP11 returns true if the response is HTTP/1.1.
+func (h *ResponseHeader) IsHTTP11() bool {
+ return !h.noHTTP11
+}
+
+// HasAcceptEncoding returns true if the header contains
+// the given Accept-Encoding value.
+func (h *RequestHeader) HasAcceptEncoding(acceptEncoding string) bool {
+ h.bufKV.value = append(h.bufKV.value[:0], acceptEncoding...)
+ return h.HasAcceptEncodingBytes(h.bufKV.value)
+}
+
+// HasAcceptEncodingBytes returns true if the header contains
+// the given Accept-Encoding value.
+func (h *RequestHeader) HasAcceptEncodingBytes(acceptEncoding []byte) bool {
+ ae := h.peek(strAcceptEncoding)
+ n := bytes.Index(ae, acceptEncoding)
+ if n < 0 {
+ return false
+ }
+ b := ae[n+len(acceptEncoding):]
+ if len(b) > 0 && b[0] != ',' {
+ return false
+ }
+ if n == 0 {
+ return true
+ }
+ return ae[n-1] == ' '
+}
+
+// Len returns the number of headers set,
+// i.e. the number of times f is called in VisitAll.
+func (h *ResponseHeader) Len() int {
+ n := 0
+ h.VisitAll(func(_, _ []byte) { n++ })
+ return n
+}
+
+// Len returns the number of headers set,
+// i.e. the number of times f is called in VisitAll.
+func (h *RequestHeader) Len() int {
+ n := 0
+ h.VisitAll(func(_, _ []byte) { n++ })
+ return n
+}
+
+// DisableSpecialHeader disables special header processing.
+// fasthttp will not set any special headers for you, such as Host, Content-Type, User-Agent, etc.
+// You must set everything yourself.
+// If RequestHeader.Read() is called, special headers will be ignored.
+// This can be used to control case and order of special headers.
+// This is generally not recommended.
+func (h *RequestHeader) DisableSpecialHeader() {
+ h.disableSpecialHeader = true
+}
+
+// EnableSpecialHeader enables special header processing.
+// fasthttp will send Host, Content-Type, User-Agent, etc headers for you.
+// This is suggested and enabled by default.
+func (h *RequestHeader) EnableSpecialHeader() {
+ h.disableSpecialHeader = false
+}
+
+// DisableNormalizing disables header names' normalization.
+//
+// By default all the header names are normalized by uppercasing
+// the first letter and all the first letters following dashes,
+// while lowercasing all the other letters.
+// Examples:
+//
+// - CONNECTION -> Connection
+// - conteNT-tYPE -> Content-Type
+// - foo-bar-baz -> Foo-Bar-Baz
+//
+// Disable header names' normalization only if know what are you doing.
+func (h *RequestHeader) DisableNormalizing() {
+ h.disableNormalizing = true
+}
+
+// EnableNormalizing enables header names' normalization.
+//
+// Header names are normalized by uppercasing the first letter and
+// all the first letters following dashes, while lowercasing all
+// the other letters.
+// Examples:
+//
+// - CONNECTION -> Connection
+// - conteNT-tYPE -> Content-Type
+// - foo-bar-baz -> Foo-Bar-Baz
+//
+// This is enabled by default unless disabled using DisableNormalizing()
+func (h *RequestHeader) EnableNormalizing() {
+ h.disableNormalizing = false
+}
+
+// DisableNormalizing disables header names' normalization.
+//
+// By default all the header names are normalized by uppercasing
+// the first letter and all the first letters following dashes,
+// while lowercasing all the other letters.
+// Examples:
+//
+// - CONNECTION -> Connection
+// - conteNT-tYPE -> Content-Type
+// - foo-bar-baz -> Foo-Bar-Baz
+//
+// Disable header names' normalization only if know what are you doing.
+func (h *ResponseHeader) DisableNormalizing() {
+ h.disableNormalizing = true
+}
+
+// EnableNormalizing enables header names' normalization.
+//
+// Header names are normalized by uppercasing the first letter and
+// all the first letters following dashes, while lowercasing all
+// the other letters.
+// Examples:
+//
+// - CONNECTION -> Connection
+// - conteNT-tYPE -> Content-Type
+// - foo-bar-baz -> Foo-Bar-Baz
+//
+// This is enabled by default unless disabled using DisableNormalizing()
+func (h *ResponseHeader) EnableNormalizing() {
+ h.disableNormalizing = false
+}
+
+// SetNoDefaultContentType allows you to control if a default Content-Type header will be set (false) or not (true).
+func (h *ResponseHeader) SetNoDefaultContentType(noDefaultContentType bool) {
+ h.noDefaultContentType = noDefaultContentType
+}
+
+// Reset clears response header.
+func (h *ResponseHeader) Reset() {
+ h.disableNormalizing = false
+ h.SetNoDefaultContentType(false)
+ h.noDefaultDate = false
+ h.resetSkipNormalize()
+}
+
+func (h *ResponseHeader) resetSkipNormalize() {
+ h.noHTTP11 = false
+ h.connectionClose = false
+
+ h.statusCode = 0
+ h.statusMessage = h.statusMessage[:0]
+ h.protocol = h.protocol[:0]
+ h.contentLength = 0
+ h.contentLengthBytes = h.contentLengthBytes[:0]
+
+ h.contentType = h.contentType[:0]
+ h.contentEncoding = h.contentEncoding[:0]
+ h.server = h.server[:0]
+
+ h.h = h.h[:0]
+ h.cookies = h.cookies[:0]
+ h.trailer = h.trailer[:0]
+ h.mulHeader = h.mulHeader[:0]
+}
+
+// SetNoDefaultContentType allows you to control if a default Content-Type header will be set (false) or not (true).
+func (h *RequestHeader) SetNoDefaultContentType(noDefaultContentType bool) {
+ h.noDefaultContentType = noDefaultContentType
+}
+
+// Reset clears request header.
+func (h *RequestHeader) Reset() {
+ h.disableSpecialHeader = false
+ h.disableNormalizing = false
+ h.SetNoDefaultContentType(false)
+ h.resetSkipNormalize()
+}
+
+func (h *RequestHeader) resetSkipNormalize() {
+ h.noHTTP11 = false
+ h.connectionClose = false
+
+ h.contentLength = 0
+ h.contentLengthBytes = h.contentLengthBytes[:0]
+
+ h.method = h.method[:0]
+ h.proto = h.proto[:0]
+ h.requestURI = h.requestURI[:0]
+ h.host = h.host[:0]
+ h.contentType = h.contentType[:0]
+ h.userAgent = h.userAgent[:0]
+ h.trailer = h.trailer[:0]
+ h.mulHeader = h.mulHeader[:0]
+
+ h.h = h.h[:0]
+ h.cookies = h.cookies[:0]
+ h.cookiesCollected = false
+
+ h.rawHeaders = h.rawHeaders[:0]
+}
+
+// CopyTo copies all the headers to dst.
+func (h *ResponseHeader) CopyTo(dst *ResponseHeader) {
+ dst.Reset()
+
+ dst.disableNormalizing = h.disableNormalizing
+ dst.noHTTP11 = h.noHTTP11
+ dst.connectionClose = h.connectionClose
+ dst.noDefaultContentType = h.noDefaultContentType
+ dst.noDefaultDate = h.noDefaultDate
+
+ dst.statusCode = h.statusCode
+ dst.statusMessage = append(dst.statusMessage, h.statusMessage...)
+ dst.protocol = append(dst.protocol, h.protocol...)
+ dst.contentLength = h.contentLength
+ dst.contentLengthBytes = append(dst.contentLengthBytes, h.contentLengthBytes...)
+ dst.contentType = append(dst.contentType, h.contentType...)
+ dst.contentEncoding = append(dst.contentEncoding, h.contentEncoding...)
+ dst.server = append(dst.server, h.server...)
+ dst.h = copyArgs(dst.h, h.h)
+ dst.cookies = copyArgs(dst.cookies, h.cookies)
+ dst.trailer = copyArgs(dst.trailer, h.trailer)
+}
+
+// CopyTo copies all the headers to dst.
+func (h *RequestHeader) CopyTo(dst *RequestHeader) {
+ dst.Reset()
+
+ dst.disableNormalizing = h.disableNormalizing
+ dst.noHTTP11 = h.noHTTP11
+ dst.connectionClose = h.connectionClose
+ dst.noDefaultContentType = h.noDefaultContentType
+
+ dst.contentLength = h.contentLength
+ dst.contentLengthBytes = append(dst.contentLengthBytes, h.contentLengthBytes...)
+ dst.method = append(dst.method, h.method...)
+ dst.proto = append(dst.proto, h.proto...)
+ dst.requestURI = append(dst.requestURI, h.requestURI...)
+ dst.host = append(dst.host, h.host...)
+ dst.contentType = append(dst.contentType, h.contentType...)
+ dst.userAgent = append(dst.userAgent, h.userAgent...)
+ dst.trailer = append(dst.trailer, h.trailer...)
+ dst.h = copyArgs(dst.h, h.h)
+ dst.cookies = copyArgs(dst.cookies, h.cookies)
+ dst.cookiesCollected = h.cookiesCollected
+ dst.rawHeaders = append(dst.rawHeaders, h.rawHeaders...)
+}
+
+// VisitAll calls f for each header.
+//
+// f must not retain references to key and/or value after returning.
+// Copy key and/or value contents before returning if you need retaining them.
+func (h *ResponseHeader) VisitAll(f func(key, value []byte)) {
+ if len(h.contentLengthBytes) > 0 {
+ f(strContentLength, h.contentLengthBytes)
+ }
+ contentType := h.ContentType()
+ if len(contentType) > 0 {
+ f(strContentType, contentType)
+ }
+ contentEncoding := h.ContentEncoding()
+ if len(contentEncoding) > 0 {
+ f(strContentEncoding, contentEncoding)
+ }
+ server := h.Server()
+ if len(server) > 0 {
+ f(strServer, server)
+ }
+ if len(h.cookies) > 0 {
+ visitArgs(h.cookies, func(_, v []byte) {
+ f(strSetCookie, v)
+ })
+ }
+ if len(h.trailer) > 0 {
+ f(strTrailer, appendArgsKeyBytes(nil, h.trailer, strCommaSpace))
+ }
+ visitArgs(h.h, f)
+ if h.ConnectionClose() {
+ f(strConnection, strClose)
+ }
+}
+
+// VisitAllTrailer calls f for each response Trailer.
+//
+// f must not retain references to value after returning.
+func (h *ResponseHeader) VisitAllTrailer(f func(value []byte)) {
+ visitArgsKey(h.trailer, f)
+}
+
+// VisitAllTrailer calls f for each request Trailer.
+//
+// f must not retain references to value after returning.
+func (h *RequestHeader) VisitAllTrailer(f func(value []byte)) {
+ visitArgsKey(h.trailer, f)
+}
+
+// VisitAllCookie calls f for each response cookie.
+//
+// Cookie name is passed in key and the whole Set-Cookie header value
+// is passed in value on each f invocation. Value may be parsed
+// with Cookie.ParseBytes().
+//
+// f must not retain references to key and/or value after returning.
+func (h *ResponseHeader) VisitAllCookie(f func(key, value []byte)) {
+ visitArgs(h.cookies, f)
+}
+
+// VisitAllCookie calls f for each request cookie.
+//
+// f must not retain references to key and/or value after returning.
+func (h *RequestHeader) VisitAllCookie(f func(key, value []byte)) {
+ h.collectCookies()
+ visitArgs(h.cookies, f)
+}
+
+// VisitAll calls f for each header.
+//
+// f must not retain references to key and/or value after returning.
+// Copy key and/or value contents before returning if you need retaining them.
+//
+// To get the headers in order they were received use VisitAllInOrder.
+func (h *RequestHeader) VisitAll(f func(key, value []byte)) {
+ host := h.Host()
+ if len(host) > 0 {
+ f(strHost, host)
+ }
+ if len(h.contentLengthBytes) > 0 {
+ f(strContentLength, h.contentLengthBytes)
+ }
+ contentType := h.ContentType()
+ if len(contentType) > 0 {
+ f(strContentType, contentType)
+ }
+ userAgent := h.UserAgent()
+ if len(userAgent) > 0 {
+ f(strUserAgent, userAgent)
+ }
+ if len(h.trailer) > 0 {
+ f(strTrailer, appendArgsKeyBytes(nil, h.trailer, strCommaSpace))
+ }
+
+ h.collectCookies()
+ if len(h.cookies) > 0 {
+ h.bufKV.value = appendRequestCookieBytes(h.bufKV.value[:0], h.cookies)
+ f(strCookie, h.bufKV.value)
+ }
+ visitArgs(h.h, f)
+ if h.ConnectionClose() {
+ f(strConnection, strClose)
+ }
+}
+
+// VisitAllInOrder calls f for each header in the order they were received.
+//
+// f must not retain references to key and/or value after returning.
+// Copy key and/or value contents before returning if you need retaining them.
+//
+// This function is slightly slower than VisitAll because it has to reparse the
+// raw headers to get the order.
+func (h *RequestHeader) VisitAllInOrder(f func(key, value []byte)) {
+ var s headerScanner
+ s.b = h.rawHeaders
+ s.disableNormalizing = h.disableNormalizing
+ for s.next() {
+ if len(s.key) > 0 {
+ f(s.key, s.value)
+ }
+ }
+}
+
+// Del deletes header with the given key.
+func (h *ResponseHeader) Del(key string) {
+ k := getHeaderKeyBytes(&h.bufKV, key, h.disableNormalizing)
+ h.del(k)
+}
+
+// DelBytes deletes header with the given key.
+func (h *ResponseHeader) DelBytes(key []byte) {
+ h.bufKV.key = append(h.bufKV.key[:0], key...)
+ normalizeHeaderKey(h.bufKV.key, h.disableNormalizing)
+ h.del(h.bufKV.key)
+}
+
+func (h *ResponseHeader) del(key []byte) {
+ switch string(key) {
+ case HeaderContentType:
+ h.contentType = h.contentType[:0]
+ case HeaderContentEncoding:
+ h.contentEncoding = h.contentEncoding[:0]
+ case HeaderServer:
+ h.server = h.server[:0]
+ case HeaderSetCookie:
+ h.cookies = h.cookies[:0]
+ case HeaderContentLength:
+ h.contentLength = 0
+ h.contentLengthBytes = h.contentLengthBytes[:0]
+ case HeaderConnection:
+ h.connectionClose = false
+ case HeaderTrailer:
+ h.trailer = h.trailer[:0]
+ }
+ h.h = delAllArgsBytes(h.h, key)
+}
+
+// Del deletes header with the given key.
+func (h *RequestHeader) Del(key string) {
+ k := getHeaderKeyBytes(&h.bufKV, key, h.disableNormalizing)
+ h.del(k)
+}
+
+// DelBytes deletes header with the given key.
+func (h *RequestHeader) DelBytes(key []byte) {
+ h.bufKV.key = append(h.bufKV.key[:0], key...)
+ normalizeHeaderKey(h.bufKV.key, h.disableNormalizing)
+ h.del(h.bufKV.key)
+}
+
+func (h *RequestHeader) del(key []byte) {
+ switch string(key) {
+ case HeaderHost:
+ h.host = h.host[:0]
+ case HeaderContentType:
+ h.contentType = h.contentType[:0]
+ case HeaderUserAgent:
+ h.userAgent = h.userAgent[:0]
+ case HeaderCookie:
+ h.cookies = h.cookies[:0]
+ case HeaderContentLength:
+ h.contentLength = 0
+ h.contentLengthBytes = h.contentLengthBytes[:0]
+ case HeaderConnection:
+ h.connectionClose = false
+ case HeaderTrailer:
+ h.trailer = h.trailer[:0]
+ }
+ h.h = delAllArgsBytes(h.h, key)
+}
+
+// setSpecialHeader handles special headers and return true when a header is processed.
+func (h *ResponseHeader) setSpecialHeader(key, value []byte) bool {
+ if len(key) == 0 {
+ return false
+ }
+
+ switch key[0] | 0x20 {
+ case 'c':
+ switch {
+ case caseInsensitiveCompare(strContentType, key):
+ h.SetContentTypeBytes(value)
+ return true
+ case caseInsensitiveCompare(strContentLength, key):
+ if contentLength, err := parseContentLength(value); err == nil {
+ h.contentLength = contentLength
+ h.contentLengthBytes = append(h.contentLengthBytes[:0], value...)
+ }
+ return true
+ case caseInsensitiveCompare(strContentEncoding, key):
+ h.SetContentEncodingBytes(value)
+ return true
+ case caseInsensitiveCompare(strConnection, key):
+ if bytes.Equal(strClose, value) {
+ h.SetConnectionClose()
+ } else {
+ h.ResetConnectionClose()
+ h.setNonSpecial(key, value)
+ }
+ return true
+ }
+ case 's':
+ if caseInsensitiveCompare(strServer, key) {
+ h.SetServerBytes(value)
+ return true
+ } else if caseInsensitiveCompare(strSetCookie, key) {
+ var kv *argsKV
+ h.cookies, kv = allocArg(h.cookies)
+ kv.key = getCookieKey(kv.key, value)
+ kv.value = append(kv.value[:0], value...)
+ return true
+ }
+ case 't':
+ if caseInsensitiveCompare(strTransferEncoding, key) {
+ // Transfer-Encoding is managed automatically.
+ return true
+ } else if caseInsensitiveCompare(strTrailer, key) {
+ _ = h.SetTrailerBytes(value)
+ return true
+ }
+ case 'd':
+ if caseInsensitiveCompare(strDate, key) {
+ // Date is managed automatically.
+ return true
+ }
+ }
+
+ return false
+}
+
+// setNonSpecial directly put into map i.e. not a basic header
+func (h *ResponseHeader) setNonSpecial(key []byte, value []byte) {
+ h.h = setArgBytes(h.h, key, value, argsHasValue)
+}
+
+// setSpecialHeader handles special headers and return true when a header is processed.
+func (h *RequestHeader) setSpecialHeader(key, value []byte) bool {
+ if len(key) == 0 || h.disableSpecialHeader {
+ return false
+ }
+
+ switch key[0] | 0x20 {
+ case 'c':
+ switch {
+ case caseInsensitiveCompare(strContentType, key):
+ h.SetContentTypeBytes(value)
+ return true
+ case caseInsensitiveCompare(strContentLength, key):
+ if contentLength, err := parseContentLength(value); err == nil {
+ h.contentLength = contentLength
+ h.contentLengthBytes = append(h.contentLengthBytes[:0], value...)
+ }
+ return true
+ case caseInsensitiveCompare(strConnection, key):
+ if bytes.Equal(strClose, value) {
+ h.SetConnectionClose()
+ } else {
+ h.ResetConnectionClose()
+ h.setNonSpecial(key, value)
+ }
+ return true
+ case caseInsensitiveCompare(strCookie, key):
+ h.collectCookies()
+ h.cookies = parseRequestCookies(h.cookies, value)
+ return true
+ }
+ case 't':
+ if caseInsensitiveCompare(strTransferEncoding, key) {
+ // Transfer-Encoding is managed automatically.
+ return true
+ } else if caseInsensitiveCompare(strTrailer, key) {
+ _ = h.SetTrailerBytes(value)
+ return true
+ }
+ case 'h':
+ if caseInsensitiveCompare(strHost, key) {
+ h.SetHostBytes(value)
+ return true
+ }
+ case 'u':
+ if caseInsensitiveCompare(strUserAgent, key) {
+ h.SetUserAgentBytes(value)
+ return true
+ }
+ }
+
+ return false
+}
+
+// setNonSpecial directly put into map i.e. not a basic header
+func (h *RequestHeader) setNonSpecial(key []byte, value []byte) {
+ h.h = setArgBytes(h.h, key, value, argsHasValue)
+}
+
+// Add adds the given 'key: value' header.
+//
+// Multiple headers with the same key may be added with this function.
+// Use Set for setting a single header for the given key.
+//
+// the Content-Type, Content-Length, Connection, Server, Set-Cookie,
+// Transfer-Encoding and Date headers can only be set once and will
+// overwrite the previous value.
+//
+// If the header is set as a Trailer (forbidden trailers will not be set, see AddTrailer for more details),
+// it will be sent after the chunked response body.
+func (h *ResponseHeader) Add(key, value string) {
+ h.AddBytesKV(s2b(key), s2b(value))
+}
+
+// AddBytesK adds the given 'key: value' header.
+//
+// Multiple headers with the same key may be added with this function.
+// Use SetBytesK for setting a single header for the given key.
+//
+// the Content-Type, Content-Length, Connection, Server, Set-Cookie,
+// Transfer-Encoding and Date headers can only be set once and will
+// overwrite the previous value.
+//
+// If the header is set as a Trailer (forbidden trailers will not be set, see AddTrailer for more details),
+// it will be sent after the chunked response body.
+func (h *ResponseHeader) AddBytesK(key []byte, value string) {
+ h.AddBytesKV(key, s2b(value))
+}
+
+// AddBytesV adds the given 'key: value' header.
+//
+// Multiple headers with the same key may be added with this function.
+// Use SetBytesV for setting a single header for the given key.
+//
+// the Content-Type, Content-Length, Connection, Server, Set-Cookie,
+// Transfer-Encoding and Date headers can only be set once and will
+// overwrite the previous value.
+//
+// If the header is set as a Trailer (forbidden trailers will not be set, see AddTrailer for more details),
+// it will be sent after the chunked response body.
+func (h *ResponseHeader) AddBytesV(key string, value []byte) {
+ h.AddBytesKV(s2b(key), value)
+}
+
+// AddBytesKV adds the given 'key: value' header.
+//
+// Multiple headers with the same key may be added with this function.
+// Use SetBytesKV for setting a single header for the given key.
+//
+// the Content-Type, Content-Length, Connection, Server, Set-Cookie,
+// Transfer-Encoding and Date headers can only be set once and will
+// overwrite the previous value.
+//
+// If the header is set as a Trailer (forbidden trailers will not be set, see AddTrailer for more details),
+// it will be sent after the chunked response body.
+func (h *ResponseHeader) AddBytesKV(key, value []byte) {
+ if h.setSpecialHeader(key, value) {
+ return
+ }
+
+ k := getHeaderKeyBytes(&h.bufKV, b2s(key), h.disableNormalizing)
+ h.h = appendArgBytes(h.h, k, value, argsHasValue)
+}
+
+// Set sets the given 'key: value' header.
+//
+// If the header is set as a Trailer (forbidden trailers will not be set, see SetTrailer for more details),
+// it will be sent after the chunked response body.
+//
+// Use Add for setting multiple header values under the same key.
+func (h *ResponseHeader) Set(key, value string) {
+ initHeaderKV(&h.bufKV, key, value, h.disableNormalizing)
+ h.SetCanonical(h.bufKV.key, h.bufKV.value)
+}
+
+// SetBytesK sets the given 'key: value' header.
+//
+// If the header is set as a Trailer (forbidden trailers will not be set, see SetTrailer for more details),
+// it will be sent after the chunked response body.
+//
+// Use AddBytesK for setting multiple header values under the same key.
+func (h *ResponseHeader) SetBytesK(key []byte, value string) {
+ h.bufKV.value = append(h.bufKV.value[:0], value...)
+ h.SetBytesKV(key, h.bufKV.value)
+}
+
+// SetBytesV sets the given 'key: value' header.
+//
+// If the header is set as a Trailer (forbidden trailers will not be set, see SetTrailer for more details),
+// it will be sent after the chunked response body.
+//
+// Use AddBytesV for setting multiple header values under the same key.
+func (h *ResponseHeader) SetBytesV(key string, value []byte) {
+ k := getHeaderKeyBytes(&h.bufKV, key, h.disableNormalizing)
+ h.SetCanonical(k, value)
+}
+
+// SetBytesKV sets the given 'key: value' header.
+//
+// If the header is set as a Trailer (forbidden trailers will not be set, see SetTrailer for more details),
+// it will be sent after the chunked response body.
+//
+// Use AddBytesKV for setting multiple header values under the same key.
+func (h *ResponseHeader) SetBytesKV(key, value []byte) {
+ h.bufKV.key = append(h.bufKV.key[:0], key...)
+ normalizeHeaderKey(h.bufKV.key, h.disableNormalizing)
+ h.SetCanonical(h.bufKV.key, value)
+}
+
+// SetCanonical sets the given 'key: value' header assuming that
+// key is in canonical form.
+//
+// If the header is set as a Trailer (forbidden trailers will not be set, see SetTrailer for more details),
+// it will be sent after the chunked response body.
+func (h *ResponseHeader) SetCanonical(key, value []byte) {
+ if h.setSpecialHeader(key, value) {
+ return
+ }
+ h.setNonSpecial(key, value)
+}
+
+// SetCookie sets the given response cookie.
+//
+// It is safe re-using the cookie after the function returns.
+func (h *ResponseHeader) SetCookie(cookie *Cookie) {
+ h.cookies = setArgBytes(h.cookies, cookie.Key(), cookie.Cookie(), argsHasValue)
+}
+
+// SetCookie sets 'key: value' cookies.
+func (h *RequestHeader) SetCookie(key, value string) {
+ h.collectCookies()
+ h.cookies = setArg(h.cookies, key, value, argsHasValue)
+}
+
+// SetCookieBytesK sets 'key: value' cookies.
+func (h *RequestHeader) SetCookieBytesK(key []byte, value string) {
+ h.SetCookie(b2s(key), value)
+}
+
+// SetCookieBytesKV sets 'key: value' cookies.
+func (h *RequestHeader) SetCookieBytesKV(key, value []byte) {
+ h.SetCookie(b2s(key), b2s(value))
+}
+
+// DelClientCookie instructs the client to remove the given cookie.
+// This doesn't work for a cookie with specific domain or path,
+// you should delete it manually like:
+//
+// c := AcquireCookie()
+// c.SetKey(key)
+// c.SetDomain("example.com")
+// c.SetPath("/path")
+// c.SetExpire(CookieExpireDelete)
+// h.SetCookie(c)
+// ReleaseCookie(c)
+//
+// Use DelCookie if you want just removing the cookie from response header.
+func (h *ResponseHeader) DelClientCookie(key string) {
+ h.DelCookie(key)
+
+ c := AcquireCookie()
+ c.SetKey(key)
+ c.SetExpire(CookieExpireDelete)
+ h.SetCookie(c)
+ ReleaseCookie(c)
+}
+
+// DelClientCookieBytes instructs the client to remove the given cookie.
+// This doesn't work for a cookie with specific domain or path,
+// you should delete it manually like:
+//
+// c := AcquireCookie()
+// c.SetKey(key)
+// c.SetDomain("example.com")
+// c.SetPath("/path")
+// c.SetExpire(CookieExpireDelete)
+// h.SetCookie(c)
+// ReleaseCookie(c)
+//
+// Use DelCookieBytes if you want just removing the cookie from response header.
+func (h *ResponseHeader) DelClientCookieBytes(key []byte) {
+ h.DelClientCookie(b2s(key))
+}
+
+// DelCookie removes cookie under the given key from response header.
+//
+// Note that DelCookie doesn't remove the cookie from the client.
+// Use DelClientCookie instead.
+func (h *ResponseHeader) DelCookie(key string) {
+ h.cookies = delAllArgs(h.cookies, key)
+}
+
+// DelCookieBytes removes cookie under the given key from response header.
+//
+// Note that DelCookieBytes doesn't remove the cookie from the client.
+// Use DelClientCookieBytes instead.
+func (h *ResponseHeader) DelCookieBytes(key []byte) {
+ h.DelCookie(b2s(key))
+}
+
+// DelCookie removes cookie under the given key.
+func (h *RequestHeader) DelCookie(key string) {
+ h.collectCookies()
+ h.cookies = delAllArgs(h.cookies, key)
+}
+
+// DelCookieBytes removes cookie under the given key.
+func (h *RequestHeader) DelCookieBytes(key []byte) {
+ h.DelCookie(b2s(key))
+}
+
+// DelAllCookies removes all the cookies from response headers.
+func (h *ResponseHeader) DelAllCookies() {
+ h.cookies = h.cookies[:0]
+}
+
+// DelAllCookies removes all the cookies from request headers.
+func (h *RequestHeader) DelAllCookies() {
+ h.collectCookies()
+ h.cookies = h.cookies[:0]
+}
+
+// Add adds the given 'key: value' header.
+//
+// Multiple headers with the same key may be added with this function.
+// Use Set for setting a single header for the given key.
+//
+// If the header is set as a Trailer (forbidden trailers will not be set, see AddTrailer for more details),
+// it will be sent after the chunked request body.
+func (h *RequestHeader) Add(key, value string) {
+ h.AddBytesKV(s2b(key), s2b(value))
+}
+
+// AddBytesK adds the given 'key: value' header.
+//
+// Multiple headers with the same key may be added with this function.
+// Use SetBytesK for setting a single header for the given key.
+//
+// If the header is set as a Trailer (forbidden trailers will not be set, see AddTrailer for more details),
+// it will be sent after the chunked request body.
+func (h *RequestHeader) AddBytesK(key []byte, value string) {
+ h.AddBytesKV(key, s2b(value))
+}
+
+// AddBytesV adds the given 'key: value' header.
+//
+// Multiple headers with the same key may be added with this function.
+// Use SetBytesV for setting a single header for the given key.
+//
+// If the header is set as a Trailer (forbidden trailers will not be set, see AddTrailer for more details),
+// it will be sent after the chunked request body.
+func (h *RequestHeader) AddBytesV(key string, value []byte) {
+ h.AddBytesKV(s2b(key), value)
+}
+
+// AddBytesKV adds the given 'key: value' header.
+//
+// Multiple headers with the same key may be added with this function.
+// Use SetBytesKV for setting a single header for the given key.
+//
+// the Content-Type, Content-Length, Connection, Cookie,
+// Transfer-Encoding, Host and User-Agent headers can only be set once
+// and will overwrite the previous value.
+//
+// If the header is set as a Trailer (forbidden trailers will not be set, see AddTrailer for more details),
+// it will be sent after the chunked request body.
+func (h *RequestHeader) AddBytesKV(key, value []byte) {
+ if h.setSpecialHeader(key, value) {
+ return
+ }
+
+ k := getHeaderKeyBytes(&h.bufKV, b2s(key), h.disableNormalizing)
+ h.h = appendArgBytes(h.h, k, value, argsHasValue)
+}
+
+// Set sets the given 'key: value' header.
+//
+// If the header is set as a Trailer (forbidden trailers will not be set, see SetTrailer for more details),
+// it will be sent after the chunked request body.
+//
+// Use Add for setting multiple header values under the same key.
+func (h *RequestHeader) Set(key, value string) {
+ initHeaderKV(&h.bufKV, key, value, h.disableNormalizing)
+ h.SetCanonical(h.bufKV.key, h.bufKV.value)
+}
+
+// SetBytesK sets the given 'key: value' header.
+//
+// If the header is set as a Trailer (forbidden trailers will not be set, see SetTrailer for more details),
+// it will be sent after the chunked request body.
+//
+// Use AddBytesK for setting multiple header values under the same key.
+func (h *RequestHeader) SetBytesK(key []byte, value string) {
+ h.bufKV.value = append(h.bufKV.value[:0], value...)
+ h.SetBytesKV(key, h.bufKV.value)
+}
+
+// SetBytesV sets the given 'key: value' header.
+//
+// If the header is set as a Trailer (forbidden trailers will not be set, see SetTrailer for more details),
+// it will be sent after the chunked request body.
+//
+// Use AddBytesV for setting multiple header values under the same key.
+func (h *RequestHeader) SetBytesV(key string, value []byte) {
+ k := getHeaderKeyBytes(&h.bufKV, key, h.disableNormalizing)
+ h.SetCanonical(k, value)
+}
+
+// SetBytesKV sets the given 'key: value' header.
+//
+// If the header is set as a Trailer (forbidden trailers will not be set, see SetTrailer for more details),
+// it will be sent after the chunked request body.
+//
+// Use AddBytesKV for setting multiple header values under the same key.
+func (h *RequestHeader) SetBytesKV(key, value []byte) {
+ h.bufKV.key = append(h.bufKV.key[:0], key...)
+ normalizeHeaderKey(h.bufKV.key, h.disableNormalizing)
+ h.SetCanonical(h.bufKV.key, value)
+}
+
+// SetCanonical sets the given 'key: value' header assuming that
+// key is in canonical form.
+//
+// If the header is set as a Trailer (forbidden trailers will not be set, see SetTrailer for more details),
+// it will be sent after the chunked request body.
+func (h *RequestHeader) SetCanonical(key, value []byte) {
+ if h.setSpecialHeader(key, value) {
+ return
+ }
+ h.setNonSpecial(key, value)
+}
+
+// Peek returns header value for the given key.
+//
+// The returned value is valid until the response is released,
+// either though ReleaseResponse or your request handler returning.
+// Do not store references to the returned value. Make copies instead.
+func (h *ResponseHeader) Peek(key string) []byte {
+ k := getHeaderKeyBytes(&h.bufKV, key, h.disableNormalizing)
+ return h.peek(k)
+}
+
+// PeekBytes returns header value for the given key.
+//
+// The returned value is valid until the response is released,
+// either though ReleaseResponse or your request handler returning.
+// Do not store references to returned value. Make copies instead.
+func (h *ResponseHeader) PeekBytes(key []byte) []byte {
+ h.bufKV.key = append(h.bufKV.key[:0], key...)
+ normalizeHeaderKey(h.bufKV.key, h.disableNormalizing)
+ return h.peek(h.bufKV.key)
+}
+
+// Peek returns header value for the given key.
+//
+// The returned value is valid until the request is released,
+// either though ReleaseRequest or your request handler returning.
+// Do not store references to returned value. Make copies instead.
+func (h *RequestHeader) Peek(key string) []byte {
+ k := getHeaderKeyBytes(&h.bufKV, key, h.disableNormalizing)
+ return h.peek(k)
+}
+
+// PeekBytes returns header value for the given key.
+//
+// The returned value is valid until the request is released,
+// either though ReleaseRequest or your request handler returning.
+// Do not store references to returned value. Make copies instead.
+func (h *RequestHeader) PeekBytes(key []byte) []byte {
+ h.bufKV.key = append(h.bufKV.key[:0], key...)
+ normalizeHeaderKey(h.bufKV.key, h.disableNormalizing)
+ return h.peek(h.bufKV.key)
+}
+
+func (h *ResponseHeader) peek(key []byte) []byte {
+ switch string(key) {
+ case HeaderContentType:
+ return h.ContentType()
+ case HeaderContentEncoding:
+ return h.ContentEncoding()
+ case HeaderServer:
+ return h.Server()
+ case HeaderConnection:
+ if h.ConnectionClose() {
+ return strClose
+ }
+ return peekArgBytes(h.h, key)
+ case HeaderContentLength:
+ return h.contentLengthBytes
+ case HeaderSetCookie:
+ return appendResponseCookieBytes(nil, h.cookies)
+ case HeaderTrailer:
+ return appendArgsKeyBytes(nil, h.trailer, strCommaSpace)
+ default:
+ return peekArgBytes(h.h, key)
+ }
+}
+
+func (h *RequestHeader) peek(key []byte) []byte {
+ switch string(key) {
+ case HeaderHost:
+ return h.Host()
+ case HeaderContentType:
+ return h.ContentType()
+ case HeaderUserAgent:
+ return h.UserAgent()
+ case HeaderConnection:
+ if h.ConnectionClose() {
+ return strClose
+ }
+ return peekArgBytes(h.h, key)
+ case HeaderContentLength:
+ return h.contentLengthBytes
+ case HeaderCookie:
+ if h.cookiesCollected {
+ return appendRequestCookieBytes(nil, h.cookies)
+ }
+ return peekArgBytes(h.h, key)
+ case HeaderTrailer:
+ return appendArgsKeyBytes(nil, h.trailer, strCommaSpace)
+ default:
+ return peekArgBytes(h.h, key)
+ }
+}
+
+// PeekAll returns all header value for the given key.
+//
+// The returned value is valid until the request is released,
+// either though ReleaseRequest or your request handler returning.
+// Any future calls to the Peek* will modify the returned value.
+// Do not store references to returned value. Make copies instead.
+func (h *RequestHeader) PeekAll(key string) [][]byte {
+ k := getHeaderKeyBytes(&h.bufKV, key, h.disableNormalizing)
+ return h.peekAll(k)
+}
+
+func (h *RequestHeader) peekAll(key []byte) [][]byte {
+ h.mulHeader = h.mulHeader[:0]
+ switch string(key) {
+ case HeaderHost:
+ if host := h.Host(); len(host) > 0 {
+ h.mulHeader = append(h.mulHeader, host)
+ }
+ case HeaderContentType:
+ if contentType := h.ContentType(); len(contentType) > 0 {
+ h.mulHeader = append(h.mulHeader, contentType)
+ }
+ case HeaderUserAgent:
+ if ua := h.UserAgent(); len(ua) > 0 {
+ h.mulHeader = append(h.mulHeader, ua)
+ }
+ case HeaderConnection:
+ if h.ConnectionClose() {
+ h.mulHeader = append(h.mulHeader, strClose)
+ } else {
+ h.mulHeader = peekAllArgBytesToDst(h.mulHeader, h.h, key)
+ }
+ case HeaderContentLength:
+ h.mulHeader = append(h.mulHeader, h.contentLengthBytes)
+ case HeaderCookie:
+ if h.cookiesCollected {
+ h.mulHeader = append(h.mulHeader, appendRequestCookieBytes(nil, h.cookies))
+ } else {
+ h.mulHeader = peekAllArgBytesToDst(h.mulHeader, h.h, key)
+ }
+ case HeaderTrailer:
+ h.mulHeader = append(h.mulHeader, appendArgsKeyBytes(nil, h.trailer, strCommaSpace))
+ default:
+ h.mulHeader = peekAllArgBytesToDst(h.mulHeader, h.h, key)
+ }
+ return h.mulHeader
+}
+
+// PeekAll returns all header value for the given key.
+//
+// The returned value is valid until the request is released,
+// either though ReleaseResponse or your request handler returning.
+// Any future calls to the Peek* will modify the returned value.
+// Do not store references to returned value. Make copies instead.
+func (h *ResponseHeader) PeekAll(key string) [][]byte {
+ k := getHeaderKeyBytes(&h.bufKV, key, h.disableNormalizing)
+ return h.peekAll(k)
+}
+
+func (h *ResponseHeader) peekAll(key []byte) [][]byte {
+ h.mulHeader = h.mulHeader[:0]
+ switch string(key) {
+ case HeaderContentType:
+ if contentType := h.ContentType(); len(contentType) > 0 {
+ h.mulHeader = append(h.mulHeader, contentType)
+ }
+ case HeaderContentEncoding:
+ if contentEncoding := h.ContentEncoding(); len(contentEncoding) > 0 {
+ h.mulHeader = append(h.mulHeader, contentEncoding)
+ }
+ case HeaderServer:
+ if server := h.Server(); len(server) > 0 {
+ h.mulHeader = append(h.mulHeader, server)
+ }
+ case HeaderConnection:
+ if h.ConnectionClose() {
+ h.mulHeader = append(h.mulHeader, strClose)
+ } else {
+ h.mulHeader = peekAllArgBytesToDst(h.mulHeader, h.h, key)
+ }
+ case HeaderContentLength:
+ h.mulHeader = append(h.mulHeader, h.contentLengthBytes)
+ case HeaderSetCookie:
+ h.mulHeader = append(h.mulHeader, appendResponseCookieBytes(nil, h.cookies))
+ case HeaderTrailer:
+ h.mulHeader = append(h.mulHeader, appendArgsKeyBytes(nil, h.trailer, strCommaSpace))
+ default:
+ h.mulHeader = peekAllArgBytesToDst(h.mulHeader, h.h, key)
+ }
+ return h.mulHeader
+}
+
+// PeekKeys return all header keys.
+//
+// The returned value is valid until the request is released,
+// either though ReleaseRequest or your request handler returning.
+// Any future calls to the Peek* will modify the returned value.
+// Do not store references to returned value. Make copies instead.
+func (h *RequestHeader) PeekKeys() [][]byte {
+ h.mulHeader = h.mulHeader[:0]
+ h.mulHeader = peekArgsKeys(h.mulHeader, h.h)
+ return h.mulHeader
+}
+
+// PeekTrailerKeys return all trailer keys.
+//
+// The returned value is valid until the request is released,
+// either though ReleaseRequest or your request handler returning.
+// Any future calls to the Peek* will modify the returned value.
+// Do not store references to returned value. Make copies instead.
+func (h *RequestHeader) PeekTrailerKeys() [][]byte {
+ h.mulHeader = h.mulHeader[:0]
+ h.mulHeader = peekArgsKeys(h.mulHeader, h.trailer)
+ return h.mulHeader
+}
+
+// PeekKeys return all header keys.
+//
+// The returned value is valid until the request is released,
+// either though ReleaseResponse or your request handler returning.
+// Any future calls to the Peek* will modify the returned value.
+// Do not store references to returned value. Make copies instead.
+func (h *ResponseHeader) PeekKeys() [][]byte {
+ h.mulHeader = h.mulHeader[:0]
+ h.mulHeader = peekArgsKeys(h.mulHeader, h.h)
+ return h.mulHeader
+}
+
+// PeekTrailerKeys return all trailer keys.
+//
+// The returned value is valid until the request is released,
+// either though ReleaseResponse or your request handler returning.
+// Any future calls to the Peek* will modify the returned value.
+// Do not store references to returned value. Make copies instead.
+func (h *ResponseHeader) PeekTrailerKeys() [][]byte {
+ h.mulHeader = h.mulHeader[:0]
+ h.mulHeader = peekArgsKeys(h.mulHeader, h.trailer)
+ return h.mulHeader
+}
+
+// Cookie returns cookie for the given key.
+func (h *RequestHeader) Cookie(key string) []byte {
+ h.collectCookies()
+ return peekArgStr(h.cookies, key)
+}
+
+// CookieBytes returns cookie for the given key.
+func (h *RequestHeader) CookieBytes(key []byte) []byte {
+ h.collectCookies()
+ return peekArgBytes(h.cookies, key)
+}
+
+// Cookie fills cookie for the given cookie.Key.
+//
+// Returns false if cookie with the given cookie.Key is missing.
+func (h *ResponseHeader) Cookie(cookie *Cookie) bool {
+ v := peekArgBytes(h.cookies, cookie.Key())
+ if v == nil {
+ return false
+ }
+ cookie.ParseBytes(v) //nolint:errcheck
+ return true
+}
+
+// Read reads response header from r.
+//
+// io.EOF is returned if r is closed before reading the first header byte.
+func (h *ResponseHeader) Read(r *bufio.Reader) error {
+ n := 1
+ for {
+ err := h.tryRead(r, n)
+ if err == nil {
+ return nil
+ }
+ if err != errNeedMore {
+ h.resetSkipNormalize()
+ return err
+ }
+ n = r.Buffered() + 1
+ }
+}
+
+func (h *ResponseHeader) tryRead(r *bufio.Reader, n int) error {
+ h.resetSkipNormalize()
+ b, err := r.Peek(n)
+ if len(b) == 0 {
+ // Return ErrTimeout on any timeout.
+ if x, ok := err.(interface{ Timeout() bool }); ok && x.Timeout() {
+ return ErrTimeout
+ }
+ // treat all other errors on the first byte read as EOF
+ if n == 1 || err == io.EOF {
+ return io.EOF
+ }
+
+ // This is for go 1.6 bug. See https://github.com/golang/go/issues/14121 .
+ if err == bufio.ErrBufferFull {
+ if h.secureErrorLogMessage {
+ return &ErrSmallBuffer{
+ error: fmt.Errorf("error when reading response headers"),
+ }
+ }
+ return &ErrSmallBuffer{
+ error: fmt.Errorf("error when reading response headers: %w", errSmallBuffer),
+ }
+ }
+
+ return fmt.Errorf("error when reading response headers: %w", err)
+ }
+ b = mustPeekBuffered(r)
+ headersLen, errParse := h.parse(b)
+ if errParse != nil {
+ return headerError("response", err, errParse, b, h.secureErrorLogMessage)
+ }
+ mustDiscard(r, headersLen)
+ return nil
+}
+
+// ReadTrailer reads response trailer header from r.
+//
+// io.EOF is returned if r is closed before reading the first byte.
+func (h *ResponseHeader) ReadTrailer(r *bufio.Reader) error {
+ n := 1
+ for {
+ err := h.tryReadTrailer(r, n)
+ if err == nil {
+ return nil
+ }
+ if err != errNeedMore {
+ return err
+ }
+ n = r.Buffered() + 1
+ }
+}
+
+func (h *ResponseHeader) tryReadTrailer(r *bufio.Reader, n int) error {
+ b, err := r.Peek(n)
+ if len(b) == 0 {
+ // Return ErrTimeout on any timeout.
+ if x, ok := err.(interface{ Timeout() bool }); ok && x.Timeout() {
+ return ErrTimeout
+ }
+
+ if n == 1 || err == io.EOF {
+ return io.EOF
+ }
+
+ // This is for go 1.6 bug. See https://github.com/golang/go/issues/14121 .
+ if err == bufio.ErrBufferFull {
+ if h.secureErrorLogMessage {
+ return &ErrSmallBuffer{
+ error: fmt.Errorf("error when reading response trailer"),
+ }
+ }
+ return &ErrSmallBuffer{
+ error: fmt.Errorf("error when reading response trailer: %w", errSmallBuffer),
+ }
+ }
+
+ return fmt.Errorf("error when reading response trailer: %w", err)
+ }
+ b = mustPeekBuffered(r)
+ headersLen, errParse := h.parseTrailer(b)
+ if errParse != nil {
+ if err == io.EOF {
+ return err
+ }
+ return headerError("response", err, errParse, b, h.secureErrorLogMessage)
+ }
+ mustDiscard(r, headersLen)
+ return nil
+}
+
+func headerError(typ string, err, errParse error, b []byte, secureErrorLogMessage bool) error {
+ if errParse != errNeedMore {
+ return headerErrorMsg(typ, errParse, b, secureErrorLogMessage)
+ }
+ if err == nil {
+ return errNeedMore
+ }
+
+ // Buggy servers may leave trailing CRLFs after http body.
+ // Treat this case as EOF.
+ if isOnlyCRLF(b) {
+ return io.EOF
+ }
+
+ if err != bufio.ErrBufferFull {
+ return headerErrorMsg(typ, err, b, secureErrorLogMessage)
+ }
+ return &ErrSmallBuffer{
+ error: headerErrorMsg(typ, errSmallBuffer, b, secureErrorLogMessage),
+ }
+}
+
+func headerErrorMsg(typ string, err error, b []byte, secureErrorLogMessage bool) error {
+ if secureErrorLogMessage {
+ return fmt.Errorf("error when reading %s headers: %w. Buffer size=%d", typ, err, len(b))
+ }
+ return fmt.Errorf("error when reading %s headers: %w. Buffer size=%d, contents: %s", typ, err, len(b), bufferSnippet(b))
+}
+
+// Read reads request header from r.
+//
+// io.EOF is returned if r is closed before reading the first header byte.
+func (h *RequestHeader) Read(r *bufio.Reader) error {
+ return h.readLoop(r, true)
+}
+
+// readLoop reads request header from r optionally loops until it has enough data.
+//
+// io.EOF is returned if r is closed before reading the first header byte.
+func (h *RequestHeader) readLoop(r *bufio.Reader, waitForMore bool) error {
+ n := 1
+ for {
+ err := h.tryRead(r, n)
+ if err == nil {
+ return nil
+ }
+ if !waitForMore || err != errNeedMore {
+ h.resetSkipNormalize()
+ return err
+ }
+ n = r.Buffered() + 1
+ }
+}
+
+// ReadTrailer reads request trailer header from r.
+//
+// io.EOF is returned if r is closed before reading the first byte.
+func (h *RequestHeader) ReadTrailer(r *bufio.Reader) error {
+ n := 1
+ for {
+ err := h.tryReadTrailer(r, n)
+ if err == nil {
+ return nil
+ }
+ if err != errNeedMore {
+ return err
+ }
+ n = r.Buffered() + 1
+ }
+}
+
+func (h *RequestHeader) tryReadTrailer(r *bufio.Reader, n int) error {
+ b, err := r.Peek(n)
+ if len(b) == 0 {
+ // Return ErrTimeout on any timeout.
+ if x, ok := err.(interface{ Timeout() bool }); ok && x.Timeout() {
+ return ErrTimeout
+ }
+
+ if n == 1 || err == io.EOF {
+ return io.EOF
+ }
+
+ // This is for go 1.6 bug. See https://github.com/golang/go/issues/14121 .
+ if err == bufio.ErrBufferFull {
+ if h.secureErrorLogMessage {
+ return &ErrSmallBuffer{
+ error: fmt.Errorf("error when reading request trailer"),
+ }
+ }
+ return &ErrSmallBuffer{
+ error: fmt.Errorf("error when reading request trailer: %w", errSmallBuffer),
+ }
+ }
+
+ return fmt.Errorf("error when reading request trailer: %w", err)
+ }
+ b = mustPeekBuffered(r)
+ headersLen, errParse := h.parseTrailer(b)
+ if errParse != nil {
+ if err == io.EOF {
+ return err
+ }
+ return headerError("request", err, errParse, b, h.secureErrorLogMessage)
+ }
+ mustDiscard(r, headersLen)
+ return nil
+}
+
+func (h *RequestHeader) tryRead(r *bufio.Reader, n int) error {
+ h.resetSkipNormalize()
+ b, err := r.Peek(n)
+ if len(b) == 0 {
+ if err == io.EOF {
+ return err
+ }
+
+ if err == nil {
+ panic("bufio.Reader.Peek() returned nil, nil")
+ }
+
+ // This is for go 1.6 bug. See https://github.com/golang/go/issues/14121 .
+ if err == bufio.ErrBufferFull {
+ return &ErrSmallBuffer{
+ error: fmt.Errorf("error when reading request headers: %w (n=%d, r.Buffered()=%d)", errSmallBuffer, n, r.Buffered()),
+ }
+ }
+
+ // n == 1 on the first read for the request.
+ if n == 1 {
+ // We didn't read a single byte.
+ return ErrNothingRead{err}
+ }
+
+ return fmt.Errorf("error when reading request headers: %w", err)
+ }
+ b = mustPeekBuffered(r)
+ headersLen, errParse := h.parse(b)
+ if errParse != nil {
+ return headerError("request", err, errParse, b, h.secureErrorLogMessage)
+ }
+ mustDiscard(r, headersLen)
+ return nil
+}
+
+func bufferSnippet(b []byte) string {
+ n := len(b)
+ start := 200
+ end := n - start
+ if start >= end {
+ start = n
+ end = n
+ }
+ bStart, bEnd := b[:start], b[end:]
+ if len(bEnd) == 0 {
+ return fmt.Sprintf("%q", b)
+ }
+ return fmt.Sprintf("%q...%q", bStart, bEnd)
+}
+
+func isOnlyCRLF(b []byte) bool {
+ for _, ch := range b {
+ if ch != rChar && ch != nChar {
+ return false
+ }
+ }
+ return true
+}
+
+func updateServerDate() {
+ refreshServerDate()
+ go func() {
+ for {
+ time.Sleep(time.Second)
+ refreshServerDate()
+ }
+ }()
+}
+
+var (
+ serverDate atomic.Value
+ serverDateOnce sync.Once // serverDateOnce.Do(updateServerDate)
+)
+
+func refreshServerDate() {
+ b := AppendHTTPDate(nil, time.Now())
+ serverDate.Store(b)
+}
+
+// Write writes response header to w.
+func (h *ResponseHeader) Write(w *bufio.Writer) error {
+ _, err := w.Write(h.Header())
+ return err
+}
+
+// WriteTo writes response header to w.
+//
+// WriteTo implements io.WriterTo interface.
+func (h *ResponseHeader) WriteTo(w io.Writer) (int64, error) {
+ n, err := w.Write(h.Header())
+ return int64(n), err
+}
+
+// Header returns response header representation.
+//
+// Headers that set as Trailer will not represent. Use TrailerHeader for trailers.
+//
+// The returned value is valid until the request is released,
+// either though ReleaseRequest or your request handler returning.
+// Do not store references to returned value. Make copies instead.
+func (h *ResponseHeader) Header() []byte {
+ h.bufKV.value = h.AppendBytes(h.bufKV.value[:0])
+ return h.bufKV.value
+}
+
+// writeTrailer writes response trailer to w.
+func (h *ResponseHeader) writeTrailer(w *bufio.Writer) error {
+ _, err := w.Write(h.TrailerHeader())
+ return err
+}
+
+// TrailerHeader returns response trailer header representation.
+//
+// Trailers will only be received with chunked transfer.
+//
+// The returned value is valid until the request is released,
+// either though ReleaseRequest or your request handler returning.
+// Do not store references to returned value. Make copies instead.
+func (h *ResponseHeader) TrailerHeader() []byte {
+ h.bufKV.value = h.bufKV.value[:0]
+ for _, t := range h.trailer {
+ value := h.peek(t.key)
+ h.bufKV.value = appendHeaderLine(h.bufKV.value, t.key, value)
+ }
+ h.bufKV.value = append(h.bufKV.value, strCRLF...)
+ return h.bufKV.value
+}
+
+// String returns response header representation.
+func (h *ResponseHeader) String() string {
+ return string(h.Header())
+}
+
+// appendStatusLine appends the response status line to dst and returns
+// the extended dst.
+func (h *ResponseHeader) appendStatusLine(dst []byte) []byte {
+ statusCode := h.StatusCode()
+ if statusCode < 0 {
+ statusCode = StatusOK
+ }
+ return formatStatusLine(dst, h.Protocol(), statusCode, h.StatusMessage())
+}
+
+// AppendBytes appends response header representation to dst and returns
+// the extended dst.
+func (h *ResponseHeader) AppendBytes(dst []byte) []byte {
+ dst = h.appendStatusLine(dst[:0])
+
+ server := h.Server()
+ if len(server) != 0 {
+ dst = appendHeaderLine(dst, strServer, server)
+ }
+
+ if !h.noDefaultDate {
+ serverDateOnce.Do(updateServerDate)
+ dst = appendHeaderLine(dst, strDate, serverDate.Load().([]byte))
+ }
+
+ // Append Content-Type only for non-zero responses
+ // or if it is explicitly set.
+ // See https://github.com/valyala/fasthttp/issues/28 .
+ if h.ContentLength() != 0 || len(h.contentType) > 0 {
+ contentType := h.ContentType()
+ if len(contentType) > 0 {
+ dst = appendHeaderLine(dst, strContentType, contentType)
+ }
+ }
+ contentEncoding := h.ContentEncoding()
+ if len(contentEncoding) > 0 {
+ dst = appendHeaderLine(dst, strContentEncoding, contentEncoding)
+ }
+
+ if len(h.contentLengthBytes) > 0 {
+ dst = appendHeaderLine(dst, strContentLength, h.contentLengthBytes)
+ }
+
+ for i, n := 0, len(h.h); i < n; i++ {
+ kv := &h.h[i]
+
+ // Exclude trailer from header
+ exclude := false
+ for _, t := range h.trailer {
+ if bytes.Equal(kv.key, t.key) {
+ exclude = true
+ break
+ }
+ }
+ if !exclude && (h.noDefaultDate || !bytes.Equal(kv.key, strDate)) {
+ dst = appendHeaderLine(dst, kv.key, kv.value)
+ }
+ }
+
+ if len(h.trailer) > 0 {
+ dst = appendHeaderLine(dst, strTrailer, appendArgsKeyBytes(nil, h.trailer, strCommaSpace))
+ }
+
+ n := len(h.cookies)
+ if n > 0 {
+ for i := 0; i < n; i++ {
+ kv := &h.cookies[i]
+ dst = appendHeaderLine(dst, strSetCookie, kv.value)
+ }
+ }
+
+ if h.ConnectionClose() {
+ dst = appendHeaderLine(dst, strConnection, strClose)
+ }
+
+ return append(dst, strCRLF...)
+}
+
+// Write writes request header to w.
+func (h *RequestHeader) Write(w *bufio.Writer) error {
+ _, err := w.Write(h.Header())
+ return err
+}
+
+// WriteTo writes request header to w.
+//
+// WriteTo implements io.WriterTo interface.
+func (h *RequestHeader) WriteTo(w io.Writer) (int64, error) {
+ n, err := w.Write(h.Header())
+ return int64(n), err
+}
+
+// Header returns request header representation.
+//
+// Headers that set as Trailer will not represent. Use TrailerHeader for trailers.
+//
+// The returned value is valid until the request is released,
+// either though ReleaseRequest or your request handler returning.
+// Do not store references to returned value. Make copies instead.
+func (h *RequestHeader) Header() []byte {
+ h.bufKV.value = h.AppendBytes(h.bufKV.value[:0])
+ return h.bufKV.value
+}
+
+// writeTrailer writes request trailer to w.
+func (h *RequestHeader) writeTrailer(w *bufio.Writer) error {
+ _, err := w.Write(h.TrailerHeader())
+ return err
+}
+
+// TrailerHeader returns request trailer header representation.
+//
+// Trailers will only be received with chunked transfer.
+//
+// The returned value is valid until the request is released,
+// either though ReleaseRequest or your request handler returning.
+// Do not store references to returned value. Make copies instead.
+func (h *RequestHeader) TrailerHeader() []byte {
+ h.bufKV.value = h.bufKV.value[:0]
+ for _, t := range h.trailer {
+ value := h.peek(t.key)
+ h.bufKV.value = appendHeaderLine(h.bufKV.value, t.key, value)
+ }
+ h.bufKV.value = append(h.bufKV.value, strCRLF...)
+ return h.bufKV.value
+}
+
+// RawHeaders returns raw header key/value bytes.
+//
+// Depending on server configuration, header keys may be normalized to
+// capital-case in place.
+//
+// This copy is set aside during parsing, so empty slice is returned for all
+// cases where parsing did not happen. Similarly, request line is not stored
+// during parsing and can not be returned.
+//
+// The slice is not safe to use after the handler returns.
+func (h *RequestHeader) RawHeaders() []byte {
+ return h.rawHeaders
+}
+
+// String returns request header representation.
+func (h *RequestHeader) String() string {
+ return string(h.Header())
+}
+
+// AppendBytes appends request header representation to dst and returns
+// the extended dst.
+func (h *RequestHeader) AppendBytes(dst []byte) []byte {
+ dst = append(dst, h.Method()...)
+ dst = append(dst, ' ')
+ dst = append(dst, h.RequestURI()...)
+ dst = append(dst, ' ')
+ dst = append(dst, h.Protocol()...)
+ dst = append(dst, strCRLF...)
+
+ userAgent := h.UserAgent()
+ if len(userAgent) > 0 && !h.disableSpecialHeader {
+ dst = appendHeaderLine(dst, strUserAgent, userAgent)
+ }
+
+ host := h.Host()
+ if len(host) > 0 && !h.disableSpecialHeader {
+ dst = appendHeaderLine(dst, strHost, host)
+ }
+
+ contentType := h.ContentType()
+ if !h.noDefaultContentType && len(contentType) == 0 && !h.ignoreBody() {
+ contentType = strDefaultContentType
+ }
+ if len(contentType) > 0 && !h.disableSpecialHeader {
+ dst = appendHeaderLine(dst, strContentType, contentType)
+ }
+ if len(h.contentLengthBytes) > 0 && !h.disableSpecialHeader {
+ dst = appendHeaderLine(dst, strContentLength, h.contentLengthBytes)
+ }
+
+ for i, n := 0, len(h.h); i < n; i++ {
+ kv := &h.h[i]
+ // Exclude trailer from header
+ exclude := false
+ for _, t := range h.trailer {
+ if bytes.Equal(kv.key, t.key) {
+ exclude = true
+ break
+ }
+ }
+ if !exclude {
+ dst = appendHeaderLine(dst, kv.key, kv.value)
+ }
+ }
+
+ if len(h.trailer) > 0 {
+ dst = appendHeaderLine(dst, strTrailer, appendArgsKeyBytes(nil, h.trailer, strCommaSpace))
+ }
+
+ // there is no need in h.collectCookies() here, since if cookies aren't collected yet,
+ // they all are located in h.h.
+ n := len(h.cookies)
+ if n > 0 && !h.disableSpecialHeader {
+ dst = append(dst, strCookie...)
+ dst = append(dst, strColonSpace...)
+ dst = appendRequestCookieBytes(dst, h.cookies)
+ dst = append(dst, strCRLF...)
+ }
+
+ if h.ConnectionClose() && !h.disableSpecialHeader {
+ dst = appendHeaderLine(dst, strConnection, strClose)
+ }
+
+ return append(dst, strCRLF...)
+}
+
+func appendHeaderLine(dst, key, value []byte) []byte {
+ dst = append(dst, key...)
+ dst = append(dst, strColonSpace...)
+ dst = append(dst, value...)
+ return append(dst, strCRLF...)
+}
+
+func (h *ResponseHeader) parse(buf []byte) (int, error) {
+ m, err := h.parseFirstLine(buf)
+ if err != nil {
+ return 0, err
+ }
+ n, err := h.parseHeaders(buf[m:])
+ if err != nil {
+ return 0, err
+ }
+ return m + n, nil
+}
+
+func (h *ResponseHeader) parseTrailer(buf []byte) (int, error) {
+ // Skip any 0 length chunk.
+ if buf[0] == '0' {
+ skip := len(strCRLF) + 1
+ if len(buf) < skip {
+ return 0, io.EOF
+ }
+ buf = buf[skip:]
+ }
+
+ var s headerScanner
+ s.b = buf
+ s.disableNormalizing = h.disableNormalizing
+ var err error
+ for s.next() {
+ if len(s.key) > 0 {
+ if bytes.IndexByte(s.key, ' ') != -1 || bytes.IndexByte(s.key, '\t') != -1 {
+ err = fmt.Errorf("invalid trailer key %q", s.key)
+ continue
+ }
+ // Forbidden by RFC 7230, section 4.1.2
+ if isBadTrailer(s.key) {
+ err = fmt.Errorf("forbidden trailer key %q", s.key)
+ continue
+ }
+ h.h = appendArgBytes(h.h, s.key, s.value, argsHasValue)
+ }
+ }
+ if s.err != nil {
+ return 0, s.err
+ }
+ if err != nil {
+ return 0, err
+ }
+ return s.hLen, nil
+}
+
+func (h *RequestHeader) ignoreBody() bool {
+ return h.IsGet() || h.IsHead()
+}
+
+func (h *RequestHeader) parse(buf []byte) (int, error) {
+ m, err := h.parseFirstLine(buf)
+ if err != nil {
+ return 0, err
+ }
+
+ h.rawHeaders, _, err = readRawHeaders(h.rawHeaders[:0], buf[m:])
+ if err != nil {
+ return 0, err
+ }
+ var n int
+ n, err = h.parseHeaders(buf[m:])
+ if err != nil {
+ return 0, err
+ }
+ return m + n, nil
+}
+
+func (h *RequestHeader) parseTrailer(buf []byte) (int, error) {
+ // Skip any 0 length chunk.
+ if buf[0] == '0' {
+ skip := len(strCRLF) + 1
+ if len(buf) < skip {
+ return 0, io.EOF
+ }
+ buf = buf[skip:]
+ }
+
+ var s headerScanner
+ s.b = buf
+ s.disableNormalizing = h.disableNormalizing
+ var err error
+ for s.next() {
+ if len(s.key) > 0 {
+ if bytes.IndexByte(s.key, ' ') != -1 || bytes.IndexByte(s.key, '\t') != -1 {
+ err = fmt.Errorf("invalid trailer key %q", s.key)
+ continue
+ }
+ // Forbidden by RFC 7230, section 4.1.2
+ if isBadTrailer(s.key) {
+ err = fmt.Errorf("forbidden trailer key %q", s.key)
+ continue
+ }
+ h.h = appendArgBytes(h.h, s.key, s.value, argsHasValue)
+ }
+ }
+ if s.err != nil {
+ return 0, s.err
+ }
+ if err != nil {
+ return 0, err
+ }
+ return s.hLen, nil
+}
+
+func isBadTrailer(key []byte) bool {
+ if len(key) == 0 {
+ return true
+ }
+
+ switch key[0] | 0x20 {
+ case 'a':
+ return caseInsensitiveCompare(key, strAuthorization)
+ case 'c':
+ if len(key) > len(HeaderContentType) && caseInsensitiveCompare(key[:8], strContentType[:8]) {
+ // skip compare prefix 'Content-'
+ return caseInsensitiveCompare(key[8:], strContentEncoding[8:]) ||
+ caseInsensitiveCompare(key[8:], strContentLength[8:]) ||
+ caseInsensitiveCompare(key[8:], strContentType[8:]) ||
+ caseInsensitiveCompare(key[8:], strContentRange[8:])
+ }
+ return caseInsensitiveCompare(key, strConnection)
+ case 'e':
+ return caseInsensitiveCompare(key, strExpect)
+ case 'h':
+ return caseInsensitiveCompare(key, strHost)
+ case 'k':
+ return caseInsensitiveCompare(key, strKeepAlive)
+ case 'm':
+ return caseInsensitiveCompare(key, strMaxForwards)
+ case 'p':
+ if len(key) > len(HeaderProxyConnection) && caseInsensitiveCompare(key[:6], strProxyConnection[:6]) {
+ // skip compare prefix 'Proxy-'
+ return caseInsensitiveCompare(key[6:], strProxyConnection[6:]) ||
+ caseInsensitiveCompare(key[6:], strProxyAuthenticate[6:]) ||
+ caseInsensitiveCompare(key[6:], strProxyAuthorization[6:])
+ }
+ case 'r':
+ return caseInsensitiveCompare(key, strRange)
+ case 't':
+ return caseInsensitiveCompare(key, strTE) ||
+ caseInsensitiveCompare(key, strTrailer) ||
+ caseInsensitiveCompare(key, strTransferEncoding)
+ case 'w':
+ return caseInsensitiveCompare(key, strWWWAuthenticate)
+ }
+ return false
+}
+
+func (h *ResponseHeader) parseFirstLine(buf []byte) (int, error) {
+ bNext := buf
+ var b []byte
+ var err error
+ for len(b) == 0 {
+ if b, bNext, err = nextLine(bNext); err != nil {
+ return 0, err
+ }
+ }
+
+ // parse protocol
+ n := bytes.IndexByte(b, ' ')
+ if n < 0 {
+ if h.secureErrorLogMessage {
+ return 0, fmt.Errorf("cannot find whitespace in the first line of response")
+ }
+ return 0, fmt.Errorf("cannot find whitespace in the first line of response %q", buf)
+ }
+ h.noHTTP11 = !bytes.Equal(b[:n], strHTTP11)
+ b = b[n+1:]
+
+ // parse status code
+ h.statusCode, n, err = parseUintBuf(b)
+ if err != nil {
+ if h.secureErrorLogMessage {
+ return 0, fmt.Errorf("cannot parse response status code: %w", err)
+ }
+ return 0, fmt.Errorf("cannot parse response status code: %w. Response %q", err, buf)
+ }
+ if len(b) > n && b[n] != ' ' {
+ if h.secureErrorLogMessage {
+ return 0, fmt.Errorf("unexpected char at the end of status code")
+ }
+ return 0, fmt.Errorf("unexpected char at the end of status code. Response %q", buf)
+ }
+ if len(b) > n+1 {
+ h.SetStatusMessage(b[n+1:])
+ }
+
+ return len(buf) - len(bNext), nil
+}
+
+func (h *RequestHeader) parseFirstLine(buf []byte) (int, error) {
+ bNext := buf
+ var b []byte
+ var err error
+ for len(b) == 0 {
+ if b, bNext, err = nextLine(bNext); err != nil {
+ return 0, err
+ }
+ }
+
+ // parse method
+ n := bytes.IndexByte(b, ' ')
+ if n <= 0 {
+ if h.secureErrorLogMessage {
+ return 0, fmt.Errorf("cannot find http request method")
+ }
+ return 0, fmt.Errorf("cannot find http request method in %q", buf)
+ }
+ h.method = append(h.method[:0], b[:n]...)
+ b = b[n+1:]
+
+ protoStr := strHTTP11
+ // parse requestURI
+ n = bytes.LastIndexByte(b, ' ')
+ switch {
+ case n < 0:
+ h.noHTTP11 = true
+ n = len(b)
+ protoStr = strHTTP10
+ case n == 0:
+ if h.secureErrorLogMessage {
+ return 0, fmt.Errorf("requestURI cannot be empty")
+ }
+ return 0, fmt.Errorf("requestURI cannot be empty in %q", buf)
+ case !bytes.Equal(b[n+1:], strHTTP11):
+ h.noHTTP11 = true
+ protoStr = b[n+1:]
+ }
+
+ h.proto = append(h.proto[:0], protoStr...)
+ h.requestURI = append(h.requestURI[:0], b[:n]...)
+
+ return len(buf) - len(bNext), nil
+}
+
+func readRawHeaders(dst, buf []byte) ([]byte, int, error) {
+ n := bytes.IndexByte(buf, nChar)
+ if n < 0 {
+ return dst[:0], 0, errNeedMore
+ }
+ if (n == 1 && buf[0] == rChar) || n == 0 {
+ // empty headers
+ return dst, n + 1, nil
+ }
+
+ n++
+ b := buf
+ m := n
+ for {
+ b = b[m:]
+ m = bytes.IndexByte(b, nChar)
+ if m < 0 {
+ return dst, 0, errNeedMore
+ }
+ m++
+ n += m
+ if (m == 2 && b[0] == rChar) || m == 1 {
+ dst = append(dst, buf[:n]...)
+ return dst, n, nil
+ }
+ }
+}
+
+func (h *ResponseHeader) parseHeaders(buf []byte) (int, error) {
+ // 'identity' content-length by default
+ h.contentLength = -2
+
+ var s headerScanner
+ s.b = buf
+ s.disableNormalizing = h.disableNormalizing
+ var err error
+ var kv *argsKV
+ for s.next() {
+ if len(s.key) > 0 {
+ switch s.key[0] | 0x20 {
+ case 'c':
+ if caseInsensitiveCompare(s.key, strContentType) {
+ h.contentType = append(h.contentType[:0], s.value...)
+ continue
+ }
+ if caseInsensitiveCompare(s.key, strContentEncoding) {
+ h.contentEncoding = append(h.contentEncoding[:0], s.value...)
+ continue
+ }
+ if caseInsensitiveCompare(s.key, strContentLength) {
+ if h.contentLength != -1 {
+ if h.contentLength, err = parseContentLength(s.value); err != nil {
+ h.contentLength = -2
+ } else {
+ h.contentLengthBytes = append(h.contentLengthBytes[:0], s.value...)
+ }
+ }
+ continue
+ }
+ if caseInsensitiveCompare(s.key, strConnection) {
+ if bytes.Equal(s.value, strClose) {
+ h.connectionClose = true
+ } else {
+ h.connectionClose = false
+ h.h = appendArgBytes(h.h, s.key, s.value, argsHasValue)
+ }
+ continue
+ }
+ case 's':
+ if caseInsensitiveCompare(s.key, strServer) {
+ h.server = append(h.server[:0], s.value...)
+ continue
+ }
+ if caseInsensitiveCompare(s.key, strSetCookie) {
+ h.cookies, kv = allocArg(h.cookies)
+ kv.key = getCookieKey(kv.key, s.value)
+ kv.value = append(kv.value[:0], s.value...)
+ continue
+ }
+ case 't':
+ if caseInsensitiveCompare(s.key, strTransferEncoding) {
+ if len(s.value) > 0 && !bytes.Equal(s.value, strIdentity) {
+ h.contentLength = -1
+ h.h = setArgBytes(h.h, strTransferEncoding, strChunked, argsHasValue)
+ }
+ continue
+ }
+ if caseInsensitiveCompare(s.key, strTrailer) {
+ err = h.SetTrailerBytes(s.value)
+ continue
+ }
+ }
+ h.h = appendArgBytes(h.h, s.key, s.value, argsHasValue)
+ }
+ }
+ if s.err != nil {
+ h.connectionClose = true
+ return 0, s.err
+ }
+
+ if h.contentLength < 0 {
+ h.contentLengthBytes = h.contentLengthBytes[:0]
+ }
+ if h.contentLength == -2 && !h.ConnectionUpgrade() && !h.mustSkipContentLength() {
+ h.h = setArgBytes(h.h, strTransferEncoding, strIdentity, argsHasValue)
+ h.connectionClose = true
+ }
+ if h.noHTTP11 && !h.connectionClose {
+ // close connection for non-http/1.1 response unless 'Connection: keep-alive' is set.
+ v := peekArgBytes(h.h, strConnection)
+ h.connectionClose = !hasHeaderValue(v, strKeepAlive)
+ }
+
+ return len(buf) - len(s.b), err
+}
+
+func (h *RequestHeader) parseHeaders(buf []byte) (int, error) {
+ h.contentLength = -2
+
+ var s headerScanner
+ s.b = buf
+ s.disableNormalizing = h.disableNormalizing
+ var err error
+ for s.next() {
+ if len(s.key) > 0 {
+ // Spaces between the header key and colon are not allowed.
+ // See RFC 7230, Section 3.2.4.
+ if bytes.IndexByte(s.key, ' ') != -1 || bytes.IndexByte(s.key, '\t') != -1 {
+ err = fmt.Errorf("invalid header key %q", s.key)
+ continue
+ }
+
+ if h.disableSpecialHeader {
+ h.h = appendArgBytes(h.h, s.key, s.value, argsHasValue)
+ continue
+ }
+
+ switch s.key[0] | 0x20 {
+ case 'h':
+ if caseInsensitiveCompare(s.key, strHost) {
+ h.host = append(h.host[:0], s.value...)
+ continue
+ }
+ case 'u':
+ if caseInsensitiveCompare(s.key, strUserAgent) {
+ h.userAgent = append(h.userAgent[:0], s.value...)
+ continue
+ }
+ case 'c':
+ if caseInsensitiveCompare(s.key, strContentType) {
+ h.contentType = append(h.contentType[:0], s.value...)
+ continue
+ }
+ if caseInsensitiveCompare(s.key, strContentLength) {
+ if h.contentLength != -1 {
+ var nerr error
+ if h.contentLength, nerr = parseContentLength(s.value); nerr != nil {
+ if err == nil {
+ err = nerr
+ }
+ h.contentLength = -2
+ } else {
+ h.contentLengthBytes = append(h.contentLengthBytes[:0], s.value...)
+ }
+ }
+ continue
+ }
+ if caseInsensitiveCompare(s.key, strConnection) {
+ if bytes.Equal(s.value, strClose) {
+ h.connectionClose = true
+ } else {
+ h.connectionClose = false
+ h.h = appendArgBytes(h.h, s.key, s.value, argsHasValue)
+ }
+ continue
+ }
+ case 't':
+ if caseInsensitiveCompare(s.key, strTransferEncoding) {
+ if !bytes.Equal(s.value, strIdentity) {
+ h.contentLength = -1
+ h.h = setArgBytes(h.h, strTransferEncoding, strChunked, argsHasValue)
+ }
+ continue
+ }
+ if caseInsensitiveCompare(s.key, strTrailer) {
+ if nerr := h.SetTrailerBytes(s.value); nerr != nil {
+ if err == nil {
+ err = nerr
+ }
+ }
+ continue
+ }
+ }
+ }
+ h.h = appendArgBytes(h.h, s.key, s.value, argsHasValue)
+ }
+ if s.err != nil && err == nil {
+ err = s.err
+ }
+ if err != nil {
+ h.connectionClose = true
+ return 0, err
+ }
+
+ if h.contentLength < 0 {
+ h.contentLengthBytes = h.contentLengthBytes[:0]
+ }
+ if h.noHTTP11 && !h.connectionClose {
+ // close connection for non-http/1.1 request unless 'Connection: keep-alive' is set.
+ v := peekArgBytes(h.h, strConnection)
+ h.connectionClose = !hasHeaderValue(v, strKeepAlive)
+ }
+ return s.hLen, nil
+}
+
+func (h *RequestHeader) collectCookies() {
+ if h.cookiesCollected {
+ return
+ }
+
+ for i, n := 0, len(h.h); i < n; i++ {
+ kv := &h.h[i]
+ if caseInsensitiveCompare(kv.key, strCookie) {
+ h.cookies = parseRequestCookies(h.cookies, kv.value)
+ tmp := *kv
+ copy(h.h[i:], h.h[i+1:])
+ n--
+ i--
+ h.h[n] = tmp
+ h.h = h.h[:n]
+ }
+ }
+ h.cookiesCollected = true
+}
+
+var errNonNumericChars = errors.New("non-numeric chars found")
+
+func parseContentLength(b []byte) (int, error) {
+ v, n, err := parseUintBuf(b)
+ if err != nil {
+ return -1, fmt.Errorf("cannot parse Content-Length: %w", err)
+ }
+ if n != len(b) {
+ return -1, fmt.Errorf("cannot parse Content-Length: %w", errNonNumericChars)
+ }
+ return v, nil
+}
+
+type headerScanner struct {
+ b []byte
+ key []byte
+ value []byte
+ err error
+
+ // hLen stores header subslice len
+ hLen int
+
+ disableNormalizing bool
+
+ // by checking whether the next line contains a colon or not to tell
+ // it's a header entry or a multi line value of current header entry.
+ // the side effect of this operation is that we know the index of the
+ // next colon and new line, so this can be used during next iteration,
+ // instead of find them again.
+ nextColon int
+ nextNewLine int
+
+ initialized bool
+}
+
+func (s *headerScanner) next() bool {
+ if !s.initialized {
+ s.nextColon = -1
+ s.nextNewLine = -1
+ s.initialized = true
+ }
+ bLen := len(s.b)
+ if bLen >= 2 && s.b[0] == rChar && s.b[1] == nChar {
+ s.b = s.b[2:]
+ s.hLen += 2
+ return false
+ }
+ if bLen >= 1 && s.b[0] == nChar {
+ s.b = s.b[1:]
+ s.hLen++
+ return false
+ }
+ var n int
+ if s.nextColon >= 0 {
+ n = s.nextColon
+ s.nextColon = -1
+ } else {
+ n = bytes.IndexByte(s.b, ':')
+
+ // There can't be a \n inside the header name, check for this.
+ x := bytes.IndexByte(s.b, nChar)
+ if x < 0 {
+ // A header name should always at some point be followed by a \n
+ // even if it's the one that terminates the header block.
+ s.err = errNeedMore
+ return false
+ }
+ if x < n {
+ // There was a \n before the :
+ s.err = errInvalidName
+ return false
+ }
+ }
+ if n < 0 {
+ s.err = errNeedMore
+ return false
+ }
+ s.key = s.b[:n]
+ normalizeHeaderKey(s.key, s.disableNormalizing)
+ n++
+ for len(s.b) > n && s.b[n] == ' ' {
+ n++
+ // the newline index is a relative index, and lines below trimmed `s.b` by `n`,
+ // so the relative newline index also shifted forward. it's safe to decrease
+ // to a minus value, it means it's invalid, and will find the newline again.
+ s.nextNewLine--
+ }
+ s.hLen += n
+ s.b = s.b[n:]
+ if s.nextNewLine >= 0 {
+ n = s.nextNewLine
+ s.nextNewLine = -1
+ } else {
+ n = bytes.IndexByte(s.b, nChar)
+ }
+ if n < 0 {
+ s.err = errNeedMore
+ return false
+ }
+ isMultiLineValue := false
+ for {
+ if n+1 >= len(s.b) {
+ break
+ }
+ if s.b[n+1] != ' ' && s.b[n+1] != '\t' {
+ break
+ }
+ d := bytes.IndexByte(s.b[n+1:], nChar)
+ if d <= 0 {
+ break
+ } else if d == 1 && s.b[n+1] == rChar {
+ break
+ }
+ e := n + d + 1
+ if c := bytes.IndexByte(s.b[n+1:e], ':'); c >= 0 {
+ s.nextColon = c
+ s.nextNewLine = d - c - 1
+ break
+ }
+ isMultiLineValue = true
+ n = e
+ }
+ if n >= len(s.b) {
+ s.err = errNeedMore
+ return false
+ }
+ oldB := s.b
+ s.value = s.b[:n]
+ s.hLen += n + 1
+ s.b = s.b[n+1:]
+
+ if n > 0 && s.value[n-1] == rChar {
+ n--
+ }
+ for n > 0 && s.value[n-1] == ' ' {
+ n--
+ }
+ s.value = s.value[:n]
+ if isMultiLineValue {
+ s.value, s.b, s.hLen = normalizeHeaderValue(s.value, oldB, s.hLen)
+ }
+ return true
+}
+
+type headerValueScanner struct {
+ b []byte
+ value []byte
+}
+
+func (s *headerValueScanner) next() bool {
+ b := s.b
+ if len(b) == 0 {
+ return false
+ }
+ n := bytes.IndexByte(b, ',')
+ if n < 0 {
+ s.value = stripSpace(b)
+ s.b = b[len(b):]
+ return true
+ }
+ s.value = stripSpace(b[:n])
+ s.b = b[n+1:]
+ return true
+}
+
+func stripSpace(b []byte) []byte {
+ for len(b) > 0 && b[0] == ' ' {
+ b = b[1:]
+ }
+ for len(b) > 0 && b[len(b)-1] == ' ' {
+ b = b[:len(b)-1]
+ }
+ return b
+}
+
+func hasHeaderValue(s, value []byte) bool {
+ var vs headerValueScanner
+ vs.b = s
+ for vs.next() {
+ if caseInsensitiveCompare(vs.value, value) {
+ return true
+ }
+ }
+ return false
+}
+
+func nextLine(b []byte) ([]byte, []byte, error) {
+ nNext := bytes.IndexByte(b, nChar)
+ if nNext < 0 {
+ return nil, nil, errNeedMore
+ }
+ n := nNext
+ if n > 0 && b[n-1] == rChar {
+ n--
+ }
+ return b[:n], b[nNext+1:], nil
+}
+
+func initHeaderKV(kv *argsKV, key, value string, disableNormalizing bool) {
+ kv.key = getHeaderKeyBytes(kv, key, disableNormalizing)
+ // https://tools.ietf.org/html/rfc7230#section-3.2.4
+ kv.value = append(kv.value[:0], value...)
+ kv.value = removeNewLines(kv.value)
+}
+
+func getHeaderKeyBytes(kv *argsKV, key string, disableNormalizing bool) []byte {
+ kv.key = append(kv.key[:0], key...)
+ normalizeHeaderKey(kv.key, disableNormalizing)
+ return kv.key
+}
+
+func normalizeHeaderValue(ov, ob []byte, headerLength int) (nv, nb []byte, nhl int) {
+ nv = ov
+ length := len(ov)
+ if length <= 0 {
+ return
+ }
+ write := 0
+ shrunk := 0
+ lineStart := false
+ for read := 0; read < length; read++ {
+ c := ov[read]
+ switch {
+ case c == rChar || c == nChar:
+ shrunk++
+ if c == nChar {
+ lineStart = true
+ }
+ continue
+ case lineStart && c == '\t':
+ c = ' '
+ default:
+ lineStart = false
+ }
+ nv[write] = c
+ write++
+ }
+
+ nv = nv[:write]
+ copy(ob[write:], ob[write+shrunk:])
+
+ // Check if we need to skip \r\n or just \n
+ skip := 0
+ if ob[write] == rChar {
+ if ob[write+1] == nChar {
+ skip += 2
+ } else {
+ skip++
+ }
+ } else if ob[write] == nChar {
+ skip++
+ }
+
+ nb = ob[write+skip : len(ob)-shrunk]
+ nhl = headerLength - shrunk
+ return
+}
+
+func normalizeHeaderKey(b []byte, disableNormalizing bool) {
+ if disableNormalizing {
+ return
+ }
+
+ n := len(b)
+ if n == 0 {
+ return
+ }
+
+ b[0] = toUpperTable[b[0]]
+ for i := 1; i < n; i++ {
+ p := &b[i]
+ if *p == '-' {
+ i++
+ if i < n {
+ b[i] = toUpperTable[b[i]]
+ }
+ continue
+ }
+ *p = toLowerTable[*p]
+ }
+}
+
+// removeNewLines will replace `\r` and `\n` with an empty space
+func removeNewLines(raw []byte) []byte {
+ // check if a `\r` is present and save the position.
+ // if no `\r` is found, check if a `\n` is present.
+ foundR := bytes.IndexByte(raw, rChar)
+ foundN := bytes.IndexByte(raw, nChar)
+ start := 0
+
+ switch {
+ case foundN != -1:
+ if foundR > foundN {
+ start = foundN
+ } else if foundR != -1 {
+ start = foundR
+ }
+ case foundR != -1:
+ start = foundR
+ default:
+ return raw
+ }
+
+ for i := start; i < len(raw); i++ {
+ switch raw[i] {
+ case rChar, nChar:
+ raw[i] = ' '
+ default:
+ continue
+ }
+ }
+ return raw
+}
+
+// AppendNormalizedHeaderKey appends normalized header key (name) to dst
+// and returns the resulting dst.
+//
+// Normalized header key starts with uppercase letter. The first letters
+// after dashes are also uppercased. All the other letters are lowercased.
+// Examples:
+//
+// - coNTENT-TYPe -> Content-Type
+// - HOST -> Host
+// - foo-bar-baz -> Foo-Bar-Baz
+func AppendNormalizedHeaderKey(dst []byte, key string) []byte {
+ dst = append(dst, key...)
+ normalizeHeaderKey(dst[len(dst)-len(key):], false)
+ return dst
+}
+
+// AppendNormalizedHeaderKeyBytes appends normalized header key (name) to dst
+// and returns the resulting dst.
+//
+// Normalized header key starts with uppercase letter. The first letters
+// after dashes are also uppercased. All the other letters are lowercased.
+// Examples:
+//
+// - coNTENT-TYPe -> Content-Type
+// - HOST -> Host
+// - foo-bar-baz -> Foo-Bar-Baz
+func AppendNormalizedHeaderKeyBytes(dst, key []byte) []byte {
+ return AppendNormalizedHeaderKey(dst, b2s(key))
+}
+
+func appendArgsKeyBytes(dst []byte, args []argsKV, sep []byte) []byte {
+ for i, n := 0, len(args); i < n; i++ {
+ kv := &args[i]
+ dst = append(dst, kv.key...)
+ if i+1 < n {
+ dst = append(dst, sep...)
+ }
+ }
+ return dst
+}
+
+var (
+ errNeedMore = errors.New("need more data: cannot find trailing lf")
+ errInvalidName = errors.New("invalid header name")
+ errSmallBuffer = errors.New("small read buffer. Increase ReadBufferSize")
+)
+
+// ErrNothingRead is returned when a keep-alive connection is closed,
+// either because the remote closed it or because of a read timeout.
+type ErrNothingRead struct {
+ error
+}
+
+// ErrSmallBuffer is returned when the provided buffer size is too small
+// for reading request and/or response headers.
+//
+// ReadBufferSize value from Server or clients should reduce the number
+// of such errors.
+type ErrSmallBuffer struct {
+ error
+}
+
+func mustPeekBuffered(r *bufio.Reader) []byte {
+ buf, err := r.Peek(r.Buffered())
+ if len(buf) == 0 || err != nil {
+ panic(fmt.Sprintf("bufio.Reader.Peek() returned unexpected data (%q, %v)", buf, err))
+ }
+ return buf
+}
+
+func mustDiscard(r *bufio.Reader, n int) {
+ if _, err := r.Discard(n); err != nil {
+ panic(fmt.Sprintf("bufio.Reader.Discard(%d) failed: %v", n, err))
+ }
+}
diff --git a/vendor/github.com/valyala/fasthttp/headers.go b/vendor/github.com/valyala/fasthttp/headers.go
new file mode 100644
index 0000000..9d6d0a3
--- /dev/null
+++ b/vendor/github.com/valyala/fasthttp/headers.go
@@ -0,0 +1,165 @@
+package fasthttp
+
+// Headers
+const (
+ // Authentication
+ HeaderAuthorization = "Authorization"
+ HeaderProxyAuthenticate = "Proxy-Authenticate"
+ HeaderProxyAuthorization = "Proxy-Authorization"
+ HeaderWWWAuthenticate = "WWW-Authenticate"
+
+ // Caching
+ HeaderAge = "Age"
+ HeaderCacheControl = "Cache-Control"
+ HeaderClearSiteData = "Clear-Site-Data"
+ HeaderExpires = "Expires"
+ HeaderPragma = "Pragma"
+ HeaderWarning = "Warning"
+
+ // Client hints
+ HeaderAcceptCH = "Accept-CH"
+ HeaderAcceptCHLifetime = "Accept-CH-Lifetime"
+ HeaderContentDPR = "Content-DPR"
+ HeaderDPR = "DPR"
+ HeaderEarlyData = "Early-Data"
+ HeaderSaveData = "Save-Data"
+ HeaderViewportWidth = "Viewport-Width"
+ HeaderWidth = "Width"
+
+ // Conditionals
+ HeaderETag = "ETag"
+ HeaderIfMatch = "If-Match"
+ HeaderIfModifiedSince = "If-Modified-Since"
+ HeaderIfNoneMatch = "If-None-Match"
+ HeaderIfUnmodifiedSince = "If-Unmodified-Since"
+ HeaderLastModified = "Last-Modified"
+ HeaderVary = "Vary"
+
+ // Connection management
+ HeaderConnection = "Connection"
+ HeaderKeepAlive = "Keep-Alive"
+ HeaderProxyConnection = "Proxy-Connection"
+
+ // Content negotiation
+ HeaderAccept = "Accept"
+ HeaderAcceptCharset = "Accept-Charset"
+ HeaderAcceptEncoding = "Accept-Encoding"
+ HeaderAcceptLanguage = "Accept-Language"
+
+ // Controls
+ HeaderCookie = "Cookie"
+ HeaderExpect = "Expect"
+ HeaderMaxForwards = "Max-Forwards"
+ HeaderSetCookie = "Set-Cookie"
+
+ // CORS
+ HeaderAccessControlAllowCredentials = "Access-Control-Allow-Credentials"
+ HeaderAccessControlAllowHeaders = "Access-Control-Allow-Headers"
+ HeaderAccessControlAllowMethods = "Access-Control-Allow-Methods"
+ HeaderAccessControlAllowOrigin = "Access-Control-Allow-Origin"
+ HeaderAccessControlExposeHeaders = "Access-Control-Expose-Headers"
+ HeaderAccessControlMaxAge = "Access-Control-Max-Age"
+ HeaderAccessControlRequestHeaders = "Access-Control-Request-Headers"
+ HeaderAccessControlRequestMethod = "Access-Control-Request-Method"
+ HeaderOrigin = "Origin"
+ HeaderTimingAllowOrigin = "Timing-Allow-Origin"
+ HeaderXPermittedCrossDomainPolicies = "X-Permitted-Cross-Domain-Policies"
+
+ // Do Not Track
+ HeaderDNT = "DNT"
+ HeaderTk = "Tk"
+
+ // Downloads
+ HeaderContentDisposition = "Content-Disposition"
+
+ // Message body information
+ HeaderContentEncoding = "Content-Encoding"
+ HeaderContentLanguage = "Content-Language"
+ HeaderContentLength = "Content-Length"
+ HeaderContentLocation = "Content-Location"
+ HeaderContentType = "Content-Type"
+
+ // Proxies
+ HeaderForwarded = "Forwarded"
+ HeaderVia = "Via"
+ HeaderXForwardedFor = "X-Forwarded-For"
+ HeaderXForwardedHost = "X-Forwarded-Host"
+ HeaderXForwardedProto = "X-Forwarded-Proto"
+
+ // Redirects
+ HeaderLocation = "Location"
+
+ // Request context
+ HeaderFrom = "From"
+ HeaderHost = "Host"
+ HeaderReferer = "Referer"
+ HeaderReferrerPolicy = "Referrer-Policy"
+ HeaderUserAgent = "User-Agent"
+
+ // Response context
+ HeaderAllow = "Allow"
+ HeaderServer = "Server"
+
+ // Range requests
+ HeaderAcceptRanges = "Accept-Ranges"
+ HeaderContentRange = "Content-Range"
+ HeaderIfRange = "If-Range"
+ HeaderRange = "Range"
+
+ // Security
+ HeaderContentSecurityPolicy = "Content-Security-Policy"
+ HeaderContentSecurityPolicyReportOnly = "Content-Security-Policy-Report-Only"
+ HeaderCrossOriginResourcePolicy = "Cross-Origin-Resource-Policy"
+ HeaderExpectCT = "Expect-CT"
+ HeaderFeaturePolicy = "Feature-Policy"
+ HeaderPublicKeyPins = "Public-Key-Pins"
+ HeaderPublicKeyPinsReportOnly = "Public-Key-Pins-Report-Only"
+ HeaderStrictTransportSecurity = "Strict-Transport-Security"
+ HeaderUpgradeInsecureRequests = "Upgrade-Insecure-Requests"
+ HeaderXContentTypeOptions = "X-Content-Type-Options"
+ HeaderXDownloadOptions = "X-Download-Options"
+ HeaderXFrameOptions = "X-Frame-Options"
+ HeaderXPoweredBy = "X-Powered-By"
+ HeaderXXSSProtection = "X-XSS-Protection"
+
+ // Server-sent event
+ HeaderLastEventID = "Last-Event-ID"
+ HeaderNEL = "NEL"
+ HeaderPingFrom = "Ping-From"
+ HeaderPingTo = "Ping-To"
+ HeaderReportTo = "Report-To"
+
+ // Transfer coding
+ HeaderTE = "TE"
+ HeaderTrailer = "Trailer"
+ HeaderTransferEncoding = "Transfer-Encoding"
+
+ // WebSockets
+ HeaderSecWebSocketAccept = "Sec-WebSocket-Accept"
+ HeaderSecWebSocketExtensions = "Sec-WebSocket-Extensions" /* #nosec G101 */
+ HeaderSecWebSocketKey = "Sec-WebSocket-Key"
+ HeaderSecWebSocketProtocol = "Sec-WebSocket-Protocol"
+ HeaderSecWebSocketVersion = "Sec-WebSocket-Version"
+
+ // Other
+ HeaderAcceptPatch = "Accept-Patch"
+ HeaderAcceptPushPolicy = "Accept-Push-Policy"
+ HeaderAcceptSignature = "Accept-Signature"
+ HeaderAltSvc = "Alt-Svc"
+ HeaderDate = "Date"
+ HeaderIndex = "Index"
+ HeaderLargeAllocation = "Large-Allocation"
+ HeaderLink = "Link"
+ HeaderPushPolicy = "Push-Policy"
+ HeaderRetryAfter = "Retry-After"
+ HeaderServerTiming = "Server-Timing"
+ HeaderSignature = "Signature"
+ HeaderSignedHeaders = "Signed-Headers"
+ HeaderSourceMap = "SourceMap"
+ HeaderUpgrade = "Upgrade"
+ HeaderXDNSPrefetchControl = "X-DNS-Prefetch-Control"
+ HeaderXPingback = "X-Pingback"
+ HeaderXRequestedWith = "X-Requested-With"
+ HeaderXRobotsTag = "X-Robots-Tag"
+ HeaderXUACompatible = "X-UA-Compatible"
+)
diff --git a/vendor/github.com/valyala/fasthttp/http.go b/vendor/github.com/valyala/fasthttp/http.go
new file mode 100644
index 0000000..2dd9061
--- /dev/null
+++ b/vendor/github.com/valyala/fasthttp/http.go
@@ -0,0 +1,2358 @@
+package fasthttp
+
+import (
+ "bufio"
+ "bytes"
+ "compress/gzip"
+ "encoding/base64"
+ "errors"
+ "fmt"
+ "io"
+ "mime/multipart"
+ "net"
+ "os"
+ "sync"
+ "time"
+
+ "github.com/valyala/bytebufferpool"
+)
+
+var (
+ requestBodyPoolSizeLimit = -1
+ responseBodyPoolSizeLimit = -1
+)
+
+// SetBodySizePoolLimit set the max body size for bodies to be returned to the pool.
+// If the body size is larger it will be released instead of put back into the pool for reuse.
+func SetBodySizePoolLimit(reqBodyLimit, respBodyLimit int) {
+ requestBodyPoolSizeLimit = reqBodyLimit
+ responseBodyPoolSizeLimit = respBodyLimit
+}
+
+// Request represents HTTP request.
+//
+// It is forbidden copying Request instances. Create new instances
+// and use CopyTo instead.
+//
+// Request instance MUST NOT be used from concurrently running goroutines.
+type Request struct {
+ noCopy noCopy
+
+ // Request header
+ //
+ // Copying Header by value is forbidden. Use pointer to Header instead.
+ Header RequestHeader
+
+ uri URI
+ postArgs Args
+
+ bodyStream io.Reader
+ w requestBodyWriter
+ body *bytebufferpool.ByteBuffer
+ bodyRaw []byte
+
+ multipartForm *multipart.Form
+ multipartFormBoundary string
+ secureErrorLogMessage bool
+
+ // Group bool members in order to reduce Request object size.
+ parsedURI bool
+ parsedPostArgs bool
+
+ keepBodyBuffer bool
+
+ // Used by Server to indicate the request was received on a HTTPS endpoint.
+ // Client/HostClient shouldn't use this field but should depend on the uri.scheme instead.
+ isTLS bool
+
+ // Request timeout. Usually set by DoDeadline or DoTimeout
+ // if <= 0, means not set
+ timeout time.Duration
+
+ // Use Host header (request.Header.SetHost) instead of the host from SetRequestURI, SetHost, or URI().SetHost
+ UseHostHeader bool
+
+ // DisableRedirectPathNormalizing disables redirect path normalization when used with DoRedirects.
+ //
+ // By default redirect path values are normalized, i.e.
+ // extra slashes are removed, special characters are encoded.
+ DisableRedirectPathNormalizing bool
+}
+
+// Response represents HTTP response.
+//
+// It is forbidden copying Response instances. Create new instances
+// and use CopyTo instead.
+//
+// Response instance MUST NOT be used from concurrently running goroutines.
+type Response struct {
+ noCopy noCopy
+
+ // Response header
+ //
+ // Copying Header by value is forbidden. Use pointer to Header instead.
+ Header ResponseHeader
+
+ // Flush headers as soon as possible without waiting for first body bytes.
+ // Relevant for bodyStream only.
+ ImmediateHeaderFlush bool
+
+ // StreamBody enables response body streaming.
+ // Use SetBodyStream to set the body stream.
+ StreamBody bool
+
+ bodyStream io.Reader
+ w responseBodyWriter
+ body *bytebufferpool.ByteBuffer
+ bodyRaw []byte
+
+ // Response.Read() skips reading body if set to true.
+ // Use it for reading HEAD responses.
+ //
+ // Response.Write() skips writing body if set to true.
+ // Use it for writing HEAD responses.
+ SkipBody bool
+
+ keepBodyBuffer bool
+ secureErrorLogMessage bool
+
+ // Remote TCPAddr from concurrently net.Conn
+ raddr net.Addr
+ // Local TCPAddr from concurrently net.Conn
+ laddr net.Addr
+}
+
+// SetHost sets host for the request.
+func (req *Request) SetHost(host string) {
+ req.URI().SetHost(host)
+}
+
+// SetHostBytes sets host for the request.
+func (req *Request) SetHostBytes(host []byte) {
+ req.URI().SetHostBytes(host)
+}
+
+// Host returns the host for the given request.
+func (req *Request) Host() []byte {
+ return req.URI().Host()
+}
+
+// SetRequestURI sets RequestURI.
+func (req *Request) SetRequestURI(requestURI string) {
+ req.Header.SetRequestURI(requestURI)
+ req.parsedURI = false
+}
+
+// SetRequestURIBytes sets RequestURI.
+func (req *Request) SetRequestURIBytes(requestURI []byte) {
+ req.Header.SetRequestURIBytes(requestURI)
+ req.parsedURI = false
+}
+
+// RequestURI returns request's URI.
+func (req *Request) RequestURI() []byte {
+ if req.parsedURI {
+ requestURI := req.uri.RequestURI()
+ req.SetRequestURIBytes(requestURI)
+ }
+ return req.Header.RequestURI()
+}
+
+// StatusCode returns response status code.
+func (resp *Response) StatusCode() int {
+ return resp.Header.StatusCode()
+}
+
+// SetStatusCode sets response status code.
+func (resp *Response) SetStatusCode(statusCode int) {
+ resp.Header.SetStatusCode(statusCode)
+}
+
+// ConnectionClose returns true if 'Connection: close' header is set.
+func (resp *Response) ConnectionClose() bool {
+ return resp.Header.ConnectionClose()
+}
+
+// SetConnectionClose sets 'Connection: close' header.
+func (resp *Response) SetConnectionClose() {
+ resp.Header.SetConnectionClose()
+}
+
+// ConnectionClose returns true if 'Connection: close' header is set.
+func (req *Request) ConnectionClose() bool {
+ return req.Header.ConnectionClose()
+}
+
+// SetConnectionClose sets 'Connection: close' header.
+func (req *Request) SetConnectionClose() {
+ req.Header.SetConnectionClose()
+}
+
+// SendFile registers file on the given path to be used as response body
+// when Write is called.
+//
+// Note that SendFile doesn't set Content-Type, so set it yourself
+// with Header.SetContentType.
+func (resp *Response) SendFile(path string) error {
+ f, err := os.Open(path)
+ if err != nil {
+ return err
+ }
+ fileInfo, err := f.Stat()
+ if err != nil {
+ f.Close()
+ return err
+ }
+ size64 := fileInfo.Size()
+ size := int(size64)
+ if int64(size) != size64 {
+ size = -1
+ }
+
+ resp.Header.SetLastModified(fileInfo.ModTime())
+ resp.SetBodyStream(f, size)
+ return nil
+}
+
+// SetBodyStream sets request body stream and, optionally body size.
+//
+// If bodySize is >= 0, then the bodyStream must provide exactly bodySize bytes
+// before returning io.EOF.
+//
+// If bodySize < 0, then bodyStream is read until io.EOF.
+//
+// bodyStream.Close() is called after finishing reading all body data
+// if it implements io.Closer.
+//
+// Note that GET and HEAD requests cannot have body.
+//
+// See also SetBodyStreamWriter.
+func (req *Request) SetBodyStream(bodyStream io.Reader, bodySize int) {
+ req.ResetBody()
+ req.bodyStream = bodyStream
+ req.Header.SetContentLength(bodySize)
+}
+
+// SetBodyStream sets response body stream and, optionally body size.
+//
+// If bodySize is >= 0, then the bodyStream must provide exactly bodySize bytes
+// before returning io.EOF.
+//
+// If bodySize < 0, then bodyStream is read until io.EOF.
+//
+// bodyStream.Close() is called after finishing reading all body data
+// if it implements io.Closer.
+//
+// See also SetBodyStreamWriter.
+func (resp *Response) SetBodyStream(bodyStream io.Reader, bodySize int) {
+ resp.ResetBody()
+ resp.bodyStream = bodyStream
+ resp.Header.SetContentLength(bodySize)
+}
+
+// IsBodyStream returns true if body is set via SetBodyStream*
+func (req *Request) IsBodyStream() bool {
+ return req.bodyStream != nil
+}
+
+// IsBodyStream returns true if body is set via SetBodyStream*
+func (resp *Response) IsBodyStream() bool {
+ return resp.bodyStream != nil
+}
+
+// SetBodyStreamWriter registers the given sw for populating request body.
+//
+// This function may be used in the following cases:
+//
+// - if request body is too big (more than 10MB).
+// - if request body is streamed from slow external sources.
+// - if request body must be streamed to the server in chunks
+// (aka `http client push` or `chunked transfer-encoding`).
+//
+// Note that GET and HEAD requests cannot have body.
+//
+// See also SetBodyStream.
+func (req *Request) SetBodyStreamWriter(sw StreamWriter) {
+ sr := NewStreamReader(sw)
+ req.SetBodyStream(sr, -1)
+}
+
+// SetBodyStreamWriter registers the given sw for populating response body.
+//
+// This function may be used in the following cases:
+//
+// - if response body is too big (more than 10MB).
+// - if response body is streamed from slow external sources.
+// - if response body must be streamed to the client in chunks
+// (aka `http server push` or `chunked transfer-encoding`).
+//
+// See also SetBodyStream.
+func (resp *Response) SetBodyStreamWriter(sw StreamWriter) {
+ sr := NewStreamReader(sw)
+ resp.SetBodyStream(sr, -1)
+}
+
+// BodyWriter returns writer for populating response body.
+//
+// If used inside RequestHandler, the returned writer must not be used
+// after returning from RequestHandler. Use RequestCtx.Write
+// or SetBodyStreamWriter in this case.
+func (resp *Response) BodyWriter() io.Writer {
+ resp.w.r = resp
+ return &resp.w
+}
+
+// BodyStream returns io.Reader
+//
+// You must CloseBodyStream or ReleaseRequest after you use it.
+func (req *Request) BodyStream() io.Reader {
+ return req.bodyStream
+}
+
+func (req *Request) CloseBodyStream() error {
+ return req.closeBodyStream()
+}
+
+// BodyStream returns io.Reader
+//
+// You must CloseBodyStream or ReleaseResponse after you use it.
+func (resp *Response) BodyStream() io.Reader {
+ return resp.bodyStream
+}
+
+func (resp *Response) CloseBodyStream() error {
+ return resp.closeBodyStream()
+}
+
+type closeReader struct {
+ io.Reader
+ closeFunc func() error
+}
+
+func newCloseReader(r io.Reader, closeFunc func() error) io.ReadCloser {
+ if r == nil {
+ panic(`BUG: reader is nil`)
+ }
+ return &closeReader{Reader: r, closeFunc: closeFunc}
+}
+
+func (c *closeReader) Close() error {
+ if c.closeFunc == nil {
+ return nil
+ }
+ return c.closeFunc()
+}
+
+// BodyWriter returns writer for populating request body.
+func (req *Request) BodyWriter() io.Writer {
+ req.w.r = req
+ return &req.w
+}
+
+type responseBodyWriter struct {
+ r *Response
+}
+
+func (w *responseBodyWriter) Write(p []byte) (int, error) {
+ w.r.AppendBody(p)
+ return len(p), nil
+}
+
+type requestBodyWriter struct {
+ r *Request
+}
+
+func (w *requestBodyWriter) Write(p []byte) (int, error) {
+ w.r.AppendBody(p)
+ return len(p), nil
+}
+
+func (resp *Response) parseNetConn(conn net.Conn) {
+ resp.raddr = conn.RemoteAddr()
+ resp.laddr = conn.LocalAddr()
+}
+
+// RemoteAddr returns the remote network address. The Addr returned is shared
+// by all invocations of RemoteAddr, so do not modify it.
+func (resp *Response) RemoteAddr() net.Addr {
+ return resp.raddr
+}
+
+// LocalAddr returns the local network address. The Addr returned is shared
+// by all invocations of LocalAddr, so do not modify it.
+func (resp *Response) LocalAddr() net.Addr {
+ return resp.laddr
+}
+
+// Body returns response body.
+//
+// The returned value is valid until the response is released,
+// either though ReleaseResponse or your request handler returning.
+// Do not store references to returned value. Make copies instead.
+func (resp *Response) Body() []byte {
+ if resp.bodyStream != nil {
+ bodyBuf := resp.bodyBuffer()
+ bodyBuf.Reset()
+ _, err := copyZeroAlloc(bodyBuf, resp.bodyStream)
+ resp.closeBodyStream() //nolint:errcheck
+ if err != nil {
+ bodyBuf.SetString(err.Error())
+ }
+ }
+ return resp.bodyBytes()
+}
+
+func (resp *Response) bodyBytes() []byte {
+ if resp.bodyRaw != nil {
+ return resp.bodyRaw
+ }
+ if resp.body == nil {
+ return nil
+ }
+ return resp.body.B
+}
+
+func (req *Request) bodyBytes() []byte {
+ if req.bodyRaw != nil {
+ return req.bodyRaw
+ }
+ if req.bodyStream != nil {
+ bodyBuf := req.bodyBuffer()
+ bodyBuf.Reset()
+ _, err := copyZeroAlloc(bodyBuf, req.bodyStream)
+ req.closeBodyStream() //nolint:errcheck
+ if err != nil {
+ bodyBuf.SetString(err.Error())
+ }
+ }
+ if req.body == nil {
+ return nil
+ }
+ return req.body.B
+}
+
+func (resp *Response) bodyBuffer() *bytebufferpool.ByteBuffer {
+ if resp.body == nil {
+ resp.body = responseBodyPool.Get()
+ }
+ resp.bodyRaw = nil
+ return resp.body
+}
+
+func (req *Request) bodyBuffer() *bytebufferpool.ByteBuffer {
+ if req.body == nil {
+ req.body = requestBodyPool.Get()
+ }
+ req.bodyRaw = nil
+ return req.body
+}
+
+var (
+ responseBodyPool bytebufferpool.Pool
+ requestBodyPool bytebufferpool.Pool
+)
+
+// BodyGunzip returns un-gzipped body data.
+//
+// This method may be used if the request header contains
+// 'Content-Encoding: gzip' for reading un-gzipped body.
+// Use Body for reading gzipped request body.
+func (req *Request) BodyGunzip() ([]byte, error) {
+ return gunzipData(req.Body())
+}
+
+// BodyGunzip returns un-gzipped body data.
+//
+// This method may be used if the response header contains
+// 'Content-Encoding: gzip' for reading un-gzipped body.
+// Use Body for reading gzipped response body.
+func (resp *Response) BodyGunzip() ([]byte, error) {
+ return gunzipData(resp.Body())
+}
+
+func gunzipData(p []byte) ([]byte, error) {
+ var bb bytebufferpool.ByteBuffer
+ _, err := WriteGunzip(&bb, p)
+ if err != nil {
+ return nil, err
+ }
+ return bb.B, nil
+}
+
+// BodyUnbrotli returns un-brotlied body data.
+//
+// This method may be used if the request header contains
+// 'Content-Encoding: br' for reading un-brotlied body.
+// Use Body for reading brotlied request body.
+func (req *Request) BodyUnbrotli() ([]byte, error) {
+ return unBrotliData(req.Body())
+}
+
+// BodyUnbrotli returns un-brotlied body data.
+//
+// This method may be used if the response header contains
+// 'Content-Encoding: br' for reading un-brotlied body.
+// Use Body for reading brotlied response body.
+func (resp *Response) BodyUnbrotli() ([]byte, error) {
+ return unBrotliData(resp.Body())
+}
+
+func unBrotliData(p []byte) ([]byte, error) {
+ var bb bytebufferpool.ByteBuffer
+ _, err := WriteUnbrotli(&bb, p)
+ if err != nil {
+ return nil, err
+ }
+ return bb.B, nil
+}
+
+// BodyInflate returns inflated body data.
+//
+// This method may be used if the response header contains
+// 'Content-Encoding: deflate' for reading inflated request body.
+// Use Body for reading deflated request body.
+func (req *Request) BodyInflate() ([]byte, error) {
+ return inflateData(req.Body())
+}
+
+// BodyInflate returns inflated body data.
+//
+// This method may be used if the response header contains
+// 'Content-Encoding: deflate' for reading inflated response body.
+// Use Body for reading deflated response body.
+func (resp *Response) BodyInflate() ([]byte, error) {
+ return inflateData(resp.Body())
+}
+
+func (ctx *RequestCtx) RequestBodyStream() io.Reader {
+ return ctx.Request.bodyStream
+}
+
+func inflateData(p []byte) ([]byte, error) {
+ var bb bytebufferpool.ByteBuffer
+ _, err := WriteInflate(&bb, p)
+ if err != nil {
+ return nil, err
+ }
+ return bb.B, nil
+}
+
+var ErrContentEncodingUnsupported = errors.New("unsupported Content-Encoding")
+
+// BodyUncompressed returns body data and if needed decompress it from gzip, deflate or Brotli.
+//
+// This method may be used if the response header contains
+// 'Content-Encoding' for reading uncompressed request body.
+// Use Body for reading the raw request body.
+func (req *Request) BodyUncompressed() ([]byte, error) {
+ switch string(req.Header.ContentEncoding()) {
+ case "":
+ return req.Body(), nil
+ case "deflate":
+ return req.BodyInflate()
+ case "gzip":
+ return req.BodyGunzip()
+ case "br":
+ return req.BodyUnbrotli()
+ default:
+ return nil, ErrContentEncodingUnsupported
+ }
+}
+
+// BodyUncompressed returns body data and if needed decompress it from gzip, deflate or Brotli.
+//
+// This method may be used if the response header contains
+// 'Content-Encoding' for reading uncompressed response body.
+// Use Body for reading the raw response body.
+func (resp *Response) BodyUncompressed() ([]byte, error) {
+ switch string(resp.Header.ContentEncoding()) {
+ case "":
+ return resp.Body(), nil
+ case "deflate":
+ return resp.BodyInflate()
+ case "gzip":
+ return resp.BodyGunzip()
+ case "br":
+ return resp.BodyUnbrotli()
+ default:
+ return nil, ErrContentEncodingUnsupported
+ }
+}
+
+// BodyWriteTo writes request body to w.
+func (req *Request) BodyWriteTo(w io.Writer) error {
+ if req.bodyStream != nil {
+ _, err := copyZeroAlloc(w, req.bodyStream)
+ req.closeBodyStream() //nolint:errcheck
+ return err
+ }
+ if req.onlyMultipartForm() {
+ return WriteMultipartForm(w, req.multipartForm, req.multipartFormBoundary)
+ }
+ _, err := w.Write(req.bodyBytes())
+ return err
+}
+
+// BodyWriteTo writes response body to w.
+func (resp *Response) BodyWriteTo(w io.Writer) error {
+ if resp.bodyStream != nil {
+ _, err := copyZeroAlloc(w, resp.bodyStream)
+ resp.closeBodyStream() //nolint:errcheck
+ return err
+ }
+ _, err := w.Write(resp.bodyBytes())
+ return err
+}
+
+// AppendBody appends p to response body.
+//
+// It is safe re-using p after the function returns.
+func (resp *Response) AppendBody(p []byte) {
+ resp.closeBodyStream() //nolint:errcheck
+ resp.bodyBuffer().Write(p) //nolint:errcheck
+}
+
+// AppendBodyString appends s to response body.
+func (resp *Response) AppendBodyString(s string) {
+ resp.closeBodyStream() //nolint:errcheck
+ resp.bodyBuffer().WriteString(s) //nolint:errcheck
+}
+
+// SetBody sets response body.
+//
+// It is safe re-using body argument after the function returns.
+func (resp *Response) SetBody(body []byte) {
+ resp.closeBodyStream() //nolint:errcheck
+ bodyBuf := resp.bodyBuffer()
+ bodyBuf.Reset()
+ bodyBuf.Write(body) //nolint:errcheck
+}
+
+// SetBodyString sets response body.
+func (resp *Response) SetBodyString(body string) {
+ resp.closeBodyStream() //nolint:errcheck
+ bodyBuf := resp.bodyBuffer()
+ bodyBuf.Reset()
+ bodyBuf.WriteString(body) //nolint:errcheck
+}
+
+// ResetBody resets response body.
+func (resp *Response) ResetBody() {
+ resp.bodyRaw = nil
+ resp.closeBodyStream() //nolint:errcheck
+ if resp.body != nil {
+ if resp.keepBodyBuffer {
+ resp.body.Reset()
+ } else {
+ responseBodyPool.Put(resp.body)
+ resp.body = nil
+ }
+ }
+}
+
+// SetBodyRaw sets response body, but without copying it.
+//
+// From this point onward the body argument must not be changed.
+func (resp *Response) SetBodyRaw(body []byte) {
+ resp.ResetBody()
+ resp.bodyRaw = body
+}
+
+// SetBodyRaw sets response body, but without copying it.
+//
+// From this point onward the body argument must not be changed.
+func (req *Request) SetBodyRaw(body []byte) {
+ req.ResetBody()
+ req.bodyRaw = body
+}
+
+// ReleaseBody retires the response body if it is greater than "size" bytes.
+//
+// This permits GC to reclaim the large buffer. If used, must be before
+// ReleaseResponse.
+//
+// Use this method only if you really understand how it works.
+// The majority of workloads don't need this method.
+func (resp *Response) ReleaseBody(size int) {
+ resp.bodyRaw = nil
+ if resp.body == nil {
+ return
+ }
+ if cap(resp.body.B) > size {
+ resp.closeBodyStream() //nolint:errcheck
+ resp.body = nil
+ }
+}
+
+// ReleaseBody retires the request body if it is greater than "size" bytes.
+//
+// This permits GC to reclaim the large buffer. If used, must be before
+// ReleaseRequest.
+//
+// Use this method only if you really understand how it works.
+// The majority of workloads don't need this method.
+func (req *Request) ReleaseBody(size int) {
+ req.bodyRaw = nil
+ if req.body == nil {
+ return
+ }
+ if cap(req.body.B) > size {
+ req.closeBodyStream() //nolint:errcheck
+ req.body = nil
+ }
+}
+
+// SwapBody swaps response body with the given body and returns
+// the previous response body.
+//
+// It is forbidden to use the body passed to SwapBody after
+// the function returns.
+func (resp *Response) SwapBody(body []byte) []byte {
+ bb := resp.bodyBuffer()
+
+ if resp.bodyStream != nil {
+ bb.Reset()
+ _, err := copyZeroAlloc(bb, resp.bodyStream)
+ resp.closeBodyStream() //nolint:errcheck
+ if err != nil {
+ bb.Reset()
+ bb.SetString(err.Error())
+ }
+ }
+
+ resp.bodyRaw = nil
+
+ oldBody := bb.B
+ bb.B = body
+ return oldBody
+}
+
+// SwapBody swaps request body with the given body and returns
+// the previous request body.
+//
+// It is forbidden to use the body passed to SwapBody after
+// the function returns.
+func (req *Request) SwapBody(body []byte) []byte {
+ bb := req.bodyBuffer()
+
+ if req.bodyStream != nil {
+ bb.Reset()
+ _, err := copyZeroAlloc(bb, req.bodyStream)
+ req.closeBodyStream() //nolint:errcheck
+ if err != nil {
+ bb.Reset()
+ bb.SetString(err.Error())
+ }
+ }
+
+ req.bodyRaw = nil
+
+ oldBody := bb.B
+ bb.B = body
+ return oldBody
+}
+
+// Body returns request body.
+//
+// The returned value is valid until the request is released,
+// either though ReleaseRequest or your request handler returning.
+// Do not store references to returned value. Make copies instead.
+func (req *Request) Body() []byte {
+ if req.bodyRaw != nil {
+ return req.bodyRaw
+ } else if req.onlyMultipartForm() {
+ body, err := marshalMultipartForm(req.multipartForm, req.multipartFormBoundary)
+ if err != nil {
+ return []byte(err.Error())
+ }
+ return body
+ }
+ return req.bodyBytes()
+}
+
+// AppendBody appends p to request body.
+//
+// It is safe re-using p after the function returns.
+func (req *Request) AppendBody(p []byte) {
+ req.RemoveMultipartFormFiles()
+ req.closeBodyStream() //nolint:errcheck
+ req.bodyBuffer().Write(p) //nolint:errcheck
+}
+
+// AppendBodyString appends s to request body.
+func (req *Request) AppendBodyString(s string) {
+ req.RemoveMultipartFormFiles()
+ req.closeBodyStream() //nolint:errcheck
+ req.bodyBuffer().WriteString(s) //nolint:errcheck
+}
+
+// SetBody sets request body.
+//
+// It is safe re-using body argument after the function returns.
+func (req *Request) SetBody(body []byte) {
+ req.RemoveMultipartFormFiles()
+ req.closeBodyStream() //nolint:errcheck
+ req.bodyBuffer().Set(body)
+}
+
+// SetBodyString sets request body.
+func (req *Request) SetBodyString(body string) {
+ req.RemoveMultipartFormFiles()
+ req.closeBodyStream() //nolint:errcheck
+ req.bodyBuffer().SetString(body)
+}
+
+// ResetBody resets request body.
+func (req *Request) ResetBody() {
+ req.bodyRaw = nil
+ req.RemoveMultipartFormFiles()
+ req.closeBodyStream() //nolint:errcheck
+ if req.body != nil {
+ if req.keepBodyBuffer {
+ req.body.Reset()
+ } else {
+ requestBodyPool.Put(req.body)
+ req.body = nil
+ }
+ }
+}
+
+// CopyTo copies req contents to dst except of body stream.
+func (req *Request) CopyTo(dst *Request) {
+ req.copyToSkipBody(dst)
+ switch {
+ case req.bodyRaw != nil:
+ dst.bodyRaw = append(dst.bodyRaw[:0], req.bodyRaw...)
+ if dst.body != nil {
+ dst.body.Reset()
+ }
+ case req.body != nil:
+ dst.bodyBuffer().Set(req.body.B)
+ case dst.body != nil:
+ dst.body.Reset()
+ }
+}
+
+func (req *Request) copyToSkipBody(dst *Request) {
+ dst.Reset()
+ req.Header.CopyTo(&dst.Header)
+
+ req.uri.CopyTo(&dst.uri)
+ dst.parsedURI = req.parsedURI
+
+ req.postArgs.CopyTo(&dst.postArgs)
+ dst.parsedPostArgs = req.parsedPostArgs
+ dst.isTLS = req.isTLS
+
+ dst.UseHostHeader = req.UseHostHeader
+
+ // do not copy multipartForm - it will be automatically
+ // re-created on the first call to MultipartForm.
+}
+
+// CopyTo copies resp contents to dst except of body stream.
+func (resp *Response) CopyTo(dst *Response) {
+ resp.copyToSkipBody(dst)
+ switch {
+ case resp.bodyRaw != nil:
+ dst.bodyRaw = append(dst.bodyRaw, resp.bodyRaw...)
+ if dst.body != nil {
+ dst.body.Reset()
+ }
+ case resp.body != nil:
+ dst.bodyBuffer().Set(resp.body.B)
+ case dst.body != nil:
+ dst.body.Reset()
+ }
+}
+
+func (resp *Response) copyToSkipBody(dst *Response) {
+ dst.Reset()
+ resp.Header.CopyTo(&dst.Header)
+ dst.SkipBody = resp.SkipBody
+ dst.raddr = resp.raddr
+ dst.laddr = resp.laddr
+}
+
+func swapRequestBody(a, b *Request) {
+ a.body, b.body = b.body, a.body
+ a.bodyRaw, b.bodyRaw = b.bodyRaw, a.bodyRaw
+ a.bodyStream, b.bodyStream = b.bodyStream, a.bodyStream
+
+ // This code assumes that if a requestStream was swapped the headers are also swapped or copied.
+ if rs, ok := a.bodyStream.(*requestStream); ok {
+ rs.header = &a.Header
+ }
+ if rs, ok := b.bodyStream.(*requestStream); ok {
+ rs.header = &b.Header
+ }
+}
+
+func swapResponseBody(a, b *Response) {
+ a.body, b.body = b.body, a.body
+ a.bodyRaw, b.bodyRaw = b.bodyRaw, a.bodyRaw
+ a.bodyStream, b.bodyStream = b.bodyStream, a.bodyStream
+}
+
+// URI returns request URI
+func (req *Request) URI() *URI {
+ req.parseURI() //nolint:errcheck
+ return &req.uri
+}
+
+// SetURI initializes request URI
+// Use this method if a single URI may be reused across multiple requests.
+// Otherwise, you can just use SetRequestURI() and it will be parsed as new URI.
+// The URI is copied and can be safely modified later.
+func (req *Request) SetURI(newURI *URI) {
+ if newURI != nil {
+ newURI.CopyTo(&req.uri)
+ req.parsedURI = true
+ return
+ }
+ req.uri.Reset()
+ req.parsedURI = false
+}
+
+func (req *Request) parseURI() error {
+ if req.parsedURI {
+ return nil
+ }
+ req.parsedURI = true
+
+ return req.uri.parse(req.Header.Host(), req.Header.RequestURI(), req.isTLS)
+}
+
+// PostArgs returns POST arguments.
+func (req *Request) PostArgs() *Args {
+ req.parsePostArgs()
+ return &req.postArgs
+}
+
+func (req *Request) parsePostArgs() {
+ if req.parsedPostArgs {
+ return
+ }
+ req.parsedPostArgs = true
+
+ if !bytes.HasPrefix(req.Header.ContentType(), strPostArgsContentType) {
+ return
+ }
+ req.postArgs.ParseBytes(req.bodyBytes())
+}
+
+// ErrNoMultipartForm means that the request's Content-Type
+// isn't 'multipart/form-data'.
+var ErrNoMultipartForm = errors.New("request Content-Type has bad boundary or is not multipart/form-data")
+
+// MultipartForm returns request's multipart form.
+//
+// Returns ErrNoMultipartForm if request's Content-Type
+// isn't 'multipart/form-data'.
+//
+// RemoveMultipartFormFiles must be called after returned multipart form
+// is processed.
+func (req *Request) MultipartForm() (*multipart.Form, error) {
+ if req.multipartForm != nil {
+ return req.multipartForm, nil
+ }
+
+ req.multipartFormBoundary = string(req.Header.MultipartFormBoundary())
+ if len(req.multipartFormBoundary) == 0 {
+ return nil, ErrNoMultipartForm
+ }
+
+ var err error
+ ce := req.Header.peek(strContentEncoding)
+
+ if req.bodyStream != nil {
+ bodyStream := req.bodyStream
+ if bytes.Equal(ce, strGzip) {
+ // Do not care about memory usage here.
+ if bodyStream, err = gzip.NewReader(bodyStream); err != nil {
+ return nil, fmt.Errorf("cannot gunzip request body: %w", err)
+ }
+ } else if len(ce) > 0 {
+ return nil, fmt.Errorf("unsupported Content-Encoding: %q", ce)
+ }
+
+ mr := multipart.NewReader(bodyStream, req.multipartFormBoundary)
+ req.multipartForm, err = mr.ReadForm(8 * 1024)
+ if err != nil {
+ return nil, fmt.Errorf("cannot read multipart/form-data body: %w", err)
+ }
+ } else {
+ body := req.bodyBytes()
+ if bytes.Equal(ce, strGzip) {
+ // Do not care about memory usage here.
+ if body, err = AppendGunzipBytes(nil, body); err != nil {
+ return nil, fmt.Errorf("cannot gunzip request body: %w", err)
+ }
+ } else if len(ce) > 0 {
+ return nil, fmt.Errorf("unsupported Content-Encoding: %q", ce)
+ }
+
+ req.multipartForm, err = readMultipartForm(bytes.NewReader(body), req.multipartFormBoundary, len(body), len(body))
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ return req.multipartForm, nil
+}
+
+func marshalMultipartForm(f *multipart.Form, boundary string) ([]byte, error) {
+ var buf bytebufferpool.ByteBuffer
+ if err := WriteMultipartForm(&buf, f, boundary); err != nil {
+ return nil, err
+ }
+ return buf.B, nil
+}
+
+// WriteMultipartForm writes the given multipart form f with the given
+// boundary to w.
+func WriteMultipartForm(w io.Writer, f *multipart.Form, boundary string) error {
+ // Do not care about memory allocations here, since multipart
+ // form processing is slow.
+ if len(boundary) == 0 {
+ return errors.New("form boundary cannot be empty")
+ }
+
+ mw := multipart.NewWriter(w)
+ if err := mw.SetBoundary(boundary); err != nil {
+ return fmt.Errorf("cannot use form boundary %q: %w", boundary, err)
+ }
+
+ // marshal values
+ for k, vv := range f.Value {
+ for _, v := range vv {
+ if err := mw.WriteField(k, v); err != nil {
+ return fmt.Errorf("cannot write form field %q value %q: %w", k, v, err)
+ }
+ }
+ }
+
+ // marshal files
+ for k, fvv := range f.File {
+ for _, fv := range fvv {
+ vw, err := mw.CreatePart(fv.Header)
+ if err != nil {
+ return fmt.Errorf("cannot create form file %q (%q): %w", k, fv.Filename, err)
+ }
+ fh, err := fv.Open()
+ if err != nil {
+ return fmt.Errorf("cannot open form file %q (%q): %w", k, fv.Filename, err)
+ }
+ if _, err = copyZeroAlloc(vw, fh); err != nil {
+ _ = fh.Close()
+ return fmt.Errorf("error when copying form file %q (%q): %w", k, fv.Filename, err)
+ }
+ if err = fh.Close(); err != nil {
+ return fmt.Errorf("cannot close form file %q (%q): %w", k, fv.Filename, err)
+ }
+ }
+ }
+
+ if err := mw.Close(); err != nil {
+ return fmt.Errorf("error when closing multipart form writer: %w", err)
+ }
+
+ return nil
+}
+
+func readMultipartForm(r io.Reader, boundary string, size, maxInMemoryFileSize int) (*multipart.Form, error) {
+ // Do not care about memory allocations here, since they are tiny
+ // compared to multipart data (aka multi-MB files) usually sent
+ // in multipart/form-data requests.
+
+ if size <= 0 {
+ return nil, fmt.Errorf("form size must be greater than 0. Given %d", size)
+ }
+ lr := io.LimitReader(r, int64(size))
+ mr := multipart.NewReader(lr, boundary)
+ f, err := mr.ReadForm(int64(maxInMemoryFileSize))
+ if err != nil {
+ return nil, fmt.Errorf("cannot read multipart/form-data body: %w", err)
+ }
+ return f, nil
+}
+
+// Reset clears request contents.
+func (req *Request) Reset() {
+ if requestBodyPoolSizeLimit >= 0 && req.body != nil {
+ req.ReleaseBody(requestBodyPoolSizeLimit)
+ }
+ req.Header.Reset()
+ req.resetSkipHeader()
+ req.timeout = 0
+ req.UseHostHeader = false
+ req.DisableRedirectPathNormalizing = false
+}
+
+func (req *Request) resetSkipHeader() {
+ req.ResetBody()
+ req.uri.Reset()
+ req.parsedURI = false
+ req.postArgs.Reset()
+ req.parsedPostArgs = false
+ req.isTLS = false
+}
+
+// RemoveMultipartFormFiles removes multipart/form-data temporary files
+// associated with the request.
+func (req *Request) RemoveMultipartFormFiles() {
+ if req.multipartForm != nil {
+ // Do not check for error, since these files may be deleted or moved
+ // to new places by user code.
+ req.multipartForm.RemoveAll() //nolint:errcheck
+ req.multipartForm = nil
+ }
+ req.multipartFormBoundary = ""
+}
+
+// Reset clears response contents.
+func (resp *Response) Reset() {
+ if responseBodyPoolSizeLimit >= 0 && resp.body != nil {
+ resp.ReleaseBody(responseBodyPoolSizeLimit)
+ }
+ resp.resetSkipHeader()
+ resp.Header.Reset()
+ resp.SkipBody = false
+ resp.raddr = nil
+ resp.laddr = nil
+ resp.ImmediateHeaderFlush = false
+ resp.StreamBody = false
+}
+
+func (resp *Response) resetSkipHeader() {
+ resp.ResetBody()
+}
+
+// Read reads request (including body) from the given r.
+//
+// RemoveMultipartFormFiles or Reset must be called after
+// reading multipart/form-data request in order to delete temporarily
+// uploaded files.
+//
+// If MayContinue returns true, the caller must:
+//
+// - Either send StatusExpectationFailed response if request headers don't
+// satisfy the caller.
+// - Or send StatusContinue response before reading request body
+// with ContinueReadBody.
+// - Or close the connection.
+//
+// io.EOF is returned if r is closed before reading the first header byte.
+func (req *Request) Read(r *bufio.Reader) error {
+ return req.ReadLimitBody(r, 0)
+}
+
+const defaultMaxInMemoryFileSize = 16 * 1024 * 1024
+
+// ErrGetOnly is returned when server expects only GET requests,
+// but some other type of request came (Server.GetOnly option is true).
+var ErrGetOnly = errors.New("non-GET request received")
+
+// ReadLimitBody reads request from the given r, limiting the body size.
+//
+// If maxBodySize > 0 and the body size exceeds maxBodySize,
+// then ErrBodyTooLarge is returned.
+//
+// RemoveMultipartFormFiles or Reset must be called after
+// reading multipart/form-data request in order to delete temporarily
+// uploaded files.
+//
+// If MayContinue returns true, the caller must:
+//
+// - Either send StatusExpectationFailed response if request headers don't
+// satisfy the caller.
+// - Or send StatusContinue response before reading request body
+// with ContinueReadBody.
+// - Or close the connection.
+//
+// io.EOF is returned if r is closed before reading the first header byte.
+func (req *Request) ReadLimitBody(r *bufio.Reader, maxBodySize int) error {
+ req.resetSkipHeader()
+ if err := req.Header.Read(r); err != nil {
+ return err
+ }
+
+ return req.readLimitBody(r, maxBodySize, false, true)
+}
+
+func (req *Request) readLimitBody(r *bufio.Reader, maxBodySize int, getOnly bool, preParseMultipartForm bool) error {
+ // Do not reset the request here - the caller must reset it before
+ // calling this method.
+
+ if getOnly && !req.Header.IsGet() && !req.Header.IsHead() {
+ return ErrGetOnly
+ }
+
+ if req.MayContinue() {
+ // 'Expect: 100-continue' header found. Let the caller deciding
+ // whether to read request body or
+ // to return StatusExpectationFailed.
+ return nil
+ }
+
+ return req.ContinueReadBody(r, maxBodySize, preParseMultipartForm)
+}
+
+func (req *Request) readBodyStream(r *bufio.Reader, maxBodySize int, getOnly bool, preParseMultipartForm bool) error {
+ // Do not reset the request here - the caller must reset it before
+ // calling this method.
+
+ if getOnly && !req.Header.IsGet() && !req.Header.IsHead() {
+ return ErrGetOnly
+ }
+
+ if req.MayContinue() {
+ // 'Expect: 100-continue' header found. Let the caller deciding
+ // whether to read request body or
+ // to return StatusExpectationFailed.
+ return nil
+ }
+
+ return req.ContinueReadBodyStream(r, maxBodySize, preParseMultipartForm)
+}
+
+// MayContinue returns true if the request contains
+// 'Expect: 100-continue' header.
+//
+// The caller must do one of the following actions if MayContinue returns true:
+//
+// - Either send StatusExpectationFailed response if request headers don't
+// satisfy the caller.
+// - Or send StatusContinue response before reading request body
+// with ContinueReadBody.
+// - Or close the connection.
+func (req *Request) MayContinue() bool {
+ return bytes.Equal(req.Header.peek(strExpect), str100Continue)
+}
+
+// ContinueReadBody reads request body if request header contains
+// 'Expect: 100-continue'.
+//
+// The caller must send StatusContinue response before calling this method.
+//
+// If maxBodySize > 0 and the body size exceeds maxBodySize,
+// then ErrBodyTooLarge is returned.
+func (req *Request) ContinueReadBody(r *bufio.Reader, maxBodySize int, preParseMultipartForm ...bool) error {
+ var err error
+ contentLength := req.Header.realContentLength()
+ if contentLength > 0 {
+ if maxBodySize > 0 && contentLength > maxBodySize {
+ return ErrBodyTooLarge
+ }
+
+ if len(preParseMultipartForm) == 0 || preParseMultipartForm[0] {
+ // Pre-read multipart form data of known length.
+ // This way we limit memory usage for large file uploads, since their contents
+ // is streamed into temporary files if file size exceeds defaultMaxInMemoryFileSize.
+ req.multipartFormBoundary = string(req.Header.MultipartFormBoundary())
+ if len(req.multipartFormBoundary) > 0 && len(req.Header.peek(strContentEncoding)) == 0 {
+ req.multipartForm, err = readMultipartForm(r, req.multipartFormBoundary, contentLength, defaultMaxInMemoryFileSize)
+ if err != nil {
+ req.Reset()
+ }
+ return err
+ }
+ }
+ }
+
+ if contentLength == -2 {
+ // identity body has no sense for http requests, since
+ // the end of body is determined by connection close.
+ // So just ignore request body for requests without
+ // 'Content-Length' and 'Transfer-Encoding' headers.
+ // refer to https://tools.ietf.org/html/rfc7230#section-3.3.2
+ if !req.Header.ignoreBody() {
+ req.Header.SetContentLength(0)
+ }
+ return nil
+ }
+
+ if err = req.ReadBody(r, contentLength, maxBodySize); err != nil {
+ return err
+ }
+
+ if contentLength == -1 {
+ err = req.Header.ReadTrailer(r)
+ if err != nil && err != io.EOF {
+ return err
+ }
+ }
+ return nil
+}
+
+// ReadBody reads request body from the given r, limiting the body size.
+//
+// If maxBodySize > 0 and the body size exceeds maxBodySize,
+// then ErrBodyTooLarge is returned.
+func (req *Request) ReadBody(r *bufio.Reader, contentLength int, maxBodySize int) (err error) {
+ bodyBuf := req.bodyBuffer()
+ bodyBuf.Reset()
+
+ switch {
+ case contentLength >= 0:
+ bodyBuf.B, err = readBody(r, contentLength, maxBodySize, bodyBuf.B)
+ case contentLength == -1:
+ bodyBuf.B, err = readBodyChunked(r, maxBodySize, bodyBuf.B)
+ if err == nil && len(bodyBuf.B) == 0 {
+ req.Header.SetContentLength(0)
+ }
+ default:
+ bodyBuf.B, err = readBodyIdentity(r, maxBodySize, bodyBuf.B)
+ req.Header.SetContentLength(len(bodyBuf.B))
+ }
+
+ if err != nil {
+ req.Reset()
+ return err
+ }
+ return nil
+}
+
+// ContinueReadBodyStream reads request body if request header contains
+// 'Expect: 100-continue'.
+//
+// The caller must send StatusContinue response before calling this method.
+//
+// If maxBodySize > 0 and the body size exceeds maxBodySize,
+// then ErrBodyTooLarge is returned.
+func (req *Request) ContinueReadBodyStream(r *bufio.Reader, maxBodySize int, preParseMultipartForm ...bool) error {
+ var err error
+ contentLength := req.Header.realContentLength()
+ if contentLength > 0 {
+ if len(preParseMultipartForm) == 0 || preParseMultipartForm[0] {
+ // Pre-read multipart form data of known length.
+ // This way we limit memory usage for large file uploads, since their contents
+ // is streamed into temporary files if file size exceeds defaultMaxInMemoryFileSize.
+ req.multipartFormBoundary = b2s(req.Header.MultipartFormBoundary())
+ if len(req.multipartFormBoundary) > 0 && len(req.Header.peek(strContentEncoding)) == 0 {
+ req.multipartForm, err = readMultipartForm(r, req.multipartFormBoundary, contentLength, defaultMaxInMemoryFileSize)
+ if err != nil {
+ req.Reset()
+ }
+ return err
+ }
+ }
+ }
+
+ if contentLength == -2 {
+ // identity body has no sense for http requests, since
+ // the end of body is determined by connection close.
+ // So just ignore request body for requests without
+ // 'Content-Length' and 'Transfer-Encoding' headers.
+
+ // refer to https://tools.ietf.org/html/rfc7230#section-3.3.2
+ if !req.Header.ignoreBody() {
+ req.Header.SetContentLength(0)
+ }
+ return nil
+ }
+
+ bodyBuf := req.bodyBuffer()
+ bodyBuf.Reset()
+ bodyBuf.B, err = readBodyWithStreaming(r, contentLength, maxBodySize, bodyBuf.B)
+ if err != nil {
+ if err == ErrBodyTooLarge {
+ req.Header.SetContentLength(contentLength)
+ req.body = bodyBuf
+ req.bodyStream = acquireRequestStream(bodyBuf, r, &req.Header)
+ return nil
+ }
+ if err == errChunkedStream {
+ req.body = bodyBuf
+ req.bodyStream = acquireRequestStream(bodyBuf, r, &req.Header)
+ return nil
+ }
+ req.Reset()
+ return err
+ }
+
+ req.body = bodyBuf
+ req.bodyStream = acquireRequestStream(bodyBuf, r, &req.Header)
+ req.Header.SetContentLength(contentLength)
+ return nil
+}
+
+// Read reads response (including body) from the given r.
+//
+// io.EOF is returned if r is closed before reading the first header byte.
+func (resp *Response) Read(r *bufio.Reader) error {
+ return resp.ReadLimitBody(r, 0)
+}
+
+// ReadLimitBody reads response headers from the given r,
+// then reads the body using the ReadBody function and limiting the body size.
+//
+// If resp.SkipBody is true then it skips reading the response body.
+//
+// If maxBodySize > 0 and the body size exceeds maxBodySize,
+// then ErrBodyTooLarge is returned.
+//
+// io.EOF is returned if r is closed before reading the first header byte.
+func (resp *Response) ReadLimitBody(r *bufio.Reader, maxBodySize int) error {
+ resp.resetSkipHeader()
+ err := resp.Header.Read(r)
+ if err != nil {
+ return err
+ }
+ if resp.Header.StatusCode() == StatusContinue {
+ // Read the next response according to http://www.w3.org/Protocols/rfc2616/rfc2616-sec8.html .
+ if err = resp.Header.Read(r); err != nil {
+ return err
+ }
+ }
+
+ if !resp.mustSkipBody() {
+ err = resp.ReadBody(r, maxBodySize)
+ if err != nil {
+ if isConnectionReset(err) {
+ return nil
+ }
+ return err
+ }
+ }
+
+ if resp.Header.ContentLength() == -1 && !resp.StreamBody {
+ err = resp.Header.ReadTrailer(r)
+ if err != nil && err != io.EOF {
+ if isConnectionReset(err) {
+ return nil
+ }
+ return err
+ }
+ }
+ return nil
+}
+
+// ReadBody reads response body from the given r, limiting the body size.
+//
+// If maxBodySize > 0 and the body size exceeds maxBodySize,
+// then ErrBodyTooLarge is returned.
+func (resp *Response) ReadBody(r *bufio.Reader, maxBodySize int) (err error) {
+ bodyBuf := resp.bodyBuffer()
+ bodyBuf.Reset()
+
+ contentLength := resp.Header.ContentLength()
+ switch {
+ case contentLength >= 0:
+ bodyBuf.B, err = readBody(r, contentLength, maxBodySize, bodyBuf.B)
+ if err == ErrBodyTooLarge && resp.StreamBody {
+ resp.bodyStream = acquireRequestStream(bodyBuf, r, &resp.Header)
+ err = nil
+ }
+ case contentLength == -1:
+ if resp.StreamBody {
+ resp.bodyStream = acquireRequestStream(bodyBuf, r, &resp.Header)
+ } else {
+ bodyBuf.B, err = readBodyChunked(r, maxBodySize, bodyBuf.B)
+ }
+ default:
+ bodyBuf.B, err = readBodyIdentity(r, maxBodySize, bodyBuf.B)
+ resp.Header.SetContentLength(len(bodyBuf.B))
+ }
+ if err == nil && resp.StreamBody && resp.bodyStream == nil {
+ resp.bodyStream = bytes.NewReader(bodyBuf.B)
+ }
+ return err
+}
+
+func (resp *Response) mustSkipBody() bool {
+ return resp.SkipBody || resp.Header.mustSkipContentLength()
+}
+
+var errRequestHostRequired = errors.New("missing required Host header in request")
+
+// WriteTo writes request to w. It implements io.WriterTo.
+func (req *Request) WriteTo(w io.Writer) (int64, error) {
+ return writeBufio(req, w)
+}
+
+// WriteTo writes response to w. It implements io.WriterTo.
+func (resp *Response) WriteTo(w io.Writer) (int64, error) {
+ return writeBufio(resp, w)
+}
+
+func writeBufio(hw httpWriter, w io.Writer) (int64, error) {
+ sw := acquireStatsWriter(w)
+ bw := acquireBufioWriter(sw)
+ err1 := hw.Write(bw)
+ err2 := bw.Flush()
+ releaseBufioWriter(bw)
+ n := sw.bytesWritten
+ releaseStatsWriter(sw)
+
+ err := err1
+ if err == nil {
+ err = err2
+ }
+ return n, err
+}
+
+type statsWriter struct {
+ w io.Writer
+ bytesWritten int64
+}
+
+func (w *statsWriter) Write(p []byte) (int, error) {
+ n, err := w.w.Write(p)
+ w.bytesWritten += int64(n)
+ return n, err
+}
+
+func acquireStatsWriter(w io.Writer) *statsWriter {
+ v := statsWriterPool.Get()
+ if v == nil {
+ return &statsWriter{
+ w: w,
+ }
+ }
+ sw := v.(*statsWriter)
+ sw.w = w
+ return sw
+}
+
+func releaseStatsWriter(sw *statsWriter) {
+ sw.w = nil
+ sw.bytesWritten = 0
+ statsWriterPool.Put(sw)
+}
+
+var statsWriterPool sync.Pool
+
+func acquireBufioWriter(w io.Writer) *bufio.Writer {
+ v := bufioWriterPool.Get()
+ if v == nil {
+ return bufio.NewWriter(w)
+ }
+ bw := v.(*bufio.Writer)
+ bw.Reset(w)
+ return bw
+}
+
+func releaseBufioWriter(bw *bufio.Writer) {
+ bufioWriterPool.Put(bw)
+}
+
+var bufioWriterPool sync.Pool
+
+func (req *Request) onlyMultipartForm() bool {
+ return req.multipartForm != nil && (req.body == nil || len(req.body.B) == 0)
+}
+
+// Write writes request to w.
+//
+// Write doesn't flush request to w for performance reasons.
+//
+// See also WriteTo.
+func (req *Request) Write(w *bufio.Writer) error {
+ if len(req.Header.Host()) == 0 || req.parsedURI {
+ uri := req.URI()
+ host := uri.Host()
+ if len(req.Header.Host()) == 0 {
+ if len(host) == 0 {
+ return errRequestHostRequired
+ } else {
+ req.Header.SetHostBytes(host)
+ }
+ } else if !req.UseHostHeader {
+ req.Header.SetHostBytes(host)
+ }
+ req.Header.SetRequestURIBytes(uri.RequestURI())
+
+ if len(uri.username) > 0 {
+ // RequestHeader.SetBytesKV only uses RequestHeader.bufKV.key
+ // So we are free to use RequestHeader.bufKV.value as a scratch pad for
+ // the base64 encoding.
+ nl := len(uri.username) + len(uri.password) + 1
+ nb := nl + len(strBasicSpace)
+ tl := nb + base64.StdEncoding.EncodedLen(nl)
+ if tl > cap(req.Header.bufKV.value) {
+ req.Header.bufKV.value = make([]byte, 0, tl)
+ }
+ buf := req.Header.bufKV.value[:0]
+ buf = append(buf, uri.username...)
+ buf = append(buf, strColon...)
+ buf = append(buf, uri.password...)
+ buf = append(buf, strBasicSpace...)
+ base64.StdEncoding.Encode(buf[nb:tl], buf[:nl])
+ req.Header.SetBytesKV(strAuthorization, buf[nl:tl])
+ }
+ }
+
+ if req.bodyStream != nil {
+ return req.writeBodyStream(w)
+ }
+
+ body := req.bodyBytes()
+ var err error
+ if req.onlyMultipartForm() {
+ body, err = marshalMultipartForm(req.multipartForm, req.multipartFormBoundary)
+ if err != nil {
+ return fmt.Errorf("error when marshaling multipart form: %w", err)
+ }
+ req.Header.SetMultipartFormBoundary(req.multipartFormBoundary)
+ }
+
+ hasBody := false
+ if len(body) == 0 {
+ body = req.postArgs.QueryString()
+ }
+ if len(body) != 0 || !req.Header.ignoreBody() {
+ hasBody = true
+ req.Header.SetContentLength(len(body))
+ }
+ if err = req.Header.Write(w); err != nil {
+ return err
+ }
+ if hasBody {
+ _, err = w.Write(body)
+ } else if len(body) > 0 {
+ if req.secureErrorLogMessage {
+ return fmt.Errorf("non-zero body for non-POST request")
+ }
+ return fmt.Errorf("non-zero body for non-POST request. body=%q", body)
+ }
+ return err
+}
+
+// WriteGzip writes response with gzipped body to w.
+//
+// The method gzips response body and sets 'Content-Encoding: gzip'
+// header before writing response to w.
+//
+// WriteGzip doesn't flush response to w for performance reasons.
+func (resp *Response) WriteGzip(w *bufio.Writer) error {
+ return resp.WriteGzipLevel(w, CompressDefaultCompression)
+}
+
+// WriteGzipLevel writes response with gzipped body to w.
+//
+// Level is the desired compression level:
+//
+// - CompressNoCompression
+// - CompressBestSpeed
+// - CompressBestCompression
+// - CompressDefaultCompression
+// - CompressHuffmanOnly
+//
+// The method gzips response body and sets 'Content-Encoding: gzip'
+// header before writing response to w.
+//
+// WriteGzipLevel doesn't flush response to w for performance reasons.
+func (resp *Response) WriteGzipLevel(w *bufio.Writer, level int) error {
+ if err := resp.gzipBody(level); err != nil {
+ return err
+ }
+ return resp.Write(w)
+}
+
+// WriteDeflate writes response with deflated body to w.
+//
+// The method deflates response body and sets 'Content-Encoding: deflate'
+// header before writing response to w.
+//
+// WriteDeflate doesn't flush response to w for performance reasons.
+func (resp *Response) WriteDeflate(w *bufio.Writer) error {
+ return resp.WriteDeflateLevel(w, CompressDefaultCompression)
+}
+
+// WriteDeflateLevel writes response with deflated body to w.
+//
+// Level is the desired compression level:
+//
+// - CompressNoCompression
+// - CompressBestSpeed
+// - CompressBestCompression
+// - CompressDefaultCompression
+// - CompressHuffmanOnly
+//
+// The method deflates response body and sets 'Content-Encoding: deflate'
+// header before writing response to w.
+//
+// WriteDeflateLevel doesn't flush response to w for performance reasons.
+func (resp *Response) WriteDeflateLevel(w *bufio.Writer, level int) error {
+ if err := resp.deflateBody(level); err != nil {
+ return err
+ }
+ return resp.Write(w)
+}
+
+func (resp *Response) brotliBody(level int) error {
+ if len(resp.Header.ContentEncoding()) > 0 {
+ // It looks like the body is already compressed.
+ // Do not compress it again.
+ return nil
+ }
+
+ if !resp.Header.isCompressibleContentType() {
+ // The content-type cannot be compressed.
+ return nil
+ }
+
+ if resp.bodyStream != nil {
+ // Reset Content-Length to -1, since it is impossible
+ // to determine body size beforehand of streamed compression.
+ // For https://github.com/valyala/fasthttp/issues/176 .
+ resp.Header.SetContentLength(-1)
+
+ // Do not care about memory allocations here, since brotli is slow
+ // and allocates a lot of memory by itself.
+ bs := resp.bodyStream
+ resp.bodyStream = NewStreamReader(func(sw *bufio.Writer) {
+ zw := acquireStacklessBrotliWriter(sw, level)
+ fw := &flushWriter{
+ wf: zw,
+ bw: sw,
+ }
+ copyZeroAlloc(fw, bs) //nolint:errcheck
+ releaseStacklessBrotliWriter(zw, level)
+ if bsc, ok := bs.(io.Closer); ok {
+ bsc.Close()
+ }
+ })
+ } else {
+ bodyBytes := resp.bodyBytes()
+ if len(bodyBytes) < minCompressLen {
+ // There is no sense in spending CPU time on small body compression,
+ // since there is a very high probability that the compressed
+ // body size will be bigger than the original body size.
+ return nil
+ }
+ w := responseBodyPool.Get()
+ w.B = AppendBrotliBytesLevel(w.B, bodyBytes, level)
+
+ // Hack: swap resp.body with w.
+ if resp.body != nil {
+ responseBodyPool.Put(resp.body)
+ }
+ resp.body = w
+ resp.bodyRaw = nil
+ }
+ resp.Header.SetContentEncodingBytes(strBr)
+ resp.Header.addVaryBytes(strAcceptEncoding)
+ return nil
+}
+
+func (resp *Response) gzipBody(level int) error {
+ if len(resp.Header.ContentEncoding()) > 0 {
+ // It looks like the body is already compressed.
+ // Do not compress it again.
+ return nil
+ }
+
+ if !resp.Header.isCompressibleContentType() {
+ // The content-type cannot be compressed.
+ return nil
+ }
+
+ if resp.bodyStream != nil {
+ // Reset Content-Length to -1, since it is impossible
+ // to determine body size beforehand of streamed compression.
+ // For https://github.com/valyala/fasthttp/issues/176 .
+ resp.Header.SetContentLength(-1)
+
+ // Do not care about memory allocations here, since gzip is slow
+ // and allocates a lot of memory by itself.
+ bs := resp.bodyStream
+ resp.bodyStream = NewStreamReader(func(sw *bufio.Writer) {
+ zw := acquireStacklessGzipWriter(sw, level)
+ fw := &flushWriter{
+ wf: zw,
+ bw: sw,
+ }
+ copyZeroAlloc(fw, bs) //nolint:errcheck
+ releaseStacklessGzipWriter(zw, level)
+ if bsc, ok := bs.(io.Closer); ok {
+ bsc.Close()
+ }
+ })
+ } else {
+ bodyBytes := resp.bodyBytes()
+ if len(bodyBytes) < minCompressLen {
+ // There is no sense in spending CPU time on small body compression,
+ // since there is a very high probability that the compressed
+ // body size will be bigger than the original body size.
+ return nil
+ }
+ w := responseBodyPool.Get()
+ w.B = AppendGzipBytesLevel(w.B, bodyBytes, level)
+
+ // Hack: swap resp.body with w.
+ if resp.body != nil {
+ responseBodyPool.Put(resp.body)
+ }
+ resp.body = w
+ resp.bodyRaw = nil
+ }
+ resp.Header.SetContentEncodingBytes(strGzip)
+ resp.Header.addVaryBytes(strAcceptEncoding)
+ return nil
+}
+
+func (resp *Response) deflateBody(level int) error {
+ if len(resp.Header.ContentEncoding()) > 0 {
+ // It looks like the body is already compressed.
+ // Do not compress it again.
+ return nil
+ }
+
+ if !resp.Header.isCompressibleContentType() {
+ // The content-type cannot be compressed.
+ return nil
+ }
+
+ if resp.bodyStream != nil {
+ // Reset Content-Length to -1, since it is impossible
+ // to determine body size beforehand of streamed compression.
+ // For https://github.com/valyala/fasthttp/issues/176 .
+ resp.Header.SetContentLength(-1)
+
+ // Do not care about memory allocations here, since flate is slow
+ // and allocates a lot of memory by itself.
+ bs := resp.bodyStream
+ resp.bodyStream = NewStreamReader(func(sw *bufio.Writer) {
+ zw := acquireStacklessDeflateWriter(sw, level)
+ fw := &flushWriter{
+ wf: zw,
+ bw: sw,
+ }
+ copyZeroAlloc(fw, bs) //nolint:errcheck
+ releaseStacklessDeflateWriter(zw, level)
+ if bsc, ok := bs.(io.Closer); ok {
+ bsc.Close()
+ }
+ })
+ } else {
+ bodyBytes := resp.bodyBytes()
+ if len(bodyBytes) < minCompressLen {
+ // There is no sense in spending CPU time on small body compression,
+ // since there is a very high probability that the compressed
+ // body size will be bigger than the original body size.
+ return nil
+ }
+ w := responseBodyPool.Get()
+ w.B = AppendDeflateBytesLevel(w.B, bodyBytes, level)
+
+ // Hack: swap resp.body with w.
+ if resp.body != nil {
+ responseBodyPool.Put(resp.body)
+ }
+ resp.body = w
+ resp.bodyRaw = nil
+ }
+ resp.Header.SetContentEncodingBytes(strDeflate)
+ resp.Header.addVaryBytes(strAcceptEncoding)
+ return nil
+}
+
+// Bodies with sizes smaller than minCompressLen aren't compressed at all
+const minCompressLen = 200
+
+type writeFlusher interface {
+ io.Writer
+ Flush() error
+}
+
+type flushWriter struct {
+ wf writeFlusher
+ bw *bufio.Writer
+}
+
+func (w *flushWriter) Write(p []byte) (int, error) {
+ n, err := w.wf.Write(p)
+ if err != nil {
+ return 0, err
+ }
+ if err = w.wf.Flush(); err != nil {
+ return 0, err
+ }
+ if err = w.bw.Flush(); err != nil {
+ return 0, err
+ }
+ return n, nil
+}
+
+// Write writes response to w.
+//
+// Write doesn't flush response to w for performance reasons.
+//
+// See also WriteTo.
+func (resp *Response) Write(w *bufio.Writer) error {
+ sendBody := !resp.mustSkipBody()
+
+ if resp.bodyStream != nil {
+ return resp.writeBodyStream(w, sendBody)
+ }
+
+ body := resp.bodyBytes()
+ bodyLen := len(body)
+ if sendBody || bodyLen > 0 {
+ resp.Header.SetContentLength(bodyLen)
+ }
+ if err := resp.Header.Write(w); err != nil {
+ return err
+ }
+ if sendBody {
+ if _, err := w.Write(body); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func (req *Request) writeBodyStream(w *bufio.Writer) error {
+ var err error
+
+ contentLength := req.Header.ContentLength()
+ if contentLength < 0 {
+ lrSize := limitedReaderSize(req.bodyStream)
+ if lrSize >= 0 {
+ contentLength = int(lrSize)
+ if int64(contentLength) != lrSize {
+ contentLength = -1
+ }
+ if contentLength >= 0 {
+ req.Header.SetContentLength(contentLength)
+ }
+ }
+ }
+ if contentLength >= 0 {
+ if err = req.Header.Write(w); err == nil {
+ err = writeBodyFixedSize(w, req.bodyStream, int64(contentLength))
+ }
+ } else {
+ req.Header.SetContentLength(-1)
+ err = req.Header.Write(w)
+ if err == nil {
+ err = writeBodyChunked(w, req.bodyStream)
+ }
+ if err == nil {
+ err = req.Header.writeTrailer(w)
+ }
+ }
+ err1 := req.closeBodyStream()
+ if err == nil {
+ err = err1
+ }
+ return err
+}
+
+// ErrBodyStreamWritePanic is returned when panic happens during writing body stream.
+type ErrBodyStreamWritePanic struct {
+ error
+}
+
+func (resp *Response) writeBodyStream(w *bufio.Writer, sendBody bool) (err error) {
+ defer func() {
+ if r := recover(); r != nil {
+ err = &ErrBodyStreamWritePanic{
+ error: fmt.Errorf("panic while writing body stream: %+v", r),
+ }
+ }
+ }()
+
+ contentLength := resp.Header.ContentLength()
+ if contentLength < 0 {
+ lrSize := limitedReaderSize(resp.bodyStream)
+ if lrSize >= 0 {
+ contentLength = int(lrSize)
+ if int64(contentLength) != lrSize {
+ contentLength = -1
+ }
+ if contentLength >= 0 {
+ resp.Header.SetContentLength(contentLength)
+ }
+ }
+ }
+ if contentLength >= 0 {
+ if err = resp.Header.Write(w); err == nil {
+ if resp.ImmediateHeaderFlush {
+ err = w.Flush()
+ }
+ if err == nil && sendBody {
+ err = writeBodyFixedSize(w, resp.bodyStream, int64(contentLength))
+ }
+ }
+ } else {
+ resp.Header.SetContentLength(-1)
+ if err = resp.Header.Write(w); err == nil {
+ if resp.ImmediateHeaderFlush {
+ err = w.Flush()
+ }
+ if err == nil && sendBody {
+ err = writeBodyChunked(w, resp.bodyStream)
+ }
+ if err == nil {
+ err = resp.Header.writeTrailer(w)
+ }
+ }
+ }
+ err1 := resp.closeBodyStream()
+ if err == nil {
+ err = err1
+ }
+ return err
+}
+
+func (req *Request) closeBodyStream() error {
+ if req.bodyStream == nil {
+ return nil
+ }
+ var err error
+ if bsc, ok := req.bodyStream.(io.Closer); ok {
+ err = bsc.Close()
+ }
+ if rs, ok := req.bodyStream.(*requestStream); ok {
+ releaseRequestStream(rs)
+ }
+ req.bodyStream = nil
+ return err
+}
+
+func (resp *Response) closeBodyStream() error {
+ if resp.bodyStream == nil {
+ return nil
+ }
+ var err error
+ if bsc, ok := resp.bodyStream.(io.Closer); ok {
+ err = bsc.Close()
+ }
+ if bsr, ok := resp.bodyStream.(*requestStream); ok {
+ releaseRequestStream(bsr)
+ }
+ resp.bodyStream = nil
+ return err
+}
+
+// String returns request representation.
+//
+// Returns error message instead of request representation on error.
+//
+// Use Write instead of String for performance-critical code.
+func (req *Request) String() string {
+ return getHTTPString(req)
+}
+
+// String returns response representation.
+//
+// Returns error message instead of response representation on error.
+//
+// Use Write instead of String for performance-critical code.
+func (resp *Response) String() string {
+ return getHTTPString(resp)
+}
+
+func getHTTPString(hw httpWriter) string {
+ w := bytebufferpool.Get()
+ defer bytebufferpool.Put(w)
+
+ bw := bufio.NewWriter(w)
+ if err := hw.Write(bw); err != nil {
+ return err.Error()
+ }
+ if err := bw.Flush(); err != nil {
+ return err.Error()
+ }
+ s := string(w.B)
+ return s
+}
+
+type httpWriter interface {
+ Write(w *bufio.Writer) error
+}
+
+func writeBodyChunked(w *bufio.Writer, r io.Reader) error {
+ vbuf := copyBufPool.Get()
+ buf := vbuf.([]byte)
+
+ var err error
+ var n int
+ for {
+ n, err = r.Read(buf)
+ if n == 0 {
+ if err == nil {
+ continue
+ }
+ if err == io.EOF {
+ if err = writeChunk(w, buf[:0]); err != nil {
+ break
+ }
+ err = nil
+ }
+ break
+ }
+ if err = writeChunk(w, buf[:n]); err != nil {
+ break
+ }
+ }
+
+ copyBufPool.Put(vbuf)
+ return err
+}
+
+func limitedReaderSize(r io.Reader) int64 {
+ lr, ok := r.(*io.LimitedReader)
+ if !ok {
+ return -1
+ }
+ return lr.N
+}
+
+func writeBodyFixedSize(w *bufio.Writer, r io.Reader, size int64) error {
+ if size > maxSmallFileSize {
+ // w buffer must be empty for triggering
+ // sendfile path in bufio.Writer.ReadFrom.
+ if err := w.Flush(); err != nil {
+ return err
+ }
+ }
+
+ n, err := copyZeroAlloc(w, r)
+
+ if n != size && err == nil {
+ err = fmt.Errorf("copied %d bytes from body stream instead of %d bytes", n, size)
+ }
+ return err
+}
+
+func copyZeroAlloc(w io.Writer, r io.Reader) (int64, error) {
+ vbuf := copyBufPool.Get()
+ buf := vbuf.([]byte)
+ n, err := io.CopyBuffer(w, r, buf)
+ copyBufPool.Put(vbuf)
+ return n, err
+}
+
+var copyBufPool = sync.Pool{
+ New: func() interface{} {
+ return make([]byte, 4096)
+ },
+}
+
+func writeChunk(w *bufio.Writer, b []byte) error {
+ n := len(b)
+ if err := writeHexInt(w, n); err != nil {
+ return err
+ }
+ if _, err := w.Write(strCRLF); err != nil {
+ return err
+ }
+ if _, err := w.Write(b); err != nil {
+ return err
+ }
+ // If is end chunk, write CRLF after writing trailer
+ if n > 0 {
+ if _, err := w.Write(strCRLF); err != nil {
+ return err
+ }
+ }
+ return w.Flush()
+}
+
+// ErrBodyTooLarge is returned if either request or response body exceeds
+// the given limit.
+var ErrBodyTooLarge = errors.New("body size exceeds the given limit")
+
+func readBody(r *bufio.Reader, contentLength int, maxBodySize int, dst []byte) ([]byte, error) {
+ if maxBodySize > 0 && contentLength > maxBodySize {
+ return dst, ErrBodyTooLarge
+ }
+ return appendBodyFixedSize(r, dst, contentLength)
+}
+
+var errChunkedStream = errors.New("chunked stream")
+
+func readBodyWithStreaming(r *bufio.Reader, contentLength int, maxBodySize int, dst []byte) (b []byte, err error) {
+ if contentLength == -1 {
+ // handled in requestStream.Read()
+ return b, errChunkedStream
+ }
+
+ dst = dst[:0]
+
+ readN := maxBodySize
+ if readN > contentLength {
+ readN = contentLength
+ }
+ if readN > 8*1024 {
+ readN = 8 * 1024
+ }
+
+ if contentLength >= 0 && maxBodySize >= contentLength {
+ b, err = appendBodyFixedSize(r, dst, readN)
+ } else {
+ b, err = readBodyIdentity(r, readN, dst)
+ }
+
+ if err != nil {
+ return b, err
+ }
+ if contentLength > maxBodySize {
+ return b, ErrBodyTooLarge
+ }
+ return b, nil
+}
+
+func readBodyIdentity(r *bufio.Reader, maxBodySize int, dst []byte) ([]byte, error) {
+ dst = dst[:cap(dst)]
+ if len(dst) == 0 {
+ dst = make([]byte, 1024)
+ }
+ offset := 0
+ for {
+ nn, err := r.Read(dst[offset:])
+ if nn <= 0 {
+ switch {
+ case errors.Is(err, io.EOF):
+ return dst[:offset], nil
+ case err != nil:
+ return dst[:offset], err
+ default:
+ return dst[:offset], fmt.Errorf("bufio.Read() returned (%d, nil)", nn)
+ }
+ }
+ offset += nn
+ if maxBodySize > 0 && offset > maxBodySize {
+ return dst[:offset], ErrBodyTooLarge
+ }
+ if len(dst) == offset {
+ n := roundUpForSliceCap(2 * offset)
+ if maxBodySize > 0 && n > maxBodySize {
+ n = maxBodySize + 1
+ }
+ b := make([]byte, n)
+ copy(b, dst)
+ dst = b
+ }
+ }
+}
+
+func appendBodyFixedSize(r *bufio.Reader, dst []byte, n int) ([]byte, error) {
+ if n == 0 {
+ return dst, nil
+ }
+
+ offset := len(dst)
+ dstLen := offset + n
+ if cap(dst) < dstLen {
+ b := make([]byte, roundUpForSliceCap(dstLen))
+ copy(b, dst)
+ dst = b
+ }
+ dst = dst[:dstLen]
+
+ for {
+ nn, err := r.Read(dst[offset:])
+ if nn <= 0 {
+ switch {
+ case errors.Is(err, io.EOF):
+ return dst[:offset], io.ErrUnexpectedEOF
+ case err != nil:
+ return dst[:offset], err
+ default:
+ return dst[:offset], fmt.Errorf("bufio.Read() returned (%d, nil)", nn)
+ }
+ }
+ offset += nn
+ if offset == dstLen {
+ return dst, nil
+ }
+ }
+}
+
+// ErrBrokenChunk is returned when server receives a broken chunked body (Transfer-Encoding: chunked).
+type ErrBrokenChunk struct {
+ error
+}
+
+func readBodyChunked(r *bufio.Reader, maxBodySize int, dst []byte) ([]byte, error) {
+ if len(dst) > 0 {
+ // data integrity might be in danger. No idea what we received,
+ // but nothing we should write to.
+ panic("BUG: expected zero-length buffer")
+ }
+
+ strCRLFLen := len(strCRLF)
+ for {
+ chunkSize, err := parseChunkSize(r)
+ if err != nil {
+ return dst, err
+ }
+ if chunkSize == 0 {
+ return dst, err
+ }
+ if maxBodySize > 0 && len(dst)+chunkSize > maxBodySize {
+ return dst, ErrBodyTooLarge
+ }
+ dst, err = appendBodyFixedSize(r, dst, chunkSize+strCRLFLen)
+ if err != nil {
+ return dst, err
+ }
+ if !bytes.Equal(dst[len(dst)-strCRLFLen:], strCRLF) {
+ return dst, ErrBrokenChunk{
+ error: fmt.Errorf("cannot find crlf at the end of chunk"),
+ }
+ }
+ dst = dst[:len(dst)-strCRLFLen]
+ }
+}
+
+func parseChunkSize(r *bufio.Reader) (int, error) {
+ n, err := readHexInt(r)
+ if err != nil {
+ return -1, err
+ }
+ for {
+ c, err := r.ReadByte()
+ if err != nil {
+ return -1, ErrBrokenChunk{
+ error: fmt.Errorf("cannot read '\r' char at the end of chunk size: %w", err),
+ }
+ }
+ // Skip chunk extension after chunk size.
+ // Add support later if anyone needs it.
+ if c != '\r' {
+ continue
+ }
+ if err := r.UnreadByte(); err != nil {
+ return -1, ErrBrokenChunk{
+ error: fmt.Errorf("cannot unread '\r' char at the end of chunk size: %w", err),
+ }
+ }
+ break
+ }
+ err = readCrLf(r)
+ if err != nil {
+ return -1, err
+ }
+ return n, nil
+}
+
+func readCrLf(r *bufio.Reader) error {
+ for _, exp := range []byte{'\r', '\n'} {
+ c, err := r.ReadByte()
+ if err != nil {
+ return ErrBrokenChunk{
+ error: fmt.Errorf("cannot read %q char at the end of chunk size: %w", exp, err),
+ }
+ }
+ if c != exp {
+ return ErrBrokenChunk{
+ error: fmt.Errorf("unexpected char %q at the end of chunk size. Expected %q", c, exp),
+ }
+ }
+ }
+ return nil
+}
+
+// SetTimeout sets timeout for the request.
+//
+// req.SetTimeout(t); c.Do(&req, &resp) is equivalent to
+// c.DoTimeout(&req, &resp, t)
+func (req *Request) SetTimeout(t time.Duration) {
+ req.timeout = t
+}
diff --git a/vendor/github.com/valyala/fasthttp/lbclient.go b/vendor/github.com/valyala/fasthttp/lbclient.go
new file mode 100644
index 0000000..7fd8a93
--- /dev/null
+++ b/vendor/github.com/valyala/fasthttp/lbclient.go
@@ -0,0 +1,203 @@
+package fasthttp
+
+import (
+ "sync"
+ "sync/atomic"
+ "time"
+)
+
+// BalancingClient is the interface for clients, which may be passed
+// to LBClient.Clients.
+type BalancingClient interface {
+ DoDeadline(req *Request, resp *Response, deadline time.Time) error
+ PendingRequests() int
+}
+
+// LBClient balances requests among available LBClient.Clients.
+//
+// It has the following features:
+//
+// - Balances load among available clients using 'least loaded' + 'least total'
+// hybrid technique.
+// - Dynamically decreases load on unhealthy clients.
+//
+// It is forbidden copying LBClient instances. Create new instances instead.
+//
+// It is safe calling LBClient methods from concurrently running goroutines.
+type LBClient struct {
+ noCopy noCopy
+
+ // Clients must contain non-zero clients list.
+ // Incoming requests are balanced among these clients.
+ Clients []BalancingClient
+
+ // HealthCheck is a callback called after each request.
+ //
+ // The request, response and the error returned by the client
+ // is passed to HealthCheck, so the callback may determine whether
+ // the client is healthy.
+ //
+ // Load on the current client is decreased if HealthCheck returns false.
+ //
+ // By default HealthCheck returns false if err != nil.
+ HealthCheck func(req *Request, resp *Response, err error) bool
+
+ // Timeout is the request timeout used when calling LBClient.Do.
+ //
+ // DefaultLBClientTimeout is used by default.
+ Timeout time.Duration
+
+ cs []*lbClient
+
+ once sync.Once
+ mu sync.RWMutex
+}
+
+// DefaultLBClientTimeout is the default request timeout used by LBClient
+// when calling LBClient.Do.
+//
+// The timeout may be overridden via LBClient.Timeout.
+const DefaultLBClientTimeout = time.Second
+
+// DoDeadline calls DoDeadline on the least loaded client
+func (cc *LBClient) DoDeadline(req *Request, resp *Response, deadline time.Time) error {
+ return cc.get().DoDeadline(req, resp, deadline)
+}
+
+// DoTimeout calculates deadline and calls DoDeadline on the least loaded client
+func (cc *LBClient) DoTimeout(req *Request, resp *Response, timeout time.Duration) error {
+ deadline := time.Now().Add(timeout)
+ return cc.get().DoDeadline(req, resp, deadline)
+}
+
+// Do calculates timeout using LBClient.Timeout and calls DoTimeout
+// on the least loaded client.
+func (cc *LBClient) Do(req *Request, resp *Response) error {
+ timeout := cc.Timeout
+ if timeout <= 0 {
+ timeout = DefaultLBClientTimeout
+ }
+ return cc.DoTimeout(req, resp, timeout)
+}
+
+func (cc *LBClient) init() {
+ cc.mu.Lock()
+ defer cc.mu.Unlock()
+ if len(cc.Clients) == 0 {
+ // developer sanity-check
+ panic("BUG: LBClient.Clients cannot be empty")
+ }
+ for _, c := range cc.Clients {
+ cc.cs = append(cc.cs, &lbClient{
+ c: c,
+ healthCheck: cc.HealthCheck,
+ })
+ }
+}
+
+// AddClient adds a new client to the balanced clients
+// returns the new total number of clients
+func (cc *LBClient) AddClient(c BalancingClient) int {
+ cc.mu.Lock()
+ cc.cs = append(cc.cs, &lbClient{
+ c: c,
+ healthCheck: cc.HealthCheck,
+ })
+ cc.mu.Unlock()
+ return len(cc.cs)
+}
+
+// RemoveClients removes clients using the provided callback
+// if rc returns true, the passed client will be removed
+// returns the new total number of clients
+func (cc *LBClient) RemoveClients(rc func(BalancingClient) bool) int {
+ cc.mu.Lock()
+ n := 0
+ for idx, cs := range cc.cs {
+ cc.cs[idx] = nil
+ if rc(cs.c) {
+ continue
+ }
+ cc.cs[n] = cs
+ n++
+ }
+ cc.cs = cc.cs[:n]
+
+ cc.mu.Unlock()
+ return len(cc.cs)
+}
+
+func (cc *LBClient) get() *lbClient {
+ cc.once.Do(cc.init)
+
+ cc.mu.RLock()
+ cs := cc.cs
+
+ minC := cs[0]
+ minN := minC.PendingRequests()
+ minT := atomic.LoadUint64(&minC.total)
+ for _, c := range cs[1:] {
+ n := c.PendingRequests()
+ t := atomic.LoadUint64(&c.total) /* #nosec G601 */
+ if n < minN || (n == minN && t < minT) {
+ minC = c
+ minN = n
+ minT = t
+ }
+ }
+ cc.mu.RUnlock()
+ return minC
+}
+
+type lbClient struct {
+ c BalancingClient
+ healthCheck func(req *Request, resp *Response, err error) bool
+ penalty uint32
+
+ // total amount of requests handled.
+ total uint64
+}
+
+func (c *lbClient) DoDeadline(req *Request, resp *Response, deadline time.Time) error {
+ err := c.c.DoDeadline(req, resp, deadline)
+ if !c.isHealthy(req, resp, err) && c.incPenalty() {
+ // Penalize the client returning error, so the next requests
+ // are routed to another clients.
+ time.AfterFunc(penaltyDuration, c.decPenalty)
+ } else {
+ atomic.AddUint64(&c.total, 1)
+ }
+ return err
+}
+
+func (c *lbClient) PendingRequests() int {
+ n := c.c.PendingRequests()
+ m := atomic.LoadUint32(&c.penalty)
+ return n + int(m)
+}
+
+func (c *lbClient) isHealthy(req *Request, resp *Response, err error) bool {
+ if c.healthCheck == nil {
+ return err == nil
+ }
+ return c.healthCheck(req, resp, err)
+}
+
+func (c *lbClient) incPenalty() bool {
+ m := atomic.AddUint32(&c.penalty, 1)
+ if m > maxPenalty {
+ c.decPenalty()
+ return false
+ }
+ return true
+}
+
+func (c *lbClient) decPenalty() {
+ atomic.AddUint32(&c.penalty, ^uint32(0))
+}
+
+const (
+ maxPenalty = 300
+
+ penaltyDuration = 3 * time.Second
+)
diff --git a/vendor/github.com/valyala/fasthttp/methods.go b/vendor/github.com/valyala/fasthttp/methods.go
new file mode 100644
index 0000000..a614584
--- /dev/null
+++ b/vendor/github.com/valyala/fasthttp/methods.go
@@ -0,0 +1,14 @@
+package fasthttp
+
+// HTTP methods were copied from net/http.
+const (
+ MethodGet = "GET" // RFC 7231, 4.3.1
+ MethodHead = "HEAD" // RFC 7231, 4.3.2
+ MethodPost = "POST" // RFC 7231, 4.3.3
+ MethodPut = "PUT" // RFC 7231, 4.3.4
+ MethodPatch = "PATCH" // RFC 5789
+ MethodDelete = "DELETE" // RFC 7231, 4.3.5
+ MethodConnect = "CONNECT" // RFC 7231, 4.3.6
+ MethodOptions = "OPTIONS" // RFC 7231, 4.3.7
+ MethodTrace = "TRACE" // RFC 7231, 4.3.8
+)
diff --git a/vendor/github.com/valyala/fasthttp/nocopy.go b/vendor/github.com/valyala/fasthttp/nocopy.go
new file mode 100644
index 0000000..8e9b89a
--- /dev/null
+++ b/vendor/github.com/valyala/fasthttp/nocopy.go
@@ -0,0 +1,11 @@
+package fasthttp
+
+// Embed this type into a struct, which mustn't be copied,
+// so `go vet` gives a warning if this struct is copied.
+//
+// See https://github.com/golang/go/issues/8005#issuecomment-190753527 for details.
+// and also: https://stackoverflow.com/questions/52494458/nocopy-minimal-example
+type noCopy struct{}
+
+func (*noCopy) Lock() {}
+func (*noCopy) Unlock() {}
diff --git a/vendor/github.com/valyala/fasthttp/peripconn.go b/vendor/github.com/valyala/fasthttp/peripconn.go
new file mode 100644
index 0000000..123c55e
--- /dev/null
+++ b/vendor/github.com/valyala/fasthttp/peripconn.go
@@ -0,0 +1,100 @@
+package fasthttp
+
+import (
+ "net"
+ "sync"
+)
+
+type perIPConnCounter struct {
+ pool sync.Pool
+ lock sync.Mutex
+ m map[uint32]int
+}
+
+func (cc *perIPConnCounter) Register(ip uint32) int {
+ cc.lock.Lock()
+ if cc.m == nil {
+ cc.m = make(map[uint32]int)
+ }
+ n := cc.m[ip] + 1
+ cc.m[ip] = n
+ cc.lock.Unlock()
+ return n
+}
+
+func (cc *perIPConnCounter) Unregister(ip uint32) {
+ cc.lock.Lock()
+ defer cc.lock.Unlock()
+ if cc.m == nil {
+ // developer safeguard
+ panic("BUG: perIPConnCounter.Register() wasn't called")
+ }
+ n := cc.m[ip] - 1
+ if n < 0 {
+ n = 0
+ }
+ cc.m[ip] = n
+}
+
+type perIPConn struct {
+ net.Conn
+
+ ip uint32
+ perIPConnCounter *perIPConnCounter
+}
+
+func acquirePerIPConn(conn net.Conn, ip uint32, counter *perIPConnCounter) *perIPConn {
+ v := counter.pool.Get()
+ if v == nil {
+ return &perIPConn{
+ perIPConnCounter: counter,
+ Conn: conn,
+ ip: ip,
+ }
+ }
+ c := v.(*perIPConn)
+ c.Conn = conn
+ c.ip = ip
+ return c
+}
+
+func releasePerIPConn(c *perIPConn) {
+ c.Conn = nil
+ c.perIPConnCounter.pool.Put(c)
+}
+
+func (c *perIPConn) Close() error {
+ err := c.Conn.Close()
+ c.perIPConnCounter.Unregister(c.ip)
+ releasePerIPConn(c)
+ return err
+}
+
+func getUint32IP(c net.Conn) uint32 {
+ return ip2uint32(getConnIP4(c))
+}
+
+func getConnIP4(c net.Conn) net.IP {
+ addr := c.RemoteAddr()
+ ipAddr, ok := addr.(*net.TCPAddr)
+ if !ok {
+ return net.IPv4zero
+ }
+ return ipAddr.IP.To4()
+}
+
+func ip2uint32(ip net.IP) uint32 {
+ if len(ip) != 4 {
+ return 0
+ }
+ return uint32(ip[0])<<24 | uint32(ip[1])<<16 | uint32(ip[2])<<8 | uint32(ip[3])
+}
+
+func uint322ip(ip uint32) net.IP {
+ b := make([]byte, 4)
+ b[0] = byte(ip >> 24)
+ b[1] = byte(ip >> 16)
+ b[2] = byte(ip >> 8)
+ b[3] = byte(ip)
+ return b
+}
diff --git a/vendor/github.com/valyala/fasthttp/round2_32.go b/vendor/github.com/valyala/fasthttp/round2_32.go
new file mode 100644
index 0000000..f7276fc
--- /dev/null
+++ b/vendor/github.com/valyala/fasthttp/round2_32.go
@@ -0,0 +1,30 @@
+//go:build !amd64 && !arm64 && !ppc64 && !ppc64le && !s390x
+
+package fasthttp
+
+import "math"
+
+func roundUpForSliceCap(n int) int {
+ if n <= 0 {
+ return 0
+ }
+
+ // Above 100MB, we don't round up as the overhead is too large.
+ if n > 100*1024*1024 {
+ return n
+ }
+
+ x := uint32(n - 1)
+ x |= x >> 1
+ x |= x >> 2
+ x |= x >> 4
+ x |= x >> 8
+ x |= x >> 16
+
+ // Make sure we don't return 0 due to overflow, even on 32 bit systems
+ if x >= uint32(math.MaxInt32) {
+ return math.MaxInt32
+ }
+
+ return int(x + 1)
+}
diff --git a/vendor/github.com/valyala/fasthttp/round2_64.go b/vendor/github.com/valyala/fasthttp/round2_64.go
new file mode 100644
index 0000000..e74368c
--- /dev/null
+++ b/vendor/github.com/valyala/fasthttp/round2_64.go
@@ -0,0 +1,23 @@
+//go:build amd64 || arm64 || ppc64 || ppc64le || s390x
+
+package fasthttp
+
+func roundUpForSliceCap(n int) int {
+ if n <= 0 {
+ return 0
+ }
+
+ // Above 100MB, we don't round up as the overhead is too large.
+ if n > 100*1024*1024 {
+ return n
+ }
+
+ x := uint64(n - 1)
+ x |= x >> 1
+ x |= x >> 2
+ x |= x >> 4
+ x |= x >> 8
+ x |= x >> 16
+
+ return int(x + 1)
+}
diff --git a/vendor/github.com/valyala/fasthttp/s2b_new.go b/vendor/github.com/valyala/fasthttp/s2b_new.go
new file mode 100644
index 0000000..aedc448
--- /dev/null
+++ b/vendor/github.com/valyala/fasthttp/s2b_new.go
@@ -0,0 +1,10 @@
+//go:build go1.20
+
+package fasthttp
+
+import "unsafe"
+
+// s2b converts string to a byte slice without memory allocation.
+func s2b(s string) []byte {
+ return unsafe.Slice(unsafe.StringData(s), len(s))
+}
diff --git a/vendor/github.com/valyala/fasthttp/s2b_old.go b/vendor/github.com/valyala/fasthttp/s2b_old.go
new file mode 100644
index 0000000..50a034b
--- /dev/null
+++ b/vendor/github.com/valyala/fasthttp/s2b_old.go
@@ -0,0 +1,21 @@
+//go:build !go1.20
+
+package fasthttp
+
+import (
+ "reflect"
+ "unsafe"
+)
+
+// s2b converts string to a byte slice without memory allocation.
+//
+// Note it may break if string and/or slice header will change
+// in the future go versions.
+func s2b(s string) (b []byte) {
+ bh := (*reflect.SliceHeader)(unsafe.Pointer(&b))
+ sh := (*reflect.StringHeader)(unsafe.Pointer(&s))
+ bh.Data = sh.Data
+ bh.Cap = sh.Len
+ bh.Len = sh.Len
+ return b
+}
diff --git a/vendor/github.com/valyala/fasthttp/server.go b/vendor/github.com/valyala/fasthttp/server.go
new file mode 100644
index 0000000..9cfc175
--- /dev/null
+++ b/vendor/github.com/valyala/fasthttp/server.go
@@ -0,0 +1,2951 @@
+package fasthttp
+
+import (
+ "bufio"
+ "context"
+ "crypto/tls"
+ "errors"
+ "fmt"
+ "io"
+ "log"
+ "mime/multipart"
+ "net"
+ "os"
+ "strings"
+ "sync"
+ "sync/atomic"
+ "time"
+)
+
+var errNoCertOrKeyProvided = errors.New("cert or key has not provided")
+
+// Deprecated: ErrAlreadyServing is never returned from Serve. See issue #633.
+var ErrAlreadyServing = errors.New("Server is already serving connections")
+
+// ServeConn serves HTTP requests from the given connection
+// using the given handler.
+//
+// ServeConn returns nil if all requests from the c are successfully served.
+// It returns non-nil error otherwise.
+//
+// Connection c must immediately propagate all the data passed to Write()
+// to the client. Otherwise requests' processing may hang.
+//
+// ServeConn closes c before returning.
+func ServeConn(c net.Conn, handler RequestHandler) error {
+ v := serverPool.Get()
+ if v == nil {
+ v = &Server{}
+ }
+ s := v.(*Server)
+ s.Handler = handler
+ err := s.ServeConn(c)
+ s.Handler = nil
+ serverPool.Put(v)
+ return err
+}
+
+var serverPool sync.Pool
+
+// Serve serves incoming connections from the given listener
+// using the given handler.
+//
+// Serve blocks until the given listener returns permanent error.
+func Serve(ln net.Listener, handler RequestHandler) error {
+ s := &Server{
+ Handler: handler,
+ }
+ return s.Serve(ln)
+}
+
+// ServeTLS serves HTTPS requests from the given net.Listener
+// using the given handler.
+//
+// certFile and keyFile are paths to TLS certificate and key files.
+func ServeTLS(ln net.Listener, certFile, keyFile string, handler RequestHandler) error {
+ s := &Server{
+ Handler: handler,
+ }
+ return s.ServeTLS(ln, certFile, keyFile)
+}
+
+// ServeTLSEmbed serves HTTPS requests from the given net.Listener
+// using the given handler.
+//
+// certData and keyData must contain valid TLS certificate and key data.
+func ServeTLSEmbed(ln net.Listener, certData, keyData []byte, handler RequestHandler) error {
+ s := &Server{
+ Handler: handler,
+ }
+ return s.ServeTLSEmbed(ln, certData, keyData)
+}
+
+// ListenAndServe serves HTTP requests from the given TCP addr
+// using the given handler.
+func ListenAndServe(addr string, handler RequestHandler) error {
+ s := &Server{
+ Handler: handler,
+ }
+ return s.ListenAndServe(addr)
+}
+
+// ListenAndServeUNIX serves HTTP requests from the given UNIX addr
+// using the given handler.
+//
+// The function deletes existing file at addr before starting serving.
+//
+// The server sets the given file mode for the UNIX addr.
+func ListenAndServeUNIX(addr string, mode os.FileMode, handler RequestHandler) error {
+ s := &Server{
+ Handler: handler,
+ }
+ return s.ListenAndServeUNIX(addr, mode)
+}
+
+// ListenAndServeTLS serves HTTPS requests from the given TCP addr
+// using the given handler.
+//
+// certFile and keyFile are paths to TLS certificate and key files.
+func ListenAndServeTLS(addr, certFile, keyFile string, handler RequestHandler) error {
+ s := &Server{
+ Handler: handler,
+ }
+ return s.ListenAndServeTLS(addr, certFile, keyFile)
+}
+
+// ListenAndServeTLSEmbed serves HTTPS requests from the given TCP addr
+// using the given handler.
+//
+// certData and keyData must contain valid TLS certificate and key data.
+func ListenAndServeTLSEmbed(addr string, certData, keyData []byte, handler RequestHandler) error {
+ s := &Server{
+ Handler: handler,
+ }
+ return s.ListenAndServeTLSEmbed(addr, certData, keyData)
+}
+
+// RequestHandler must process incoming requests.
+//
+// RequestHandler must call ctx.TimeoutError() before returning
+// if it keeps references to ctx and/or its members after the return.
+// Consider wrapping RequestHandler into TimeoutHandler if response time
+// must be limited.
+type RequestHandler func(ctx *RequestCtx)
+
+// ServeHandler must process tls.Config.NextProto negotiated requests.
+type ServeHandler func(c net.Conn) error
+
+// Server implements HTTP server.
+//
+// Default Server settings should satisfy the majority of Server users.
+// Adjust Server settings only if you really understand the consequences.
+//
+// It is forbidden copying Server instances. Create new Server instances
+// instead.
+//
+// It is safe to call Server methods from concurrently running goroutines.
+type Server struct {
+ noCopy noCopy
+
+ // Handler for processing incoming requests.
+ //
+ // Take into account that no `panic` recovery is done by `fasthttp` (thus any `panic` will take down the entire server).
+ // Instead the user should use `recover` to handle these situations.
+ Handler RequestHandler
+
+ // ErrorHandler for returning a response in case of an error while receiving or parsing the request.
+ //
+ // The following is a non-exhaustive list of errors that can be expected as argument:
+ // * io.EOF
+ // * io.ErrUnexpectedEOF
+ // * ErrGetOnly
+ // * ErrSmallBuffer
+ // * ErrBodyTooLarge
+ // * ErrBrokenChunks
+ ErrorHandler func(ctx *RequestCtx, err error)
+
+ // HeaderReceived is called after receiving the header
+ //
+ // non zero RequestConfig field values will overwrite the default configs
+ HeaderReceived func(header *RequestHeader) RequestConfig
+
+ // ContinueHandler is called after receiving the Expect 100 Continue Header
+ //
+ // https://www.w3.org/Protocols/rfc2616/rfc2616-sec8.html#sec8.2.3
+ // https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.1.1
+ // Using ContinueHandler a server can make decisioning on whether or not
+ // to read a potentially large request body based on the headers
+ //
+ // The default is to automatically read request bodies of Expect 100 Continue requests
+ // like they are normal requests
+ ContinueHandler func(header *RequestHeader) bool
+
+ // Server name for sending in response headers.
+ //
+ // Default server name is used if left blank.
+ Name string
+
+ // The maximum number of concurrent connections the server may serve.
+ //
+ // DefaultConcurrency is used if not set.
+ //
+ // Concurrency only works if you either call Serve once, or only ServeConn multiple times.
+ // It works with ListenAndServe as well.
+ Concurrency int
+
+ // Per-connection buffer size for requests' reading.
+ // This also limits the maximum header size.
+ //
+ // Increase this buffer if your clients send multi-KB RequestURIs
+ // and/or multi-KB headers (for example, BIG cookies).
+ //
+ // Default buffer size is used if not set.
+ ReadBufferSize int
+
+ // Per-connection buffer size for responses' writing.
+ //
+ // Default buffer size is used if not set.
+ WriteBufferSize int
+
+ // ReadTimeout is the amount of time allowed to read
+ // the full request including body. The connection's read
+ // deadline is reset when the connection opens, or for
+ // keep-alive connections after the first byte has been read.
+ //
+ // By default request read timeout is unlimited.
+ ReadTimeout time.Duration
+
+ // WriteTimeout is the maximum duration before timing out
+ // writes of the response. It is reset after the request handler
+ // has returned.
+ //
+ // By default response write timeout is unlimited.
+ WriteTimeout time.Duration
+
+ // IdleTimeout is the maximum amount of time to wait for the
+ // next request when keep-alive is enabled. If IdleTimeout
+ // is zero, the value of ReadTimeout is used.
+ IdleTimeout time.Duration
+
+ // Maximum number of concurrent client connections allowed per IP.
+ //
+ // By default unlimited number of concurrent connections
+ // may be established to the server from a single IP address.
+ MaxConnsPerIP int
+
+ // Maximum number of requests served per connection.
+ //
+ // The server closes connection after the last request.
+ // 'Connection: close' header is added to the last response.
+ //
+ // By default unlimited number of requests may be served per connection.
+ MaxRequestsPerConn int
+
+ // MaxKeepaliveDuration is a no-op and only left here for backwards compatibility.
+ // Deprecated: Use IdleTimeout instead.
+ MaxKeepaliveDuration time.Duration
+
+ // MaxIdleWorkerDuration is the maximum idle time of a single worker in the underlying
+ // worker pool of the Server. Idle workers beyond this time will be cleared.
+ MaxIdleWorkerDuration time.Duration
+
+ // Period between tcp keep-alive messages.
+ //
+ // TCP keep-alive period is determined by operation system by default.
+ TCPKeepalivePeriod time.Duration
+
+ // Maximum request body size.
+ //
+ // The server rejects requests with bodies exceeding this limit.
+ //
+ // Request body size is limited by DefaultMaxRequestBodySize by default.
+ MaxRequestBodySize int
+
+ // Whether to disable keep-alive connections.
+ //
+ // The server will close all the incoming connections after sending
+ // the first response to client if this option is set to true.
+ //
+ // By default keep-alive connections are enabled.
+ DisableKeepalive bool
+
+ // Whether to enable tcp keep-alive connections.
+ //
+ // Whether the operating system should send tcp keep-alive messages on the tcp connection.
+ //
+ // By default tcp keep-alive connections are disabled.
+ TCPKeepalive bool
+
+ // Aggressively reduces memory usage at the cost of higher CPU usage
+ // if set to true.
+ //
+ // Try enabling this option only if the server consumes too much memory
+ // serving mostly idle keep-alive connections. This may reduce memory
+ // usage by more than 50%.
+ //
+ // Aggressive memory usage reduction is disabled by default.
+ ReduceMemoryUsage bool
+
+ // Rejects all non-GET requests if set to true.
+ //
+ // This option is useful as anti-DoS protection for servers
+ // accepting only GET requests and HEAD requests. The request size is limited
+ // by ReadBufferSize if GetOnly is set.
+ //
+ // Server accepts all the requests by default.
+ GetOnly bool
+
+ // Will not pre parse Multipart Form data if set to true.
+ //
+ // This option is useful for servers that desire to treat
+ // multipart form data as a binary blob, or choose when to parse the data.
+ //
+ // Server pre parses multipart form data by default.
+ DisablePreParseMultipartForm bool
+
+ // Logs all errors, including the most frequent
+ // 'connection reset by peer', 'broken pipe' and 'connection timeout'
+ // errors. Such errors are common in production serving real-world
+ // clients.
+ //
+ // By default the most frequent errors such as
+ // 'connection reset by peer', 'broken pipe' and 'connection timeout'
+ // are suppressed in order to limit output log traffic.
+ LogAllErrors bool
+
+ // Will not log potentially sensitive content in error logs
+ //
+ // This option is useful for servers that handle sensitive data
+ // in the request/response.
+ //
+ // Server logs all full errors by default.
+ SecureErrorLogMessage bool
+
+ // Header names are passed as-is without normalization
+ // if this option is set.
+ //
+ // Disabled header names' normalization may be useful only for proxying
+ // incoming requests to other servers expecting case-sensitive
+ // header names. See https://github.com/valyala/fasthttp/issues/57
+ // for details.
+ //
+ // By default request and response header names are normalized, i.e.
+ // The first letter and the first letters following dashes
+ // are uppercased, while all the other letters are lowercased.
+ // Examples:
+ //
+ // * HOST -> Host
+ // * content-type -> Content-Type
+ // * cONTENT-lenGTH -> Content-Length
+ DisableHeaderNamesNormalizing bool
+
+ // SleepWhenConcurrencyLimitsExceeded is a duration to be slept of if
+ // the concurrency limit in exceeded (default [when is 0]: don't sleep
+ // and accept new connections immediately).
+ SleepWhenConcurrencyLimitsExceeded time.Duration
+
+ // NoDefaultServerHeader, when set to true, causes the default Server header
+ // to be excluded from the Response.
+ //
+ // The default Server header value is the value of the Name field or an
+ // internal default value in its absence. With this option set to true,
+ // the only time a Server header will be sent is if a non-zero length
+ // value is explicitly provided during a request.
+ NoDefaultServerHeader bool
+
+ // NoDefaultDate, when set to true, causes the default Date
+ // header to be excluded from the Response.
+ //
+ // The default Date header value is the current date value. When
+ // set to true, the Date will not be present.
+ NoDefaultDate bool
+
+ // NoDefaultContentType, when set to true, causes the default Content-Type
+ // header to be excluded from the Response.
+ //
+ // The default Content-Type header value is the internal default value. When
+ // set to true, the Content-Type will not be present.
+ NoDefaultContentType bool
+
+ // KeepHijackedConns is an opt-in disable of connection
+ // close by fasthttp after connections' HijackHandler returns.
+ // This allows to save goroutines, e.g. when fasthttp used to upgrade
+ // http connections to WS and connection goes to another handler,
+ // which will close it when needed.
+ KeepHijackedConns bool
+
+ // CloseOnShutdown when true adds a `Connection: close` header when the server is shutting down.
+ CloseOnShutdown bool
+
+ // StreamRequestBody enables request body streaming,
+ // and calls the handler sooner when given body is
+ // larger than the current limit.
+ StreamRequestBody bool
+
+ // ConnState specifies an optional callback function that is
+ // called when a client connection changes state. See the
+ // ConnState type and associated constants for details.
+ ConnState func(net.Conn, ConnState)
+
+ // Logger, which is used by RequestCtx.Logger().
+ //
+ // By default standard logger from log package is used.
+ Logger Logger
+
+ // TLSConfig optionally provides a TLS configuration for use
+ // by ServeTLS, ServeTLSEmbed, ListenAndServeTLS, ListenAndServeTLSEmbed,
+ // AppendCert, AppendCertEmbed and NextProto.
+ //
+ // Note that this value is cloned by ServeTLS, ServeTLSEmbed, ListenAndServeTLS
+ // and ListenAndServeTLSEmbed, so it's not possible to modify the configuration
+ // with methods like tls.Config.SetSessionTicketKeys.
+ // To use SetSessionTicketKeys, use Server.Serve with a TLS Listener
+ // instead.
+ TLSConfig *tls.Config
+
+ // FormValueFunc, which is used by RequestCtx.FormValue and support for customizing
+ // the behaviour of the RequestCtx.FormValue function.
+ //
+ // NetHttpFormValueFunc gives a FormValueFunc func implementation that is consistent with net/http.
+ FormValueFunc FormValueFunc
+
+ nextProtos map[string]ServeHandler
+
+ concurrency uint32
+ concurrencyCh chan struct{}
+ perIPConnCounter perIPConnCounter
+
+ ctxPool sync.Pool
+ readerPool sync.Pool
+ writerPool sync.Pool
+ hijackConnPool sync.Pool
+
+ // We need to know our listeners and idle connections so we can close them in Shutdown().
+ ln []net.Listener
+
+ idleConns map[net.Conn]time.Time
+ idleConnsMu sync.Mutex
+
+ mu sync.Mutex
+ open int32
+ stop int32
+ done chan struct{}
+}
+
+// TimeoutHandler creates RequestHandler, which returns StatusRequestTimeout
+// error with the given msg to the client if h didn't return during
+// the given duration.
+//
+// The returned handler may return StatusTooManyRequests error with the given
+// msg to the client if there are more than Server.Concurrency concurrent
+// handlers h are running at the moment.
+func TimeoutHandler(h RequestHandler, timeout time.Duration, msg string) RequestHandler {
+ return TimeoutWithCodeHandler(h, timeout, msg, StatusRequestTimeout)
+}
+
+// TimeoutWithCodeHandler creates RequestHandler, which returns an error with
+// the given msg and status code to the client if h didn't return during
+// the given duration.
+//
+// The returned handler may return StatusTooManyRequests error with the given
+// msg to the client if there are more than Server.Concurrency concurrent
+// handlers h are running at the moment.
+func TimeoutWithCodeHandler(h RequestHandler, timeout time.Duration, msg string, statusCode int) RequestHandler {
+ if timeout <= 0 {
+ return h
+ }
+
+ return func(ctx *RequestCtx) {
+ concurrencyCh := ctx.s.concurrencyCh
+ select {
+ case concurrencyCh <- struct{}{}:
+ default:
+ ctx.Error(msg, StatusTooManyRequests)
+ return
+ }
+
+ ch := ctx.timeoutCh
+ if ch == nil {
+ ch = make(chan struct{}, 1)
+ ctx.timeoutCh = ch
+ }
+ go func() {
+ h(ctx)
+ ch <- struct{}{}
+ <-concurrencyCh
+ }()
+ ctx.timeoutTimer = initTimer(ctx.timeoutTimer, timeout)
+ select {
+ case <-ch:
+ case <-ctx.timeoutTimer.C:
+ ctx.TimeoutErrorWithCode(msg, statusCode)
+ }
+ stopTimer(ctx.timeoutTimer)
+ }
+}
+
+// RequestConfig configure the per request deadline and body limits
+type RequestConfig struct {
+ // ReadTimeout is the maximum duration for reading the entire
+ // request body.
+ // a zero value means that default values will be honored
+ ReadTimeout time.Duration
+ // WriteTimeout is the maximum duration before timing out
+ // writes of the response.
+ // a zero value means that default values will be honored
+ WriteTimeout time.Duration
+ // Maximum request body size.
+ // a zero value means that default values will be honored
+ MaxRequestBodySize int
+}
+
+// CompressHandler returns RequestHandler that transparently compresses
+// response body generated by h if the request contains 'gzip' or 'deflate'
+// 'Accept-Encoding' header.
+func CompressHandler(h RequestHandler) RequestHandler {
+ return CompressHandlerLevel(h, CompressDefaultCompression)
+}
+
+// CompressHandlerLevel returns RequestHandler that transparently compresses
+// response body generated by h if the request contains a 'gzip' or 'deflate'
+// 'Accept-Encoding' header.
+//
+// Level is the desired compression level:
+//
+// - CompressNoCompression
+// - CompressBestSpeed
+// - CompressBestCompression
+// - CompressDefaultCompression
+// - CompressHuffmanOnly
+func CompressHandlerLevel(h RequestHandler, level int) RequestHandler {
+ return func(ctx *RequestCtx) {
+ h(ctx)
+ if ctx.Request.Header.HasAcceptEncodingBytes(strGzip) {
+ ctx.Response.gzipBody(level) //nolint:errcheck
+ } else if ctx.Request.Header.HasAcceptEncodingBytes(strDeflate) {
+ ctx.Response.deflateBody(level) //nolint:errcheck
+ }
+ }
+}
+
+// CompressHandlerBrotliLevel returns RequestHandler that transparently compresses
+// response body generated by h if the request contains a 'br', 'gzip' or 'deflate'
+// 'Accept-Encoding' header.
+//
+// brotliLevel is the desired compression level for brotli.
+//
+// - CompressBrotliNoCompression
+// - CompressBrotliBestSpeed
+// - CompressBrotliBestCompression
+// - CompressBrotliDefaultCompression
+//
+// otherLevel is the desired compression level for gzip and deflate.
+//
+// - CompressNoCompression
+// - CompressBestSpeed
+// - CompressBestCompression
+// - CompressDefaultCompression
+// - CompressHuffmanOnly
+func CompressHandlerBrotliLevel(h RequestHandler, brotliLevel, otherLevel int) RequestHandler {
+ return func(ctx *RequestCtx) {
+ h(ctx)
+ switch {
+ case ctx.Request.Header.HasAcceptEncodingBytes(strBr):
+ ctx.Response.brotliBody(brotliLevel) //nolint:errcheck
+ case ctx.Request.Header.HasAcceptEncodingBytes(strGzip):
+ ctx.Response.gzipBody(otherLevel) //nolint:errcheck
+ case ctx.Request.Header.HasAcceptEncodingBytes(strDeflate):
+ ctx.Response.deflateBody(otherLevel) //nolint:errcheck
+ }
+ }
+}
+
+// RequestCtx contains incoming request and manages outgoing response.
+//
+// It is forbidden copying RequestCtx instances.
+//
+// RequestHandler should avoid holding references to incoming RequestCtx and/or
+// its members after the return.
+// If holding RequestCtx references after the return is unavoidable
+// (for instance, ctx is passed to a separate goroutine and ctx lifetime cannot
+// be controlled), then the RequestHandler MUST call ctx.TimeoutError()
+// before return.
+//
+// It is unsafe modifying/reading RequestCtx instance from concurrently
+// running goroutines. The only exception is TimeoutError*, which may be called
+// while other goroutines accessing RequestCtx.
+type RequestCtx struct {
+ noCopy noCopy
+
+ // Incoming request.
+ //
+ // Copying Request by value is forbidden. Use pointer to Request instead.
+ Request Request
+
+ // Outgoing response.
+ //
+ // Copying Response by value is forbidden. Use pointer to Response instead.
+ Response Response
+
+ userValues userData
+
+ connID uint64
+ connRequestNum uint64
+ connTime time.Time
+ remoteAddr net.Addr
+
+ time time.Time
+
+ logger ctxLogger
+ s *Server
+ c net.Conn
+ fbr firstByteReader
+
+ timeoutResponse *Response
+ timeoutCh chan struct{}
+ timeoutTimer *time.Timer
+
+ hijackHandler HijackHandler
+ hijackNoResponse bool
+ formValueFunc FormValueFunc
+}
+
+// HijackHandler must process the hijacked connection c.
+//
+// If KeepHijackedConns is disabled, which is by default,
+// the connection c is automatically closed after returning from HijackHandler.
+//
+// The connection c must not be used after returning from the handler, if KeepHijackedConns is disabled.
+//
+// When KeepHijackedConns enabled, fasthttp will not Close() the connection,
+// you must do it when you need it. You must not use c in any way after calling Close().
+type HijackHandler func(c net.Conn)
+
+// Hijack registers the given handler for connection hijacking.
+//
+// The handler is called after returning from RequestHandler
+// and sending http response. The current connection is passed
+// to the handler. The connection is automatically closed after
+// returning from the handler.
+//
+// The server skips calling the handler in the following cases:
+//
+// - 'Connection: close' header exists in either request or response.
+// - Unexpected error during response writing to the connection.
+//
+// The server stops processing requests from hijacked connections.
+//
+// Server limits such as Concurrency, ReadTimeout, WriteTimeout, etc.
+// aren't applied to hijacked connections.
+//
+// The handler must not retain references to ctx members.
+//
+// Arbitrary 'Connection: Upgrade' protocols may be implemented
+// with HijackHandler. For instance,
+//
+// - WebSocket ( https://en.wikipedia.org/wiki/WebSocket )
+// - HTTP/2.0 ( https://en.wikipedia.org/wiki/HTTP/2 )
+func (ctx *RequestCtx) Hijack(handler HijackHandler) {
+ ctx.hijackHandler = handler
+}
+
+// HijackSetNoResponse changes the behavior of hijacking a request.
+// If HijackSetNoResponse is called with false fasthttp will send a response
+// to the client before calling the HijackHandler (default). If HijackSetNoResponse
+// is called with true no response is send back before calling the
+// HijackHandler supplied in the Hijack function.
+func (ctx *RequestCtx) HijackSetNoResponse(noResponse bool) {
+ ctx.hijackNoResponse = noResponse
+}
+
+// Hijacked returns true after Hijack is called.
+func (ctx *RequestCtx) Hijacked() bool {
+ return ctx.hijackHandler != nil
+}
+
+// SetUserValue stores the given value (arbitrary object)
+// under the given key in ctx.
+//
+// The value stored in ctx may be obtained by UserValue*.
+//
+// This functionality may be useful for passing arbitrary values between
+// functions involved in request processing.
+//
+// All the values are removed from ctx after returning from the top
+// RequestHandler. Additionally, Close method is called on each value
+// implementing io.Closer before removing the value from ctx.
+func (ctx *RequestCtx) SetUserValue(key interface{}, value interface{}) {
+ ctx.userValues.Set(key, value)
+}
+
+// SetUserValueBytes stores the given value (arbitrary object)
+// under the given key in ctx.
+//
+// The value stored in ctx may be obtained by UserValue*.
+//
+// This functionality may be useful for passing arbitrary values between
+// functions involved in request processing.
+//
+// All the values stored in ctx are deleted after returning from RequestHandler.
+func (ctx *RequestCtx) SetUserValueBytes(key []byte, value interface{}) {
+ ctx.userValues.SetBytes(key, value)
+}
+
+// UserValue returns the value stored via SetUserValue* under the given key.
+func (ctx *RequestCtx) UserValue(key interface{}) interface{} {
+ return ctx.userValues.Get(key)
+}
+
+// UserValueBytes returns the value stored via SetUserValue*
+// under the given key.
+func (ctx *RequestCtx) UserValueBytes(key []byte) interface{} {
+ return ctx.userValues.GetBytes(key)
+}
+
+// VisitUserValues calls visitor for each existing userValue with a key that is a string or []byte.
+//
+// visitor must not retain references to key and value after returning.
+// Make key and/or value copies if you need storing them after returning.
+func (ctx *RequestCtx) VisitUserValues(visitor func([]byte, interface{})) {
+ for i, n := 0, len(ctx.userValues); i < n; i++ {
+ kv := &ctx.userValues[i]
+ if _, ok := kv.key.(string); ok {
+ visitor(s2b(kv.key.(string)), kv.value)
+ }
+ }
+}
+
+// VisitUserValuesAll calls visitor for each existing userValue.
+//
+// visitor must not retain references to key and value after returning.
+// Make key and/or value copies if you need storing them after returning.
+func (ctx *RequestCtx) VisitUserValuesAll(visitor func(interface{}, interface{})) {
+ for i, n := 0, len(ctx.userValues); i < n; i++ {
+ kv := &ctx.userValues[i]
+ visitor(kv.key, kv.value)
+ }
+}
+
+// ResetUserValues allows to reset user values from Request Context
+func (ctx *RequestCtx) ResetUserValues() {
+ ctx.userValues.Reset()
+}
+
+// RemoveUserValue removes the given key and the value under it in ctx.
+func (ctx *RequestCtx) RemoveUserValue(key interface{}) {
+ ctx.userValues.Remove(key)
+}
+
+// RemoveUserValueBytes removes the given key and the value under it in ctx.
+func (ctx *RequestCtx) RemoveUserValueBytes(key []byte) {
+ ctx.userValues.RemoveBytes(key)
+}
+
+type connTLSer interface {
+ Handshake() error
+ ConnectionState() tls.ConnectionState
+}
+
+// IsTLS returns true if the underlying connection is tls.Conn.
+//
+// tls.Conn is an encrypted connection (aka SSL, HTTPS).
+func (ctx *RequestCtx) IsTLS() bool {
+ // cast to (connTLSer) instead of (*tls.Conn), since it catches
+ // cases with overridden tls.Conn such as:
+ //
+ // type customConn struct {
+ // *tls.Conn
+ //
+ // // other custom fields here
+ // }
+
+ // perIPConn wraps the net.Conn in the Conn field
+ if pic, ok := ctx.c.(*perIPConn); ok {
+ _, ok := pic.Conn.(connTLSer)
+ return ok
+ }
+
+ _, ok := ctx.c.(connTLSer)
+ return ok
+}
+
+// TLSConnectionState returns TLS connection state.
+//
+// The function returns nil if the underlying connection isn't tls.Conn.
+//
+// The returned state may be used for verifying TLS version, client certificates,
+// etc.
+func (ctx *RequestCtx) TLSConnectionState() *tls.ConnectionState {
+ tlsConn, ok := ctx.c.(connTLSer)
+ if !ok {
+ return nil
+ }
+ state := tlsConn.ConnectionState()
+ return &state
+}
+
+// Conn returns a reference to the underlying net.Conn.
+//
+// WARNING: Only use this method if you know what you are doing!
+//
+// Reading from or writing to the returned connection will end badly!
+func (ctx *RequestCtx) Conn() net.Conn {
+ return ctx.c
+}
+
+func (ctx *RequestCtx) reset() {
+ ctx.userValues.Reset()
+ ctx.Request.Reset()
+ ctx.Response.Reset()
+ ctx.fbr.reset()
+
+ ctx.connID = 0
+ ctx.connRequestNum = 0
+ ctx.connTime = zeroTime
+ ctx.remoteAddr = nil
+ ctx.time = zeroTime
+ ctx.c = nil
+
+ // Don't reset ctx.s!
+ // We have a pool per server so the next time this ctx is used it
+ // will be assigned the same value again.
+ // ctx might still be in use for context.Done() and context.Err()
+ // which are safe to use as they only use ctx.s and no other value.
+
+ if ctx.timeoutResponse != nil {
+ ctx.timeoutResponse.Reset()
+ }
+
+ if ctx.timeoutTimer != nil {
+ stopTimer(ctx.timeoutTimer)
+ }
+
+ ctx.hijackHandler = nil
+ ctx.hijackNoResponse = false
+}
+
+type firstByteReader struct {
+ c net.Conn
+ ch byte
+ byteRead bool
+}
+
+func (r *firstByteReader) reset() {
+ r.c = nil
+ r.ch = 0
+ r.byteRead = false
+}
+
+func (r *firstByteReader) Read(b []byte) (int, error) {
+ if len(b) == 0 {
+ return 0, nil
+ }
+ nn := 0
+ if !r.byteRead {
+ b[0] = r.ch
+ b = b[1:]
+ r.byteRead = true
+ nn = 1
+ }
+ n, err := r.c.Read(b)
+ return n + nn, err
+}
+
+// Logger is used for logging formatted messages.
+type Logger interface {
+ // Printf must have the same semantics as log.Printf.
+ Printf(format string, args ...interface{})
+}
+
+var ctxLoggerLock sync.Mutex
+
+type ctxLogger struct {
+ ctx *RequestCtx
+ logger Logger
+}
+
+func (cl *ctxLogger) Printf(format string, args ...interface{}) {
+ msg := fmt.Sprintf(format, args...)
+ ctxLoggerLock.Lock()
+ cl.logger.Printf("%.3f %s - %s", time.Since(cl.ctx.ConnTime()).Seconds(), cl.ctx.String(), msg)
+ ctxLoggerLock.Unlock()
+}
+
+var zeroTCPAddr = &net.TCPAddr{
+ IP: net.IPv4zero,
+}
+
+// String returns unique string representation of the ctx.
+//
+// The returned value may be useful for logging.
+func (ctx *RequestCtx) String() string {
+ return fmt.Sprintf("#%016X - %s<->%s - %s %s", ctx.ID(), ctx.LocalAddr(), ctx.RemoteAddr(), ctx.Request.Header.Method(), ctx.URI().FullURI())
+}
+
+// ID returns unique ID of the request.
+func (ctx *RequestCtx) ID() uint64 {
+ return (ctx.connID << 32) | ctx.connRequestNum
+}
+
+// ConnID returns unique connection ID.
+//
+// This ID may be used to match distinct requests to the same incoming
+// connection.
+func (ctx *RequestCtx) ConnID() uint64 {
+ return ctx.connID
+}
+
+// Time returns RequestHandler call time.
+func (ctx *RequestCtx) Time() time.Time {
+ return ctx.time
+}
+
+// ConnTime returns the time the server started serving the connection
+// the current request came from.
+func (ctx *RequestCtx) ConnTime() time.Time {
+ return ctx.connTime
+}
+
+// ConnRequestNum returns request sequence number
+// for the current connection.
+//
+// Sequence starts with 1.
+func (ctx *RequestCtx) ConnRequestNum() uint64 {
+ return ctx.connRequestNum
+}
+
+// SetConnectionClose sets 'Connection: close' response header and closes
+// connection after the RequestHandler returns.
+func (ctx *RequestCtx) SetConnectionClose() {
+ ctx.Response.SetConnectionClose()
+}
+
+// SetStatusCode sets response status code.
+func (ctx *RequestCtx) SetStatusCode(statusCode int) {
+ ctx.Response.SetStatusCode(statusCode)
+}
+
+// SetContentType sets response Content-Type.
+func (ctx *RequestCtx) SetContentType(contentType string) {
+ ctx.Response.Header.SetContentType(contentType)
+}
+
+// SetContentTypeBytes sets response Content-Type.
+//
+// It is safe modifying contentType buffer after function return.
+func (ctx *RequestCtx) SetContentTypeBytes(contentType []byte) {
+ ctx.Response.Header.SetContentTypeBytes(contentType)
+}
+
+// RequestURI returns RequestURI.
+//
+// The returned bytes are valid until your request handler returns.
+func (ctx *RequestCtx) RequestURI() []byte {
+ return ctx.Request.Header.RequestURI()
+}
+
+// URI returns requested uri.
+//
+// This uri is valid until your request handler returns.
+func (ctx *RequestCtx) URI() *URI {
+ return ctx.Request.URI()
+}
+
+// Referer returns request referer.
+//
+// The returned bytes are valid until your request handler returns.
+func (ctx *RequestCtx) Referer() []byte {
+ return ctx.Request.Header.Referer()
+}
+
+// UserAgent returns User-Agent header value from the request.
+//
+// The returned bytes are valid until your request handler returns.
+func (ctx *RequestCtx) UserAgent() []byte {
+ return ctx.Request.Header.UserAgent()
+}
+
+// Path returns requested path.
+//
+// The returned bytes are valid until your request handler returns.
+func (ctx *RequestCtx) Path() []byte {
+ return ctx.URI().Path()
+}
+
+// Host returns requested host.
+//
+// The returned bytes are valid until your request handler returns.
+func (ctx *RequestCtx) Host() []byte {
+ return ctx.URI().Host()
+}
+
+// QueryArgs returns query arguments from RequestURI.
+//
+// It doesn't return POST'ed arguments - use PostArgs() for this.
+//
+// See also PostArgs, FormValue and FormFile.
+//
+// These args are valid until your request handler returns.
+func (ctx *RequestCtx) QueryArgs() *Args {
+ return ctx.URI().QueryArgs()
+}
+
+// PostArgs returns POST arguments.
+//
+// It doesn't return query arguments from RequestURI - use QueryArgs for this.
+//
+// See also QueryArgs, FormValue and FormFile.
+//
+// These args are valid until your request handler returns.
+func (ctx *RequestCtx) PostArgs() *Args {
+ return ctx.Request.PostArgs()
+}
+
+// MultipartForm returns request's multipart form.
+//
+// Returns ErrNoMultipartForm if request's content-type
+// isn't 'multipart/form-data'.
+//
+// All uploaded temporary files are automatically deleted after
+// returning from RequestHandler. Either move or copy uploaded files
+// into new place if you want retaining them.
+//
+// Use SaveMultipartFile function for permanently saving uploaded file.
+//
+// The returned form is valid until your request handler returns.
+//
+// See also FormFile and FormValue.
+func (ctx *RequestCtx) MultipartForm() (*multipart.Form, error) {
+ return ctx.Request.MultipartForm()
+}
+
+// FormFile returns uploaded file associated with the given multipart form key.
+//
+// The file is automatically deleted after returning from RequestHandler,
+// so either move or copy uploaded file into new place if you want retaining it.
+//
+// Use SaveMultipartFile function for permanently saving uploaded file.
+//
+// The returned file header is valid until your request handler returns.
+func (ctx *RequestCtx) FormFile(key string) (*multipart.FileHeader, error) {
+ mf, err := ctx.MultipartForm()
+ if err != nil {
+ return nil, err
+ }
+ if mf.File == nil {
+ return nil, err
+ }
+ fhh := mf.File[key]
+ if fhh == nil {
+ return nil, ErrMissingFile
+ }
+ return fhh[0], nil
+}
+
+// ErrMissingFile may be returned from FormFile when the is no uploaded file
+// associated with the given multipart form key.
+var ErrMissingFile = errors.New("there is no uploaded file associated with the given key")
+
+// SaveMultipartFile saves multipart file fh under the given filename path.
+func SaveMultipartFile(fh *multipart.FileHeader, path string) (err error) {
+ var (
+ f multipart.File
+ ff *os.File
+ )
+ f, err = fh.Open()
+ if err != nil {
+ return
+ }
+
+ var ok bool
+ if ff, ok = f.(*os.File); ok {
+ // Windows can't rename files that are opened.
+ if err = f.Close(); err != nil {
+ return
+ }
+
+ // If renaming fails we try the normal copying method.
+ // Renaming could fail if the files are on different devices.
+ if os.Rename(ff.Name(), path) == nil {
+ return nil
+ }
+
+ // Reopen f for the code below.
+ if f, err = fh.Open(); err != nil {
+ return
+ }
+ }
+
+ defer func() {
+ e := f.Close()
+ if err == nil {
+ err = e
+ }
+ }()
+
+ if ff, err = os.Create(path); err != nil {
+ return
+ }
+ defer func() {
+ e := ff.Close()
+ if err == nil {
+ err = e
+ }
+ }()
+ _, err = copyZeroAlloc(ff, f)
+ return
+}
+
+// FormValue returns form value associated with the given key.
+//
+// The value is searched in the following places:
+//
+// - Query string.
+// - POST or PUT body.
+//
+// There are more fine-grained methods for obtaining form values:
+//
+// - QueryArgs for obtaining values from query string.
+// - PostArgs for obtaining values from POST or PUT body.
+// - MultipartForm for obtaining values from multipart form.
+// - FormFile for obtaining uploaded files.
+//
+// The returned value is valid until your request handler returns.
+func (ctx *RequestCtx) FormValue(key string) []byte {
+ if ctx.formValueFunc != nil {
+ return ctx.formValueFunc(ctx, key)
+ }
+ return defaultFormValue(ctx, key)
+}
+
+type FormValueFunc func(*RequestCtx, string) []byte
+
+var (
+ defaultFormValue = func(ctx *RequestCtx, key string) []byte {
+ v := ctx.QueryArgs().Peek(key)
+ if len(v) > 0 {
+ return v
+ }
+ v = ctx.PostArgs().Peek(key)
+ if len(v) > 0 {
+ return v
+ }
+ mf, err := ctx.MultipartForm()
+ if err == nil && mf.Value != nil {
+ vv := mf.Value[key]
+ if len(vv) > 0 {
+ return []byte(vv[0])
+ }
+ }
+ return nil
+ }
+
+ // NetHttpFormValueFunc gives consistent behavior with net/http. POST and PUT body parameters take precedence over URL query string values.
+ NetHttpFormValueFunc = func(ctx *RequestCtx, key string) []byte {
+ v := ctx.PostArgs().Peek(key)
+ if len(v) > 0 {
+ return v
+ }
+ mf, err := ctx.MultipartForm()
+ if err == nil && mf.Value != nil {
+ vv := mf.Value[key]
+ if len(vv) > 0 {
+ return []byte(vv[0])
+ }
+ }
+ v = ctx.QueryArgs().Peek(key)
+ if len(v) > 0 {
+ return v
+ }
+ return nil
+ }
+)
+
+// IsGet returns true if request method is GET.
+func (ctx *RequestCtx) IsGet() bool {
+ return ctx.Request.Header.IsGet()
+}
+
+// IsPost returns true if request method is POST.
+func (ctx *RequestCtx) IsPost() bool {
+ return ctx.Request.Header.IsPost()
+}
+
+// IsPut returns true if request method is PUT.
+func (ctx *RequestCtx) IsPut() bool {
+ return ctx.Request.Header.IsPut()
+}
+
+// IsDelete returns true if request method is DELETE.
+func (ctx *RequestCtx) IsDelete() bool {
+ return ctx.Request.Header.IsDelete()
+}
+
+// IsConnect returns true if request method is CONNECT.
+func (ctx *RequestCtx) IsConnect() bool {
+ return ctx.Request.Header.IsConnect()
+}
+
+// IsOptions returns true if request method is OPTIONS.
+func (ctx *RequestCtx) IsOptions() bool {
+ return ctx.Request.Header.IsOptions()
+}
+
+// IsTrace returns true if request method is TRACE.
+func (ctx *RequestCtx) IsTrace() bool {
+ return ctx.Request.Header.IsTrace()
+}
+
+// IsPatch returns true if request method is PATCH.
+func (ctx *RequestCtx) IsPatch() bool {
+ return ctx.Request.Header.IsPatch()
+}
+
+// Method return request method.
+//
+// Returned value is valid until your request handler returns.
+func (ctx *RequestCtx) Method() []byte {
+ return ctx.Request.Header.Method()
+}
+
+// IsHead returns true if request method is HEAD.
+func (ctx *RequestCtx) IsHead() bool {
+ return ctx.Request.Header.IsHead()
+}
+
+// RemoteAddr returns client address for the given request.
+//
+// Always returns non-nil result.
+func (ctx *RequestCtx) RemoteAddr() net.Addr {
+ if ctx.remoteAddr != nil {
+ return ctx.remoteAddr
+ }
+ if ctx.c == nil {
+ return zeroTCPAddr
+ }
+ addr := ctx.c.RemoteAddr()
+ if addr == nil {
+ return zeroTCPAddr
+ }
+ return addr
+}
+
+// SetRemoteAddr sets remote address to the given value.
+//
+// Set nil value to restore default behaviour for using
+// connection remote address.
+func (ctx *RequestCtx) SetRemoteAddr(remoteAddr net.Addr) {
+ ctx.remoteAddr = remoteAddr
+}
+
+// LocalAddr returns server address for the given request.
+//
+// Always returns non-nil result.
+func (ctx *RequestCtx) LocalAddr() net.Addr {
+ if ctx.c == nil {
+ return zeroTCPAddr
+ }
+ addr := ctx.c.LocalAddr()
+ if addr == nil {
+ return zeroTCPAddr
+ }
+ return addr
+}
+
+// RemoteIP returns the client ip the request came from.
+//
+// Always returns non-nil result.
+func (ctx *RequestCtx) RemoteIP() net.IP {
+ return addrToIP(ctx.RemoteAddr())
+}
+
+// LocalIP returns the server ip the request came to.
+//
+// Always returns non-nil result.
+func (ctx *RequestCtx) LocalIP() net.IP {
+ return addrToIP(ctx.LocalAddr())
+}
+
+func addrToIP(addr net.Addr) net.IP {
+ x, ok := addr.(*net.TCPAddr)
+ if !ok {
+ return net.IPv4zero
+ }
+ return x.IP
+}
+
+// Error sets response status code to the given value and sets response body
+// to the given message.
+//
+// Warning: this will reset the response headers and body already set!
+func (ctx *RequestCtx) Error(msg string, statusCode int) {
+ ctx.Response.Reset()
+ ctx.SetStatusCode(statusCode)
+ ctx.SetContentTypeBytes(defaultContentType)
+ ctx.SetBodyString(msg)
+}
+
+// Success sets response Content-Type and body to the given values.
+func (ctx *RequestCtx) Success(contentType string, body []byte) {
+ ctx.SetContentType(contentType)
+ ctx.SetBody(body)
+}
+
+// SuccessString sets response Content-Type and body to the given values.
+func (ctx *RequestCtx) SuccessString(contentType, body string) {
+ ctx.SetContentType(contentType)
+ ctx.SetBodyString(body)
+}
+
+// Redirect sets 'Location: uri' response header and sets the given statusCode.
+//
+// statusCode must have one of the following values:
+//
+// - StatusMovedPermanently (301)
+// - StatusFound (302)
+// - StatusSeeOther (303)
+// - StatusTemporaryRedirect (307)
+// - StatusPermanentRedirect (308)
+//
+// All other statusCode values are replaced by StatusFound (302).
+//
+// The redirect uri may be either absolute or relative to the current
+// request uri. Fasthttp will always send an absolute uri back to the client.
+// To send a relative uri you can use the following code:
+//
+// strLocation = []byte("Location") // Put this with your top level var () declarations.
+// ctx.Response.Header.SetCanonical(strLocation, "/relative?uri")
+// ctx.Response.SetStatusCode(fasthttp.StatusMovedPermanently)
+func (ctx *RequestCtx) Redirect(uri string, statusCode int) {
+ u := AcquireURI()
+ ctx.URI().CopyTo(u)
+ u.Update(uri)
+ ctx.redirect(u.FullURI(), statusCode)
+ ReleaseURI(u)
+}
+
+// RedirectBytes sets 'Location: uri' response header and sets
+// the given statusCode.
+//
+// statusCode must have one of the following values:
+//
+// - StatusMovedPermanently (301)
+// - StatusFound (302)
+// - StatusSeeOther (303)
+// - StatusTemporaryRedirect (307)
+// - StatusPermanentRedirect (308)
+//
+// All other statusCode values are replaced by StatusFound (302).
+//
+// The redirect uri may be either absolute or relative to the current
+// request uri. Fasthttp will always send an absolute uri back to the client.
+// To send a relative uri you can use the following code:
+//
+// strLocation = []byte("Location") // Put this with your top level var () declarations.
+// ctx.Response.Header.SetCanonical(strLocation, "/relative?uri")
+// ctx.Response.SetStatusCode(fasthttp.StatusMovedPermanently)
+func (ctx *RequestCtx) RedirectBytes(uri []byte, statusCode int) {
+ s := b2s(uri)
+ ctx.Redirect(s, statusCode)
+}
+
+func (ctx *RequestCtx) redirect(uri []byte, statusCode int) {
+ ctx.Response.Header.setNonSpecial(strLocation, uri)
+ statusCode = getRedirectStatusCode(statusCode)
+ ctx.Response.SetStatusCode(statusCode)
+}
+
+func getRedirectStatusCode(statusCode int) int {
+ if statusCode == StatusMovedPermanently || statusCode == StatusFound ||
+ statusCode == StatusSeeOther || statusCode == StatusTemporaryRedirect ||
+ statusCode == StatusPermanentRedirect {
+ return statusCode
+ }
+ return StatusFound
+}
+
+// SetBody sets response body to the given value.
+//
+// It is safe re-using body argument after the function returns.
+func (ctx *RequestCtx) SetBody(body []byte) {
+ ctx.Response.SetBody(body)
+}
+
+// SetBodyString sets response body to the given value.
+func (ctx *RequestCtx) SetBodyString(body string) {
+ ctx.Response.SetBodyString(body)
+}
+
+// ResetBody resets response body contents.
+func (ctx *RequestCtx) ResetBody() {
+ ctx.Response.ResetBody()
+}
+
+// SendFile sends local file contents from the given path as response body.
+//
+// This is a shortcut to ServeFile(ctx, path).
+//
+// SendFile logs all the errors via ctx.Logger.
+//
+// See also ServeFile, FSHandler and FS.
+//
+// WARNING: do not pass any user supplied paths to this function!
+// WARNING: if path is based on user input users will be able to request
+// any file on your filesystem! Use fasthttp.FS with a sane Root instead.
+func (ctx *RequestCtx) SendFile(path string) {
+ ServeFile(ctx, path)
+}
+
+// SendFileBytes sends local file contents from the given path as response body.
+//
+// This is a shortcut to ServeFileBytes(ctx, path).
+//
+// SendFileBytes logs all the errors via ctx.Logger.
+//
+// See also ServeFileBytes, FSHandler and FS.
+//
+// WARNING: do not pass any user supplied paths to this function!
+// WARNING: if path is based on user input users will be able to request
+// any file on your filesystem! Use fasthttp.FS with a sane Root instead.
+func (ctx *RequestCtx) SendFileBytes(path []byte) {
+ ServeFileBytes(ctx, path)
+}
+
+// IfModifiedSince returns true if lastModified exceeds 'If-Modified-Since'
+// value from the request header.
+//
+// The function returns true also 'If-Modified-Since' request header is missing.
+func (ctx *RequestCtx) IfModifiedSince(lastModified time.Time) bool {
+ ifModStr := ctx.Request.Header.peek(strIfModifiedSince)
+ if len(ifModStr) == 0 {
+ return true
+ }
+ ifMod, err := ParseHTTPDate(ifModStr)
+ if err != nil {
+ return true
+ }
+ lastModified = lastModified.Truncate(time.Second)
+ return ifMod.Before(lastModified)
+}
+
+// NotModified resets response and sets '304 Not Modified' response status code.
+func (ctx *RequestCtx) NotModified() {
+ ctx.Response.Reset()
+ ctx.SetStatusCode(StatusNotModified)
+}
+
+// NotFound resets response and sets '404 Not Found' response status code.
+func (ctx *RequestCtx) NotFound() {
+ ctx.Response.Reset()
+ ctx.SetStatusCode(StatusNotFound)
+ ctx.SetBodyString("404 Page not found")
+}
+
+// Write writes p into response body.
+func (ctx *RequestCtx) Write(p []byte) (int, error) {
+ ctx.Response.AppendBody(p)
+ return len(p), nil
+}
+
+// WriteString appends s to response body.
+func (ctx *RequestCtx) WriteString(s string) (int, error) {
+ ctx.Response.AppendBodyString(s)
+ return len(s), nil
+}
+
+// PostBody returns POST request body.
+//
+// The returned bytes are valid until your request handler returns.
+func (ctx *RequestCtx) PostBody() []byte {
+ return ctx.Request.Body()
+}
+
+// SetBodyStream sets response body stream and, optionally body size.
+//
+// bodyStream.Close() is called after finishing reading all body data
+// if it implements io.Closer.
+//
+// If bodySize is >= 0, then bodySize bytes must be provided by bodyStream
+// before returning io.EOF.
+//
+// If bodySize < 0, then bodyStream is read until io.EOF.
+//
+// See also SetBodyStreamWriter.
+func (ctx *RequestCtx) SetBodyStream(bodyStream io.Reader, bodySize int) {
+ ctx.Response.SetBodyStream(bodyStream, bodySize)
+}
+
+// SetBodyStreamWriter registers the given stream writer for populating
+// response body.
+//
+// Access to RequestCtx and/or its members is forbidden from sw.
+//
+// This function may be used in the following cases:
+//
+// - if response body is too big (more than 10MB).
+// - if response body is streamed from slow external sources.
+// - if response body must be streamed to the client in chunks.
+// (aka `http server push`).
+func (ctx *RequestCtx) SetBodyStreamWriter(sw StreamWriter) {
+ ctx.Response.SetBodyStreamWriter(sw)
+}
+
+// IsBodyStream returns true if response body is set via SetBodyStream*.
+func (ctx *RequestCtx) IsBodyStream() bool {
+ return ctx.Response.IsBodyStream()
+}
+
+// Logger returns logger, which may be used for logging arbitrary
+// request-specific messages inside RequestHandler.
+//
+// Each message logged via returned logger contains request-specific information
+// such as request id, request duration, local address, remote address,
+// request method and request url.
+//
+// It is safe re-using returned logger for logging multiple messages
+// for the current request.
+//
+// The returned logger is valid until your request handler returns.
+func (ctx *RequestCtx) Logger() Logger {
+ if ctx.logger.ctx == nil {
+ ctx.logger.ctx = ctx
+ }
+ if ctx.logger.logger == nil {
+ ctx.logger.logger = ctx.s.logger()
+ }
+ return &ctx.logger
+}
+
+// TimeoutError sets response status code to StatusRequestTimeout and sets
+// body to the given msg.
+//
+// All response modifications after TimeoutError call are ignored.
+//
+// TimeoutError MUST be called before returning from RequestHandler if there are
+// references to ctx and/or its members in other goroutines remain.
+//
+// Usage of this function is discouraged. Prefer eliminating ctx references
+// from pending goroutines instead of using this function.
+func (ctx *RequestCtx) TimeoutError(msg string) {
+ ctx.TimeoutErrorWithCode(msg, StatusRequestTimeout)
+}
+
+// TimeoutErrorWithCode sets response body to msg and response status
+// code to statusCode.
+//
+// All response modifications after TimeoutErrorWithCode call are ignored.
+//
+// TimeoutErrorWithCode MUST be called before returning from RequestHandler
+// if there are references to ctx and/or its members in other goroutines remain.
+//
+// Usage of this function is discouraged. Prefer eliminating ctx references
+// from pending goroutines instead of using this function.
+func (ctx *RequestCtx) TimeoutErrorWithCode(msg string, statusCode int) {
+ var resp Response
+ resp.SetStatusCode(statusCode)
+ resp.SetBodyString(msg)
+ ctx.TimeoutErrorWithResponse(&resp)
+}
+
+// TimeoutErrorWithResponse marks the ctx as timed out and sends the given
+// response to the client.
+//
+// All ctx modifications after TimeoutErrorWithResponse call are ignored.
+//
+// TimeoutErrorWithResponse MUST be called before returning from RequestHandler
+// if there are references to ctx and/or its members in other goroutines remain.
+//
+// Usage of this function is discouraged. Prefer eliminating ctx references
+// from pending goroutines instead of using this function.
+func (ctx *RequestCtx) TimeoutErrorWithResponse(resp *Response) {
+ respCopy := &Response{}
+ resp.CopyTo(respCopy)
+ ctx.timeoutResponse = respCopy
+}
+
+// NextProto adds nph to be processed when key is negotiated when TLS
+// connection is established.
+//
+// This function can only be called before the server is started.
+func (s *Server) NextProto(key string, nph ServeHandler) {
+ if s.nextProtos == nil {
+ s.nextProtos = make(map[string]ServeHandler)
+ }
+
+ s.configTLS()
+ s.TLSConfig.NextProtos = append(s.TLSConfig.NextProtos, key)
+ s.nextProtos[key] = nph
+}
+
+func (s *Server) getNextProto(c net.Conn) (proto string, err error) {
+ if tlsConn, ok := c.(connTLSer); ok {
+ if s.ReadTimeout > 0 {
+ if err := c.SetReadDeadline(time.Now().Add(s.ReadTimeout)); err != nil {
+ panic(fmt.Sprintf("BUG: error in SetReadDeadline(%v): %v", s.ReadTimeout, err))
+ }
+ }
+
+ if s.WriteTimeout > 0 {
+ if err := c.SetWriteDeadline(time.Now().Add(s.WriteTimeout)); err != nil {
+ panic(fmt.Sprintf("BUG: error in SetWriteDeadline(%v): %v", s.WriteTimeout, err))
+ }
+ }
+
+ err = tlsConn.Handshake()
+ if err == nil {
+ proto = tlsConn.ConnectionState().NegotiatedProtocol
+ }
+ }
+ return
+}
+
+// ListenAndServe serves HTTP requests from the given TCP4 addr.
+//
+// Pass custom listener to Serve if you need listening on non-TCP4 media
+// such as IPv6.
+//
+// Accepted connections are configured to enable TCP keep-alives.
+func (s *Server) ListenAndServe(addr string) error {
+ ln, err := net.Listen("tcp4", addr)
+ if err != nil {
+ return err
+ }
+ return s.Serve(ln)
+}
+
+// ListenAndServeUNIX serves HTTP requests from the given UNIX addr.
+//
+// The function deletes existing file at addr before starting serving.
+//
+// The server sets the given file mode for the UNIX addr.
+func (s *Server) ListenAndServeUNIX(addr string, mode os.FileMode) error {
+ if err := os.Remove(addr); err != nil && !os.IsNotExist(err) {
+ return fmt.Errorf("unexpected error when trying to remove unix socket file %q: %w", addr, err)
+ }
+ ln, err := net.Listen("unix", addr)
+ if err != nil {
+ return err
+ }
+ if err = os.Chmod(addr, mode); err != nil {
+ return fmt.Errorf("cannot chmod %#o for %q: %w", mode, addr, err)
+ }
+ return s.Serve(ln)
+}
+
+// ListenAndServeTLS serves HTTPS requests from the given TCP4 addr.
+//
+// certFile and keyFile are paths to TLS certificate and key files.
+//
+// Pass custom listener to Serve if you need listening on non-TCP4 media
+// such as IPv6.
+//
+// If the certFile or keyFile has not been provided to the server structure,
+// the function will use the previously added TLS configuration.
+//
+// Accepted connections are configured to enable TCP keep-alives.
+func (s *Server) ListenAndServeTLS(addr, certFile, keyFile string) error {
+ ln, err := net.Listen("tcp4", addr)
+ if err != nil {
+ return err
+ }
+ return s.ServeTLS(ln, certFile, keyFile)
+}
+
+// ListenAndServeTLSEmbed serves HTTPS requests from the given TCP4 addr.
+//
+// certData and keyData must contain valid TLS certificate and key data.
+//
+// Pass custom listener to Serve if you need listening on arbitrary media
+// such as IPv6.
+//
+// If the certFile or keyFile has not been provided the server structure,
+// the function will use previously added TLS configuration.
+//
+// Accepted connections are configured to enable TCP keep-alives.
+func (s *Server) ListenAndServeTLSEmbed(addr string, certData, keyData []byte) error {
+ ln, err := net.Listen("tcp4", addr)
+ if err != nil {
+ return err
+ }
+ return s.ServeTLSEmbed(ln, certData, keyData)
+}
+
+// ServeTLS serves HTTPS requests from the given listener.
+//
+// certFile and keyFile are paths to TLS certificate and key files.
+//
+// If the certFile or keyFile has not been provided the server structure,
+// the function will use previously added TLS configuration.
+func (s *Server) ServeTLS(ln net.Listener, certFile, keyFile string) error {
+ s.mu.Lock()
+ s.configTLS()
+ configHasCert := len(s.TLSConfig.Certificates) > 0 || s.TLSConfig.GetCertificate != nil
+ if !configHasCert || certFile != "" || keyFile != "" {
+ if err := s.AppendCert(certFile, keyFile); err != nil {
+ s.mu.Unlock()
+ return err
+ }
+ }
+
+ // BuildNameToCertificate has been deprecated since 1.14.
+ // But since we also support older versions we'll keep this here.
+ s.TLSConfig.BuildNameToCertificate() //nolint:staticcheck
+
+ s.mu.Unlock()
+
+ return s.Serve(
+ tls.NewListener(ln, s.TLSConfig.Clone()),
+ )
+}
+
+// ServeTLSEmbed serves HTTPS requests from the given listener.
+//
+// certData and keyData must contain valid TLS certificate and key data.
+//
+// If the certFile or keyFile has not been provided the server structure,
+// the function will use previously added TLS configuration.
+func (s *Server) ServeTLSEmbed(ln net.Listener, certData, keyData []byte) error {
+ s.mu.Lock()
+ s.configTLS()
+ configHasCert := len(s.TLSConfig.Certificates) > 0 || s.TLSConfig.GetCertificate != nil
+ if !configHasCert || len(certData) != 0 || len(keyData) != 0 {
+ if err := s.AppendCertEmbed(certData, keyData); err != nil {
+ s.mu.Unlock()
+ return err
+ }
+ }
+
+ // BuildNameToCertificate has been deprecated since 1.14.
+ // But since we also support older versions we'll keep this here.
+ s.TLSConfig.BuildNameToCertificate() //nolint:staticcheck
+
+ s.mu.Unlock()
+
+ return s.Serve(
+ tls.NewListener(ln, s.TLSConfig.Clone()),
+ )
+}
+
+// AppendCert appends certificate and keyfile to TLS Configuration.
+//
+// This function allows programmer to handle multiple domains
+// in one server structure. See examples/multidomain
+func (s *Server) AppendCert(certFile, keyFile string) error {
+ if len(certFile) == 0 && len(keyFile) == 0 {
+ return errNoCertOrKeyProvided
+ }
+
+ cert, err := tls.LoadX509KeyPair(certFile, keyFile)
+ if err != nil {
+ return fmt.Errorf("cannot load TLS key pair from certFile=%q and keyFile=%q: %w", certFile, keyFile, err)
+ }
+
+ s.configTLS()
+ s.TLSConfig.Certificates = append(s.TLSConfig.Certificates, cert)
+
+ return nil
+}
+
+// AppendCertEmbed does the same as AppendCert but using in-memory data.
+func (s *Server) AppendCertEmbed(certData, keyData []byte) error {
+ if len(certData) == 0 && len(keyData) == 0 {
+ return errNoCertOrKeyProvided
+ }
+
+ cert, err := tls.X509KeyPair(certData, keyData)
+ if err != nil {
+ return fmt.Errorf("cannot load TLS key pair from the provided certData(%d) and keyData(%d): %w",
+ len(certData), len(keyData), err)
+ }
+
+ s.configTLS()
+ s.TLSConfig.Certificates = append(s.TLSConfig.Certificates, cert)
+
+ return nil
+}
+
+func (s *Server) configTLS() {
+ if s.TLSConfig == nil {
+ s.TLSConfig = &tls.Config{}
+ }
+}
+
+// DefaultConcurrency is the maximum number of concurrent connections
+// the Server may serve by default (i.e. if Server.Concurrency isn't set).
+const DefaultConcurrency = 256 * 1024
+
+// Serve serves incoming connections from the given listener.
+//
+// Serve blocks until the given listener returns permanent error.
+func (s *Server) Serve(ln net.Listener) error {
+ var lastOverflowErrorTime time.Time
+ var lastPerIPErrorTime time.Time
+ var c net.Conn
+ var err error
+
+ maxWorkersCount := s.getConcurrency()
+
+ s.mu.Lock()
+ s.ln = append(s.ln, ln)
+ if s.done == nil {
+ s.done = make(chan struct{})
+ }
+ if s.concurrencyCh == nil {
+ s.concurrencyCh = make(chan struct{}, maxWorkersCount)
+ }
+ s.mu.Unlock()
+
+ wp := &workerPool{
+ WorkerFunc: s.serveConn,
+ MaxWorkersCount: maxWorkersCount,
+ LogAllErrors: s.LogAllErrors,
+ MaxIdleWorkerDuration: s.MaxIdleWorkerDuration,
+ Logger: s.logger(),
+ connState: s.setState,
+ }
+ wp.Start()
+
+ // Count our waiting to accept a connection as an open connection.
+ // This way we can't get into any weird state where just after accepting
+ // a connection Shutdown is called which reads open as 0 because it isn't
+ // incremented yet.
+ atomic.AddInt32(&s.open, 1)
+ defer atomic.AddInt32(&s.open, -1)
+
+ for {
+ if c, err = acceptConn(s, ln, &lastPerIPErrorTime); err != nil {
+ wp.Stop()
+ if err == io.EOF {
+ return nil
+ }
+ return err
+ }
+ s.setState(c, StateNew)
+ atomic.AddInt32(&s.open, 1)
+ if !wp.Serve(c) {
+ atomic.AddInt32(&s.open, -1)
+ s.writeFastError(c, StatusServiceUnavailable,
+ "The connection cannot be served because Server.Concurrency limit exceeded")
+ c.Close()
+ s.setState(c, StateClosed)
+ if time.Since(lastOverflowErrorTime) > time.Minute {
+ s.logger().Printf("The incoming connection cannot be served, because %d concurrent connections are served. "+
+ "Try increasing Server.Concurrency", maxWorkersCount)
+ lastOverflowErrorTime = time.Now()
+ }
+
+ // The current server reached concurrency limit,
+ // so give other concurrently running servers a chance
+ // accepting incoming connections on the same address.
+ //
+ // There is a hope other servers didn't reach their
+ // concurrency limits yet :)
+ //
+ // See also: https://github.com/valyala/fasthttp/pull/485#discussion_r239994990
+ if s.SleepWhenConcurrencyLimitsExceeded > 0 {
+ time.Sleep(s.SleepWhenConcurrencyLimitsExceeded)
+ }
+ }
+ c = nil
+ }
+}
+
+// Shutdown gracefully shuts down the server without interrupting any active connections.
+// Shutdown works by first closing all open listeners and then waiting indefinitely for all connections to return to idle and then shut down.
+//
+// When Shutdown is called, Serve, ListenAndServe, and ListenAndServeTLS immediately return nil.
+// Make sure the program doesn't exit and waits instead for Shutdown to return.
+//
+// Shutdown does not close keepalive connections so it's recommended to set ReadTimeout and IdleTimeout to something else than 0.
+func (s *Server) Shutdown() error {
+ return s.ShutdownWithContext(context.Background())
+}
+
+// ShutdownWithContext gracefully shuts down the server without interrupting any active connections.
+// ShutdownWithContext works by first closing all open listeners and then waiting for all connections to return to idle or context timeout and then shut down.
+//
+// When ShutdownWithContext is called, Serve, ListenAndServe, and ListenAndServeTLS immediately return nil.
+// Make sure the program doesn't exit and waits instead for Shutdown to return.
+//
+// ShutdownWithContext does not close keepalive connections so it's recommended to set ReadTimeout and IdleTimeout to something else than 0.
+func (s *Server) ShutdownWithContext(ctx context.Context) (err error) {
+ s.mu.Lock()
+ defer s.mu.Unlock()
+
+ atomic.StoreInt32(&s.stop, 1)
+ defer atomic.StoreInt32(&s.stop, 0)
+
+ if s.ln == nil {
+ return nil
+ }
+
+ for _, ln := range s.ln {
+ if err = ln.Close(); err != nil {
+ return err
+ }
+ }
+
+ if s.done != nil {
+ close(s.done)
+ }
+
+ // Closing the listener will make Serve() call Stop on the worker pool.
+ // Setting .stop to 1 will make serveConn() break out of its loop.
+ // Now we just have to wait until all workers are done or timeout.
+ ticker := time.NewTicker(time.Millisecond * 100)
+ defer ticker.Stop()
+END:
+ for {
+ s.closeIdleConns()
+
+ if open := atomic.LoadInt32(&s.open); open == 0 {
+ break
+ }
+ // This is not an optimal solution but using a sync.WaitGroup
+ // here causes data races as it's hard to prevent Add() to be called
+ // while Wait() is waiting.
+ select {
+ case <-ctx.Done():
+ err = ctx.Err()
+ break END
+ case <-ticker.C:
+ continue
+ }
+ }
+
+ s.done = nil
+ s.ln = nil
+ return err
+}
+
+func acceptConn(s *Server, ln net.Listener, lastPerIPErrorTime *time.Time) (net.Conn, error) {
+ for {
+ c, err := ln.Accept()
+ if err != nil {
+ if netErr, ok := err.(net.Error); ok && netErr.Timeout() {
+ s.logger().Printf("Timeout error when accepting new connections: %v", netErr)
+ time.Sleep(time.Second)
+ continue
+ }
+ if err != io.EOF && !strings.Contains(err.Error(), "use of closed network connection") {
+ s.logger().Printf("Permanent error when accepting new connections: %v", err)
+ return nil, err
+ }
+ return nil, io.EOF
+ }
+
+ if tc, ok := c.(*net.TCPConn); ok && s.TCPKeepalive {
+ if err := tc.SetKeepAlive(s.TCPKeepalive); err != nil {
+ _ = tc.Close()
+ return nil, err
+ }
+ if s.TCPKeepalivePeriod > 0 {
+ if err := tc.SetKeepAlivePeriod(s.TCPKeepalivePeriod); err != nil {
+ _ = tc.Close()
+ return nil, err
+ }
+ }
+ }
+
+ if s.MaxConnsPerIP > 0 {
+ pic := wrapPerIPConn(s, c)
+ if pic == nil {
+ if time.Since(*lastPerIPErrorTime) > time.Minute {
+ s.logger().Printf("The number of connections from %s exceeds MaxConnsPerIP=%d",
+ getConnIP4(c), s.MaxConnsPerIP)
+ *lastPerIPErrorTime = time.Now()
+ }
+ continue
+ }
+ c = pic
+ }
+ return c, nil
+ }
+}
+
+func wrapPerIPConn(s *Server, c net.Conn) net.Conn {
+ ip := getUint32IP(c)
+ if ip == 0 {
+ return c
+ }
+ n := s.perIPConnCounter.Register(ip)
+ if n > s.MaxConnsPerIP {
+ s.perIPConnCounter.Unregister(ip)
+ s.writeFastError(c, StatusTooManyRequests, "The number of connections from your ip exceeds MaxConnsPerIP")
+ c.Close()
+ return nil
+ }
+ return acquirePerIPConn(c, ip, &s.perIPConnCounter)
+}
+
+var defaultLogger = Logger(log.New(os.Stderr, "", log.LstdFlags))
+
+func (s *Server) logger() Logger {
+ if s.Logger != nil {
+ return s.Logger
+ }
+ return defaultLogger
+}
+
+var (
+ // ErrPerIPConnLimit may be returned from ServeConn if the number of connections
+ // per ip exceeds Server.MaxConnsPerIP.
+ ErrPerIPConnLimit = errors.New("too many connections per ip")
+
+ // ErrConcurrencyLimit may be returned from ServeConn if the number
+ // of concurrently served connections exceeds Server.Concurrency.
+ ErrConcurrencyLimit = errors.New("cannot serve the connection because Server.Concurrency concurrent connections are served")
+)
+
+// ServeConn serves HTTP requests from the given connection.
+//
+// ServeConn returns nil if all requests from the c are successfully served.
+// It returns non-nil error otherwise.
+//
+// Connection c must immediately propagate all the data passed to Write()
+// to the client. Otherwise requests' processing may hang.
+//
+// ServeConn closes c before returning.
+func (s *Server) ServeConn(c net.Conn) error {
+ if s.MaxConnsPerIP > 0 {
+ pic := wrapPerIPConn(s, c)
+ if pic == nil {
+ return ErrPerIPConnLimit
+ }
+ c = pic
+ }
+
+ n := atomic.AddUint32(&s.concurrency, 1)
+ if n > uint32(s.getConcurrency()) {
+ atomic.AddUint32(&s.concurrency, ^uint32(0))
+ s.writeFastError(c, StatusServiceUnavailable, "The connection cannot be served because Server.Concurrency limit exceeded")
+ c.Close()
+ return ErrConcurrencyLimit
+ }
+
+ atomic.AddInt32(&s.open, 1)
+
+ err := s.serveConn(c)
+
+ atomic.AddUint32(&s.concurrency, ^uint32(0))
+
+ if err != errHijacked {
+ err1 := c.Close()
+ s.setState(c, StateClosed)
+ if err == nil {
+ err = err1
+ }
+ } else {
+ err = nil
+ s.setState(c, StateHijacked)
+ }
+ return err
+}
+
+var errHijacked = errors.New("connection has been hijacked")
+
+// GetCurrentConcurrency returns a number of currently served
+// connections.
+//
+// This function is intended be used by monitoring systems
+func (s *Server) GetCurrentConcurrency() uint32 {
+ return atomic.LoadUint32(&s.concurrency)
+}
+
+// GetOpenConnectionsCount returns a number of opened connections.
+//
+// This function is intended be used by monitoring systems
+func (s *Server) GetOpenConnectionsCount() int32 {
+ if atomic.LoadInt32(&s.stop) == 0 {
+ // Decrement by one to avoid reporting the extra open value that gets
+ // counted while the server is listening.
+ return atomic.LoadInt32(&s.open) - 1
+ }
+ // This is not perfect, because s.stop could have changed to zero
+ // before we load the value of s.open. However, in the common case
+ // this avoids underreporting open connections by 1 during server shutdown.
+ return atomic.LoadInt32(&s.open)
+}
+
+func (s *Server) getConcurrency() int {
+ n := s.Concurrency
+ if n <= 0 {
+ n = DefaultConcurrency
+ }
+ return n
+}
+
+var globalConnID uint64
+
+func nextConnID() uint64 {
+ return atomic.AddUint64(&globalConnID, 1)
+}
+
+// DefaultMaxRequestBodySize is the maximum request body size the server
+// reads by default.
+//
+// See Server.MaxRequestBodySize for details.
+const DefaultMaxRequestBodySize = 4 * 1024 * 1024
+
+func (s *Server) idleTimeout() time.Duration {
+ if s.IdleTimeout != 0 {
+ return s.IdleTimeout
+ }
+ return s.ReadTimeout
+}
+
+func (s *Server) serveConnCleanup() {
+ atomic.AddInt32(&s.open, -1)
+ atomic.AddUint32(&s.concurrency, ^uint32(0))
+}
+
+func (s *Server) serveConn(c net.Conn) (err error) {
+ defer s.serveConnCleanup()
+ atomic.AddUint32(&s.concurrency, 1)
+
+ var proto string
+ if proto, err = s.getNextProto(c); err != nil {
+ return
+ }
+ if handler, ok := s.nextProtos[proto]; ok {
+ // Remove read or write deadlines that might have previously been set.
+ // The next handler is responsible for setting its own deadlines.
+ if s.ReadTimeout > 0 || s.WriteTimeout > 0 {
+ if err := c.SetDeadline(zeroTime); err != nil {
+ panic(fmt.Sprintf("BUG: error in SetDeadline(zeroTime): %v", err))
+ }
+ }
+
+ return handler(c)
+ }
+
+ serverName := s.getServerName()
+ connRequestNum := uint64(0)
+ connID := nextConnID()
+ connTime := time.Now()
+ maxRequestBodySize := s.MaxRequestBodySize
+ if maxRequestBodySize <= 0 {
+ maxRequestBodySize = DefaultMaxRequestBodySize
+ }
+ writeTimeout := s.WriteTimeout
+ previousWriteTimeout := time.Duration(0)
+
+ ctx := s.acquireCtx(c)
+ ctx.connTime = connTime
+ isTLS := ctx.IsTLS()
+ var (
+ br *bufio.Reader
+ bw *bufio.Writer
+
+ timeoutResponse *Response
+ hijackHandler HijackHandler
+ hijackNoResponse bool
+
+ connectionClose bool
+
+ continueReadingRequest = true
+ )
+ for {
+ connRequestNum++
+
+ // If this is a keep-alive connection set the idle timeout.
+ if connRequestNum > 1 {
+ if d := s.idleTimeout(); d > 0 {
+ if err := c.SetReadDeadline(time.Now().Add(d)); err != nil {
+ break
+ }
+ }
+ }
+
+ if !s.ReduceMemoryUsage || br != nil {
+ if br == nil {
+ br = acquireReader(ctx)
+ }
+
+ // If this is a keep-alive connection we want to try and read the first bytes
+ // within the idle time.
+ if connRequestNum > 1 {
+ var b []byte
+ b, err = br.Peek(1)
+ if len(b) == 0 {
+ // If reading from a keep-alive connection returns nothing it means
+ // the connection was closed (either timeout or from the other side).
+ if err != io.EOF {
+ err = ErrNothingRead{err}
+ }
+ }
+ }
+ } else {
+ // If this is a keep-alive connection acquireByteReader will try to peek
+ // a couple of bytes already so the idle timeout will already be used.
+ br, err = acquireByteReader(&ctx)
+ }
+
+ ctx.Request.isTLS = isTLS
+ ctx.Response.Header.noDefaultContentType = s.NoDefaultContentType
+ ctx.Response.Header.noDefaultDate = s.NoDefaultDate
+
+ // Secure header error logs configuration
+ ctx.Request.Header.secureErrorLogMessage = s.SecureErrorLogMessage
+ ctx.Response.Header.secureErrorLogMessage = s.SecureErrorLogMessage
+ ctx.Request.secureErrorLogMessage = s.SecureErrorLogMessage
+ ctx.Response.secureErrorLogMessage = s.SecureErrorLogMessage
+
+ if err == nil {
+ s.setState(c, StateActive)
+
+ if s.ReadTimeout > 0 {
+ if err := c.SetReadDeadline(time.Now().Add(s.ReadTimeout)); err != nil {
+ break
+ }
+ } else if s.IdleTimeout > 0 && connRequestNum > 1 {
+ // If this was an idle connection and the server has an IdleTimeout but
+ // no ReadTimeout then we should remove the ReadTimeout.
+ if err := c.SetReadDeadline(zeroTime); err != nil {
+ break
+ }
+ }
+ if s.DisableHeaderNamesNormalizing {
+ ctx.Request.Header.DisableNormalizing()
+ ctx.Response.Header.DisableNormalizing()
+ }
+
+ // Reading Headers.
+ //
+ // If we have pipeline response in the outgoing buffer,
+ // we only want to try and read the next headers once.
+ // If we have to wait for the next request we flush the
+ // outgoing buffer first so it doesn't have to wait.
+ if bw != nil && bw.Buffered() > 0 {
+ err = ctx.Request.Header.readLoop(br, false)
+ if err == errNeedMore {
+ err = bw.Flush()
+ if err != nil {
+ break
+ }
+
+ err = ctx.Request.Header.Read(br)
+ }
+ } else {
+ err = ctx.Request.Header.Read(br)
+ }
+
+ if err == nil {
+ if onHdrRecv := s.HeaderReceived; onHdrRecv != nil {
+ reqConf := onHdrRecv(&ctx.Request.Header)
+ if reqConf.ReadTimeout > 0 {
+ deadline := time.Now().Add(reqConf.ReadTimeout)
+ if err := c.SetReadDeadline(deadline); err != nil {
+ panic(fmt.Sprintf("BUG: error in SetReadDeadline(%v): %v", deadline, err))
+ }
+ }
+ switch {
+ case reqConf.MaxRequestBodySize > 0:
+ maxRequestBodySize = reqConf.MaxRequestBodySize
+ case s.MaxRequestBodySize > 0:
+ maxRequestBodySize = s.MaxRequestBodySize
+ default:
+ maxRequestBodySize = DefaultMaxRequestBodySize
+ }
+ if reqConf.WriteTimeout > 0 {
+ writeTimeout = reqConf.WriteTimeout
+ } else {
+ writeTimeout = s.WriteTimeout
+ }
+ }
+ // read body
+ if s.StreamRequestBody {
+ err = ctx.Request.readBodyStream(br, maxRequestBodySize, s.GetOnly, !s.DisablePreParseMultipartForm)
+ } else {
+ err = ctx.Request.readLimitBody(br, maxRequestBodySize, s.GetOnly, !s.DisablePreParseMultipartForm)
+ }
+ }
+
+ if (s.ReduceMemoryUsage && br.Buffered() == 0) || err != nil {
+ releaseReader(s, br)
+ br = nil
+ }
+ }
+
+ if err != nil {
+ if err == io.EOF {
+ err = nil
+ } else if nr, ok := err.(ErrNothingRead); ok {
+ if connRequestNum > 1 {
+ // This is not the first request and we haven't read a single byte
+ // of a new request yet. This means it's just a keep-alive connection
+ // closing down either because the remote closed it or because
+ // or a read timeout on our side. Either way just close the connection
+ // and don't return any error response.
+ err = nil
+ } else {
+ err = nr.error
+ }
+ }
+
+ if err != nil {
+ bw = s.writeErrorResponse(bw, ctx, serverName, err)
+ }
+ break
+ }
+
+ // 'Expect: 100-continue' request handling.
+ // See https://www.w3.org/Protocols/rfc2616/rfc2616-sec8.html#sec8.2.3 for details.
+ if ctx.Request.MayContinue() {
+
+ // Allow the ability to deny reading the incoming request body
+ if s.ContinueHandler != nil {
+ if continueReadingRequest = s.ContinueHandler(&ctx.Request.Header); !continueReadingRequest {
+ if br != nil {
+ br.Reset(ctx.c)
+ }
+
+ ctx.SetStatusCode(StatusExpectationFailed)
+ }
+ }
+
+ if continueReadingRequest {
+ if bw == nil {
+ bw = acquireWriter(ctx)
+ }
+
+ // Send 'HTTP/1.1 100 Continue' response.
+ _, err = bw.Write(strResponseContinue)
+ if err != nil {
+ break
+ }
+ err = bw.Flush()
+ if err != nil {
+ break
+ }
+ if s.ReduceMemoryUsage {
+ releaseWriter(s, bw)
+ bw = nil
+ }
+
+ // Read request body.
+ if br == nil {
+ br = acquireReader(ctx)
+ }
+
+ if s.StreamRequestBody {
+ err = ctx.Request.ContinueReadBodyStream(br, maxRequestBodySize, !s.DisablePreParseMultipartForm)
+ } else {
+ err = ctx.Request.ContinueReadBody(br, maxRequestBodySize, !s.DisablePreParseMultipartForm)
+ }
+ if (s.ReduceMemoryUsage && br.Buffered() == 0) || err != nil {
+ releaseReader(s, br)
+ br = nil
+ }
+ if err != nil {
+ bw = s.writeErrorResponse(bw, ctx, serverName, err)
+ break
+ }
+ }
+ }
+
+ // store req.ConnectionClose so even if it was changed inside of handler
+ connectionClose = s.DisableKeepalive || ctx.Request.Header.ConnectionClose()
+
+ if serverName != "" {
+ ctx.Response.Header.SetServer(serverName)
+ }
+ ctx.connID = connID
+ ctx.connRequestNum = connRequestNum
+ ctx.time = time.Now()
+
+ // If a client denies a request the handler should not be called
+ if continueReadingRequest {
+ s.Handler(ctx)
+ }
+
+ timeoutResponse = ctx.timeoutResponse
+ if timeoutResponse != nil {
+ // Acquire a new ctx because the old one will still be in use by the timeout out handler.
+ ctx = s.acquireCtx(c)
+ timeoutResponse.CopyTo(&ctx.Response)
+ }
+
+ if ctx.IsHead() {
+ ctx.Response.SkipBody = true
+ }
+
+ hijackHandler = ctx.hijackHandler
+ ctx.hijackHandler = nil
+ hijackNoResponse = ctx.hijackNoResponse && hijackHandler != nil
+ ctx.hijackNoResponse = false
+
+ if writeTimeout > 0 {
+ if err := c.SetWriteDeadline(time.Now().Add(writeTimeout)); err != nil {
+ panic(fmt.Sprintf("BUG: error in SetWriteDeadline(%v): %v", writeTimeout, err))
+ }
+ previousWriteTimeout = writeTimeout
+ } else if previousWriteTimeout > 0 {
+ // We don't want a write timeout but we previously set one, remove it.
+ if err := c.SetWriteDeadline(zeroTime); err != nil {
+ panic(fmt.Sprintf("BUG: error in SetWriteDeadline(zeroTime): %v", err))
+ }
+ previousWriteTimeout = 0
+ }
+
+ connectionClose = connectionClose ||
+ (s.MaxRequestsPerConn > 0 && connRequestNum >= uint64(s.MaxRequestsPerConn)) ||
+ ctx.Response.Header.ConnectionClose() ||
+ (s.CloseOnShutdown && atomic.LoadInt32(&s.stop) == 1)
+ if connectionClose {
+ ctx.Response.Header.SetConnectionClose()
+ } else if !ctx.Request.Header.IsHTTP11() {
+ // Set 'Connection: keep-alive' response header for HTTP/1.0 request.
+ // There is no need in setting this header for http/1.1, since in http/1.1
+ // connections are keep-alive by default.
+ ctx.Response.Header.setNonSpecial(strConnection, strKeepAlive)
+ }
+
+ if serverName != "" && len(ctx.Response.Header.Server()) == 0 {
+ ctx.Response.Header.SetServer(serverName)
+ }
+
+ if !hijackNoResponse {
+ if bw == nil {
+ bw = acquireWriter(ctx)
+ }
+ if err = writeResponse(ctx, bw); err != nil {
+ break
+ }
+
+ // Only flush the writer if we don't have another request in the pipeline.
+ // This is a big of an ugly optimization for https://www.techempower.com/benchmarks/
+ // This benchmark will send 16 pipelined requests. It is faster to pack as many responses
+ // in a TCP packet and send it back at once than waiting for a flush every request.
+ // In real world circumstances this behaviour could be argued as being wrong.
+ if br == nil || br.Buffered() == 0 || connectionClose {
+ err = bw.Flush()
+ if err != nil {
+ break
+ }
+ }
+ if connectionClose {
+ break
+ }
+ if s.ReduceMemoryUsage && hijackHandler == nil {
+ releaseWriter(s, bw)
+ bw = nil
+ }
+ }
+
+ if hijackHandler != nil {
+ var hjr io.Reader = c
+ if br != nil {
+ hjr = br
+ br = nil
+ }
+ if bw != nil {
+ err = bw.Flush()
+ if err != nil {
+ break
+ }
+ releaseWriter(s, bw)
+ bw = nil
+ }
+ err = c.SetDeadline(zeroTime)
+ if err != nil {
+ break
+ }
+ go hijackConnHandler(ctx, hjr, c, s, hijackHandler)
+ err = errHijacked
+ break
+ }
+
+ if ctx.Request.bodyStream != nil {
+ if rs, ok := ctx.Request.bodyStream.(*requestStream); ok {
+ releaseRequestStream(rs)
+ }
+ ctx.Request.bodyStream = nil
+ }
+
+ s.setState(c, StateIdle)
+ ctx.userValues.Reset()
+ ctx.Request.Reset()
+ ctx.Response.Reset()
+
+ if atomic.LoadInt32(&s.stop) == 1 {
+ err = nil
+ break
+ }
+ }
+
+ if br != nil {
+ releaseReader(s, br)
+ }
+ if bw != nil {
+ releaseWriter(s, bw)
+ }
+ if hijackHandler == nil {
+ s.releaseCtx(ctx)
+ }
+
+ return
+}
+
+func (s *Server) setState(nc net.Conn, state ConnState) {
+ s.trackConn(nc, state)
+ if hook := s.ConnState; hook != nil {
+ hook(nc, state)
+ }
+}
+
+func hijackConnHandler(ctx *RequestCtx, r io.Reader, c net.Conn, s *Server, h HijackHandler) {
+ hjc := s.acquireHijackConn(r, c)
+ h(hjc)
+
+ if br, ok := r.(*bufio.Reader); ok {
+ releaseReader(s, br)
+ }
+ if !s.KeepHijackedConns {
+ c.Close()
+ s.releaseHijackConn(hjc)
+ }
+ s.releaseCtx(ctx)
+}
+
+func (s *Server) acquireHijackConn(r io.Reader, c net.Conn) *hijackConn {
+ v := s.hijackConnPool.Get()
+ if v == nil {
+ hjc := &hijackConn{
+ Conn: c,
+ r: r,
+ s: s,
+ }
+ return hjc
+ }
+ hjc := v.(*hijackConn)
+ hjc.Conn = c
+ hjc.r = r
+ return hjc
+}
+
+func (s *Server) releaseHijackConn(hjc *hijackConn) {
+ hjc.Conn = nil
+ hjc.r = nil
+ s.hijackConnPool.Put(hjc)
+}
+
+type hijackConn struct {
+ net.Conn
+ r io.Reader
+ s *Server
+}
+
+func (c *hijackConn) UnsafeConn() net.Conn {
+ return c.Conn
+}
+
+func (c *hijackConn) Read(p []byte) (int, error) {
+ return c.r.Read(p)
+}
+
+func (c *hijackConn) Close() error {
+ if !c.s.KeepHijackedConns {
+ // when we do not keep hijacked connections,
+ // it is closed in hijackConnHandler.
+ return nil
+ }
+
+ return c.Conn.Close()
+}
+
+// LastTimeoutErrorResponse returns the last timeout response set
+// via TimeoutError* call.
+//
+// This function is intended for custom server implementations.
+func (ctx *RequestCtx) LastTimeoutErrorResponse() *Response {
+ return ctx.timeoutResponse
+}
+
+func writeResponse(ctx *RequestCtx, w *bufio.Writer) error {
+ if ctx.timeoutResponse != nil {
+ return errors.New("cannot write timed out response")
+ }
+ err := ctx.Response.Write(w)
+
+ return err
+}
+
+const (
+ defaultReadBufferSize = 4096
+ defaultWriteBufferSize = 4096
+)
+
+func acquireByteReader(ctxP **RequestCtx) (*bufio.Reader, error) {
+ ctx := *ctxP
+ s := ctx.s
+ c := ctx.c
+ s.releaseCtx(ctx)
+
+ // Make GC happy, so it could garbage collect ctx while we wait for the
+ // next request.
+ ctx = nil
+ *ctxP = nil
+
+ var b [1]byte
+ n, err := c.Read(b[:])
+
+ ctx = s.acquireCtx(c)
+ *ctxP = ctx
+ if err != nil {
+ // Treat all errors as EOF on unsuccessful read
+ // of the first request byte.
+ return nil, io.EOF
+ }
+ if n != 1 {
+ // developer sanity-check
+ panic("BUG: Reader must return at least one byte")
+ }
+
+ ctx.fbr.c = c
+ ctx.fbr.ch = b[0]
+ ctx.fbr.byteRead = false
+ r := acquireReader(ctx)
+ r.Reset(&ctx.fbr)
+ return r, nil
+}
+
+func acquireReader(ctx *RequestCtx) *bufio.Reader {
+ v := ctx.s.readerPool.Get()
+ if v == nil {
+ n := ctx.s.ReadBufferSize
+ if n <= 0 {
+ n = defaultReadBufferSize
+ }
+ return bufio.NewReaderSize(ctx.c, n)
+ }
+ r := v.(*bufio.Reader)
+ r.Reset(ctx.c)
+ return r
+}
+
+func releaseReader(s *Server, r *bufio.Reader) {
+ s.readerPool.Put(r)
+}
+
+func acquireWriter(ctx *RequestCtx) *bufio.Writer {
+ v := ctx.s.writerPool.Get()
+ if v == nil {
+ n := ctx.s.WriteBufferSize
+ if n <= 0 {
+ n = defaultWriteBufferSize
+ }
+ return bufio.NewWriterSize(ctx.c, n)
+ }
+ w := v.(*bufio.Writer)
+ w.Reset(ctx.c)
+ return w
+}
+
+func releaseWriter(s *Server, w *bufio.Writer) {
+ s.writerPool.Put(w)
+}
+
+func (s *Server) acquireCtx(c net.Conn) (ctx *RequestCtx) {
+ v := s.ctxPool.Get()
+ if v == nil {
+ keepBodyBuffer := !s.ReduceMemoryUsage
+
+ ctx = new(RequestCtx)
+ ctx.Request.keepBodyBuffer = keepBodyBuffer
+ ctx.Response.keepBodyBuffer = keepBodyBuffer
+ ctx.s = s
+ } else {
+ ctx = v.(*RequestCtx)
+ }
+ if s.FormValueFunc != nil {
+ ctx.formValueFunc = s.FormValueFunc
+ }
+ ctx.c = c
+
+ return ctx
+}
+
+// Init2 prepares ctx for passing to RequestHandler.
+//
+// conn is used only for determining local and remote addresses.
+//
+// This function is intended for custom Server implementations.
+// See https://github.com/valyala/httpteleport for details.
+func (ctx *RequestCtx) Init2(conn net.Conn, logger Logger, reduceMemoryUsage bool) {
+ ctx.c = conn
+ ctx.remoteAddr = nil
+ ctx.logger.logger = logger
+ ctx.connID = nextConnID()
+ ctx.s = fakeServer
+ ctx.connRequestNum = 0
+ ctx.connTime = time.Now()
+
+ keepBodyBuffer := !reduceMemoryUsage
+ ctx.Request.keepBodyBuffer = keepBodyBuffer
+ ctx.Response.keepBodyBuffer = keepBodyBuffer
+}
+
+// Init prepares ctx for passing to RequestHandler.
+//
+// remoteAddr and logger are optional. They are used by RequestCtx.Logger().
+//
+// This function is intended for custom Server implementations.
+func (ctx *RequestCtx) Init(req *Request, remoteAddr net.Addr, logger Logger) {
+ if remoteAddr == nil {
+ remoteAddr = zeroTCPAddr
+ }
+ c := &fakeAddrer{
+ laddr: zeroTCPAddr,
+ raddr: remoteAddr,
+ }
+ if logger == nil {
+ logger = defaultLogger
+ }
+ ctx.Init2(c, logger, true)
+ req.CopyTo(&ctx.Request)
+}
+
+// Deadline returns the time when work done on behalf of this context
+// should be canceled. Deadline returns ok==false when no deadline is
+// set. Successive calls to Deadline return the same results.
+//
+// This method always returns 0, false and is only present to make
+// RequestCtx implement the context interface.
+func (ctx *RequestCtx) Deadline() (deadline time.Time, ok bool) {
+ return
+}
+
+// Done returns a channel that's closed when work done on behalf of this
+// context should be canceled. Done may return nil if this context can
+// never be canceled. Successive calls to Done return the same value.
+//
+// Note: Because creating a new channel for every request is just too expensive, so
+// RequestCtx.s.done is only closed when the server is shutting down
+func (ctx *RequestCtx) Done() <-chan struct{} {
+ return ctx.s.done
+}
+
+// Err returns a non-nil error value after Done is closed,
+// successive calls to Err return the same error.
+// If Done is not yet closed, Err returns nil.
+// If Done is closed, Err returns a non-nil error explaining why:
+// Canceled if the context was canceled (via server Shutdown)
+// or DeadlineExceeded if the context's deadline passed.
+//
+// Note: Because creating a new channel for every request is just too expensive, so
+// RequestCtx.s.done is only closed when the server is shutting down
+func (ctx *RequestCtx) Err() error {
+ select {
+ case <-ctx.s.done:
+ return context.Canceled
+ default:
+ return nil
+ }
+}
+
+// Value returns the value associated with this context for key, or nil
+// if no value is associated with key. Successive calls to Value with
+// the same key returns the same result.
+//
+// This method is present to make RequestCtx implement the context interface.
+// This method is the same as calling ctx.UserValue(key)
+func (ctx *RequestCtx) Value(key interface{}) interface{} {
+ return ctx.UserValue(key)
+}
+
+var fakeServer = &Server{
+ // Initialize concurrencyCh for TimeoutHandler
+ concurrencyCh: make(chan struct{}, DefaultConcurrency),
+}
+
+type fakeAddrer struct {
+ net.Conn
+ laddr net.Addr
+ raddr net.Addr
+}
+
+func (fa *fakeAddrer) RemoteAddr() net.Addr {
+ return fa.raddr
+}
+
+func (fa *fakeAddrer) LocalAddr() net.Addr {
+ return fa.laddr
+}
+
+func (fa *fakeAddrer) Read(p []byte) (int, error) {
+ // developer sanity-check
+ panic("BUG: unexpected Read call")
+}
+
+func (fa *fakeAddrer) Write(p []byte) (int, error) {
+ // developer sanity-check
+ panic("BUG: unexpected Write call")
+}
+
+func (fa *fakeAddrer) Close() error {
+ // developer sanity-check
+ panic("BUG: unexpected Close call")
+}
+
+func (s *Server) releaseCtx(ctx *RequestCtx) {
+ if ctx.timeoutResponse != nil {
+ // developer sanity-check
+ panic("BUG: cannot release timed out RequestCtx")
+ }
+
+ ctx.reset()
+ s.ctxPool.Put(ctx)
+}
+
+func (s *Server) getServerName() string {
+ serverName := s.Name
+ if serverName == "" {
+ if !s.NoDefaultServerHeader {
+ serverName = defaultServerName
+ }
+ }
+ return serverName
+}
+
+func (s *Server) writeFastError(w io.Writer, statusCode int, msg string) {
+ w.Write(formatStatusLine(nil, strHTTP11, statusCode, s2b(StatusMessage(statusCode)))) //nolint:errcheck
+
+ server := s.getServerName()
+ if server != "" {
+ server = fmt.Sprintf("Server: %s\r\n", server)
+ }
+ date := ""
+ if !s.NoDefaultDate {
+ serverDateOnce.Do(updateServerDate)
+ date = fmt.Sprintf("Date: %s\r\n", serverDate.Load())
+ }
+
+ fmt.Fprintf(w, "Connection: close\r\n"+
+ server+
+ date+
+ "Content-Type: text/plain\r\n"+
+ "Content-Length: %d\r\n"+
+ "\r\n"+
+ "%s",
+ len(msg), msg)
+}
+
+func defaultErrorHandler(ctx *RequestCtx, err error) {
+ if _, ok := err.(*ErrSmallBuffer); ok {
+ ctx.Error("Too big request header", StatusRequestHeaderFieldsTooLarge)
+ } else if netErr, ok := err.(*net.OpError); ok && netErr.Timeout() {
+ ctx.Error("Request timeout", StatusRequestTimeout)
+ } else {
+ ctx.Error("Error when parsing request", StatusBadRequest)
+ }
+}
+
+func (s *Server) writeErrorResponse(bw *bufio.Writer, ctx *RequestCtx, serverName string, err error) *bufio.Writer {
+ errorHandler := defaultErrorHandler
+ if s.ErrorHandler != nil {
+ errorHandler = s.ErrorHandler
+ }
+
+ errorHandler(ctx, err)
+
+ if serverName != "" {
+ ctx.Response.Header.SetServer(serverName)
+ }
+ ctx.SetConnectionClose()
+ if bw == nil {
+ bw = acquireWriter(ctx)
+ }
+
+ writeResponse(ctx, bw) //nolint:errcheck
+ ctx.Response.Reset()
+ bw.Flush()
+
+ return bw
+}
+
+func (s *Server) trackConn(c net.Conn, state ConnState) {
+ s.idleConnsMu.Lock()
+ switch state {
+ case StateIdle:
+ if s.idleConns == nil {
+ s.idleConns = make(map[net.Conn]time.Time)
+ }
+ s.idleConns[c] = time.Now()
+ case StateNew:
+ if s.idleConns == nil {
+ s.idleConns = make(map[net.Conn]time.Time)
+ }
+ // Count the connection as Idle after 5 seconds.
+ // Same as net/http.Server: https://github.com/golang/go/blob/85d7bab91d9a3ed1f76842e4328973ea75efef54/src/net/http/server.go#L2834-L2836
+ s.idleConns[c] = time.Now().Add(time.Second * 5)
+
+ default:
+ delete(s.idleConns, c)
+ }
+ s.idleConnsMu.Unlock()
+}
+
+func (s *Server) closeIdleConns() {
+ s.idleConnsMu.Lock()
+ now := time.Now()
+ for c, t := range s.idleConns {
+ if now.Sub(t) >= 0 {
+ _ = c.Close()
+ delete(s.idleConns, c)
+ }
+ }
+ s.idleConnsMu.Unlock()
+}
+
+// A ConnState represents the state of a client connection to a server.
+// It's used by the optional Server.ConnState hook.
+type ConnState int
+
+const (
+ // StateNew represents a new connection that is expected to
+ // send a request immediately. Connections begin at this
+ // state and then transition to either StateActive or
+ // StateClosed.
+ StateNew ConnState = iota
+
+ // StateActive represents a connection that has read 1 or more
+ // bytes of a request. The Server.ConnState hook for
+ // StateActive fires before the request has entered a handler
+ // and doesn't fire again until the request has been
+ // handled. After the request is handled, the state
+ // transitions to StateClosed, StateHijacked, or StateIdle.
+ // For HTTP/2, StateActive fires on the transition from zero
+ // to one active request, and only transitions away once all
+ // active requests are complete. That means that ConnState
+ // cannot be used to do per-request work; ConnState only notes
+ // the overall state of the connection.
+ StateActive
+
+ // StateIdle represents a connection that has finished
+ // handling a request and is in the keep-alive state, waiting
+ // for a new request. Connections transition from StateIdle
+ // to either StateActive or StateClosed.
+ StateIdle
+
+ // StateHijacked represents a hijacked connection.
+ // This is a terminal state. It does not transition to StateClosed.
+ StateHijacked
+
+ // StateClosed represents a closed connection.
+ // This is a terminal state. Hijacked connections do not
+ // transition to StateClosed.
+ StateClosed
+)
+
+var stateName = map[ConnState]string{
+ StateNew: "new",
+ StateActive: "active",
+ StateIdle: "idle",
+ StateHijacked: "hijacked",
+ StateClosed: "closed",
+}
+
+func (c ConnState) String() string {
+ return stateName[c]
+}
diff --git a/vendor/github.com/valyala/fasthttp/stackless/doc.go b/vendor/github.com/valyala/fasthttp/stackless/doc.go
new file mode 100644
index 0000000..8c0cc49
--- /dev/null
+++ b/vendor/github.com/valyala/fasthttp/stackless/doc.go
@@ -0,0 +1,3 @@
+// Package stackless provides functionality that may save stack space
+// for high number of concurrently running goroutines.
+package stackless
diff --git a/vendor/github.com/valyala/fasthttp/stackless/func.go b/vendor/github.com/valyala/fasthttp/stackless/func.go
new file mode 100644
index 0000000..70521e1
--- /dev/null
+++ b/vendor/github.com/valyala/fasthttp/stackless/func.go
@@ -0,0 +1,80 @@
+package stackless
+
+import (
+ "runtime"
+ "sync"
+)
+
+// NewFunc returns stackless wrapper for the function f.
+//
+// Unlike f, the returned stackless wrapper doesn't use stack space
+// on the goroutine that calls it.
+// The wrapper may save a lot of stack space if the following conditions
+// are met:
+//
+// - f doesn't contain blocking calls on network, I/O or channels;
+// - f uses a lot of stack space;
+// - the wrapper is called from high number of concurrent goroutines.
+//
+// The stackless wrapper returns false if the call cannot be processed
+// at the moment due to high load.
+func NewFunc(f func(ctx interface{})) func(ctx interface{}) bool {
+ if f == nil {
+ // developer sanity-check
+ panic("BUG: f cannot be nil")
+ }
+
+ funcWorkCh := make(chan *funcWork, runtime.GOMAXPROCS(-1)*2048)
+ onceInit := func() {
+ n := runtime.GOMAXPROCS(-1)
+ for i := 0; i < n; i++ {
+ go funcWorker(funcWorkCh, f)
+ }
+ }
+ var once sync.Once
+
+ return func(ctx interface{}) bool {
+ once.Do(onceInit)
+ fw := getFuncWork()
+ fw.ctx = ctx
+
+ select {
+ case funcWorkCh <- fw:
+ default:
+ putFuncWork(fw)
+ return false
+ }
+ <-fw.done
+ putFuncWork(fw)
+ return true
+ }
+}
+
+func funcWorker(funcWorkCh <-chan *funcWork, f func(ctx interface{})) {
+ for fw := range funcWorkCh {
+ f(fw.ctx)
+ fw.done <- struct{}{}
+ }
+}
+
+func getFuncWork() *funcWork {
+ v := funcWorkPool.Get()
+ if v == nil {
+ v = &funcWork{
+ done: make(chan struct{}, 1),
+ }
+ }
+ return v.(*funcWork)
+}
+
+func putFuncWork(fw *funcWork) {
+ fw.ctx = nil
+ funcWorkPool.Put(fw)
+}
+
+var funcWorkPool sync.Pool
+
+type funcWork struct {
+ ctx interface{}
+ done chan struct{}
+}
diff --git a/vendor/github.com/valyala/fasthttp/stackless/writer.go b/vendor/github.com/valyala/fasthttp/stackless/writer.go
new file mode 100644
index 0000000..347e464
--- /dev/null
+++ b/vendor/github.com/valyala/fasthttp/stackless/writer.go
@@ -0,0 +1,149 @@
+package stackless
+
+import (
+ "errors"
+ "fmt"
+ "io"
+ "sync"
+
+ "github.com/valyala/bytebufferpool"
+)
+
+// Writer is an interface stackless writer must conform to.
+//
+// The interface contains common subset for Writers from compress/* packages.
+type Writer interface {
+ Write(p []byte) (int, error)
+ Flush() error
+ Close() error
+ Reset(w io.Writer)
+}
+
+// NewWriterFunc must return new writer that will be wrapped into
+// stackless writer.
+type NewWriterFunc func(w io.Writer) Writer
+
+// NewWriter creates a stackless writer around a writer returned
+// from newWriter.
+//
+// The returned writer writes data to dstW.
+//
+// Writers that use a lot of stack space may be wrapped into stackless writer,
+// thus saving stack space for high number of concurrently running goroutines.
+func NewWriter(dstW io.Writer, newWriter NewWriterFunc) Writer {
+ w := &writer{
+ dstW: dstW,
+ }
+ w.zw = newWriter(&w.xw)
+ return w
+}
+
+type writer struct {
+ dstW io.Writer
+ zw Writer
+ xw xWriter
+
+ err error
+ n int
+
+ p []byte
+ op op
+}
+
+type op int
+
+const (
+ opWrite op = iota
+ opFlush
+ opClose
+ opReset
+)
+
+func (w *writer) Write(p []byte) (int, error) {
+ w.p = p
+ err := w.do(opWrite)
+ w.p = nil
+ return w.n, err
+}
+
+func (w *writer) Flush() error {
+ return w.do(opFlush)
+}
+
+func (w *writer) Close() error {
+ return w.do(opClose)
+}
+
+func (w *writer) Reset(dstW io.Writer) {
+ w.xw.Reset()
+ w.do(opReset) //nolint:errcheck
+ w.dstW = dstW
+}
+
+func (w *writer) do(op op) error {
+ w.op = op
+ if !stacklessWriterFunc(w) {
+ return errHighLoad
+ }
+ err := w.err
+ if err != nil {
+ return err
+ }
+ if w.xw.bb != nil && len(w.xw.bb.B) > 0 {
+ _, err = w.dstW.Write(w.xw.bb.B)
+ }
+ w.xw.Reset()
+
+ return err
+}
+
+var errHighLoad = errors.New("cannot compress data due to high load")
+
+var (
+ stacklessWriterFuncOnce sync.Once
+ stacklessWriterFuncFunc func(ctx interface{}) bool
+)
+
+func stacklessWriterFunc(ctx interface{}) bool {
+ stacklessWriterFuncOnce.Do(func() {
+ stacklessWriterFuncFunc = NewFunc(writerFunc)
+ })
+ return stacklessWriterFuncFunc(ctx)
+}
+
+func writerFunc(ctx interface{}) {
+ w := ctx.(*writer)
+ switch w.op {
+ case opWrite:
+ w.n, w.err = w.zw.Write(w.p)
+ case opFlush:
+ w.err = w.zw.Flush()
+ case opClose:
+ w.err = w.zw.Close()
+ case opReset:
+ w.zw.Reset(&w.xw)
+ w.err = nil
+ default:
+ panic(fmt.Sprintf("BUG: unexpected op: %d", w.op))
+ }
+}
+
+type xWriter struct {
+ bb *bytebufferpool.ByteBuffer
+}
+
+func (w *xWriter) Write(p []byte) (int, error) {
+ if w.bb == nil {
+ w.bb = bufferPool.Get()
+ }
+ return w.bb.Write(p)
+}
+
+func (w *xWriter) Reset() {
+ if w.bb != nil {
+ bufferPool.Put(w.bb)
+ w.bb = nil
+ }
+}
+
+var bufferPool bytebufferpool.Pool
diff --git a/vendor/github.com/valyala/fasthttp/status.go b/vendor/github.com/valyala/fasthttp/status.go
new file mode 100644
index 0000000..c88ba11
--- /dev/null
+++ b/vendor/github.com/valyala/fasthttp/status.go
@@ -0,0 +1,177 @@
+package fasthttp
+
+import (
+ "strconv"
+)
+
+const (
+ statusMessageMin = 100
+ statusMessageMax = 511
+)
+
+// HTTP status codes were stolen from net/http.
+const (
+ StatusContinue = 100 // RFC 7231, 6.2.1
+ StatusSwitchingProtocols = 101 // RFC 7231, 6.2.2
+ StatusProcessing = 102 // RFC 2518, 10.1
+ StatusEarlyHints = 103 // RFC 8297
+
+ StatusOK = 200 // RFC 7231, 6.3.1
+ StatusCreated = 201 // RFC 7231, 6.3.2
+ StatusAccepted = 202 // RFC 7231, 6.3.3
+ StatusNonAuthoritativeInfo = 203 // RFC 7231, 6.3.4
+ StatusNoContent = 204 // RFC 7231, 6.3.5
+ StatusResetContent = 205 // RFC 7231, 6.3.6
+ StatusPartialContent = 206 // RFC 7233, 4.1
+ StatusMultiStatus = 207 // RFC 4918, 11.1
+ StatusAlreadyReported = 208 // RFC 5842, 7.1
+ StatusIMUsed = 226 // RFC 3229, 10.4.1
+
+ StatusMultipleChoices = 300 // RFC 7231, 6.4.1
+ StatusMovedPermanently = 301 // RFC 7231, 6.4.2
+ StatusFound = 302 // RFC 7231, 6.4.3
+ StatusSeeOther = 303 // RFC 7231, 6.4.4
+ StatusNotModified = 304 // RFC 7232, 4.1
+ StatusUseProxy = 305 // RFC 7231, 6.4.5
+ _ = 306 // RFC 7231, 6.4.6 (Unused)
+ StatusTemporaryRedirect = 307 // RFC 7231, 6.4.7
+ StatusPermanentRedirect = 308 // RFC 7538, 3
+
+ StatusBadRequest = 400 // RFC 7231, 6.5.1
+ StatusUnauthorized = 401 // RFC 7235, 3.1
+ StatusPaymentRequired = 402 // RFC 7231, 6.5.2
+ StatusForbidden = 403 // RFC 7231, 6.5.3
+ StatusNotFound = 404 // RFC 7231, 6.5.4
+ StatusMethodNotAllowed = 405 // RFC 7231, 6.5.5
+ StatusNotAcceptable = 406 // RFC 7231, 6.5.6
+ StatusProxyAuthRequired = 407 // RFC 7235, 3.2
+ StatusRequestTimeout = 408 // RFC 7231, 6.5.7
+ StatusConflict = 409 // RFC 7231, 6.5.8
+ StatusGone = 410 // RFC 7231, 6.5.9
+ StatusLengthRequired = 411 // RFC 7231, 6.5.10
+ StatusPreconditionFailed = 412 // RFC 7232, 4.2
+ StatusRequestEntityTooLarge = 413 // RFC 7231, 6.5.11
+ StatusRequestURITooLong = 414 // RFC 7231, 6.5.12
+ StatusUnsupportedMediaType = 415 // RFC 7231, 6.5.13
+ StatusRequestedRangeNotSatisfiable = 416 // RFC 7233, 4.4
+ StatusExpectationFailed = 417 // RFC 7231, 6.5.14
+ StatusTeapot = 418 // RFC 7168, 2.3.3
+ StatusMisdirectedRequest = 421 // RFC 7540, 9.1.2
+ StatusUnprocessableEntity = 422 // RFC 4918, 11.2
+ StatusLocked = 423 // RFC 4918, 11.3
+ StatusFailedDependency = 424 // RFC 4918, 11.4
+ StatusUpgradeRequired = 426 // RFC 7231, 6.5.15
+ StatusPreconditionRequired = 428 // RFC 6585, 3
+ StatusTooManyRequests = 429 // RFC 6585, 4
+ StatusRequestHeaderFieldsTooLarge = 431 // RFC 6585, 5
+ StatusUnavailableForLegalReasons = 451 // RFC 7725, 3
+
+ StatusInternalServerError = 500 // RFC 7231, 6.6.1
+ StatusNotImplemented = 501 // RFC 7231, 6.6.2
+ StatusBadGateway = 502 // RFC 7231, 6.6.3
+ StatusServiceUnavailable = 503 // RFC 7231, 6.6.4
+ StatusGatewayTimeout = 504 // RFC 7231, 6.6.5
+ StatusHTTPVersionNotSupported = 505 // RFC 7231, 6.6.6
+ StatusVariantAlsoNegotiates = 506 // RFC 2295, 8.1
+ StatusInsufficientStorage = 507 // RFC 4918, 11.5
+ StatusLoopDetected = 508 // RFC 5842, 7.2
+ StatusNotExtended = 510 // RFC 2774, 7
+ StatusNetworkAuthenticationRequired = 511 // RFC 6585, 6
+)
+
+var (
+ unknownStatusCode = "Unknown Status Code"
+
+ statusMessages = []string{
+ StatusContinue: "Continue",
+ StatusSwitchingProtocols: "Switching Protocols",
+ StatusProcessing: "Processing",
+ StatusEarlyHints: "Early Hints",
+
+ StatusOK: "OK",
+ StatusCreated: "Created",
+ StatusAccepted: "Accepted",
+ StatusNonAuthoritativeInfo: "Non-Authoritative Information",
+ StatusNoContent: "No Content",
+ StatusResetContent: "Reset Content",
+ StatusPartialContent: "Partial Content",
+ StatusMultiStatus: "Multi-Status",
+ StatusAlreadyReported: "Already Reported",
+ StatusIMUsed: "IM Used",
+
+ StatusMultipleChoices: "Multiple Choices",
+ StatusMovedPermanently: "Moved Permanently",
+ StatusFound: "Found",
+ StatusSeeOther: "See Other",
+ StatusNotModified: "Not Modified",
+ StatusUseProxy: "Use Proxy",
+ StatusTemporaryRedirect: "Temporary Redirect",
+ StatusPermanentRedirect: "Permanent Redirect",
+
+ StatusBadRequest: "Bad Request",
+ StatusUnauthorized: "Unauthorized",
+ StatusPaymentRequired: "Payment Required",
+ StatusForbidden: "Forbidden",
+ StatusNotFound: "Not Found",
+ StatusMethodNotAllowed: "Method Not Allowed",
+ StatusNotAcceptable: "Not Acceptable",
+ StatusProxyAuthRequired: "Proxy Authentication Required",
+ StatusRequestTimeout: "Request Timeout",
+ StatusConflict: "Conflict",
+ StatusGone: "Gone",
+ StatusLengthRequired: "Length Required",
+ StatusPreconditionFailed: "Precondition Failed",
+ StatusRequestEntityTooLarge: "Request Entity Too Large",
+ StatusRequestURITooLong: "Request URI Too Long",
+ StatusUnsupportedMediaType: "Unsupported Media Type",
+ StatusRequestedRangeNotSatisfiable: "Requested Range Not Satisfiable",
+ StatusExpectationFailed: "Expectation Failed",
+ StatusTeapot: "I'm a teapot",
+ StatusMisdirectedRequest: "Misdirected Request",
+ StatusUnprocessableEntity: "Unprocessable Entity",
+ StatusLocked: "Locked",
+ StatusFailedDependency: "Failed Dependency",
+ StatusUpgradeRequired: "Upgrade Required",
+ StatusPreconditionRequired: "Precondition Required",
+ StatusTooManyRequests: "Too Many Requests",
+ StatusRequestHeaderFieldsTooLarge: "Request Header Fields Too Large",
+ StatusUnavailableForLegalReasons: "Unavailable For Legal Reasons",
+
+ StatusInternalServerError: "Internal Server Error",
+ StatusNotImplemented: "Not Implemented",
+ StatusBadGateway: "Bad Gateway",
+ StatusServiceUnavailable: "Service Unavailable",
+ StatusGatewayTimeout: "Gateway Timeout",
+ StatusHTTPVersionNotSupported: "HTTP Version Not Supported",
+ StatusVariantAlsoNegotiates: "Variant Also Negotiates",
+ StatusInsufficientStorage: "Insufficient Storage",
+ StatusLoopDetected: "Loop Detected",
+ StatusNotExtended: "Not Extended",
+ StatusNetworkAuthenticationRequired: "Network Authentication Required",
+ }
+)
+
+// StatusMessage returns HTTP status message for the given status code.
+func StatusMessage(statusCode int) string {
+ if statusCode < statusMessageMin || statusCode > statusMessageMax {
+ return unknownStatusCode
+ }
+
+ if s := statusMessages[statusCode]; s != "" {
+ return s
+ }
+ return unknownStatusCode
+}
+
+func formatStatusLine(dst []byte, protocol []byte, statusCode int, statusText []byte) []byte {
+ dst = append(dst, protocol...)
+ dst = append(dst, ' ')
+ dst = strconv.AppendInt(dst, int64(statusCode), 10)
+ dst = append(dst, ' ')
+ if len(statusText) == 0 {
+ dst = append(dst, s2b(StatusMessage(statusCode))...)
+ } else {
+ dst = append(dst, statusText...)
+ }
+ return append(dst, strCRLF...)
+}
diff --git a/vendor/github.com/valyala/fasthttp/stream.go b/vendor/github.com/valyala/fasthttp/stream.go
new file mode 100644
index 0000000..aa23b1a
--- /dev/null
+++ b/vendor/github.com/valyala/fasthttp/stream.go
@@ -0,0 +1,54 @@
+package fasthttp
+
+import (
+ "bufio"
+ "io"
+ "sync"
+
+ "github.com/valyala/fasthttp/fasthttputil"
+)
+
+// StreamWriter must write data to w.
+//
+// Usually StreamWriter writes data to w in a loop (aka 'data streaming').
+//
+// StreamWriter must return immediately if w returns error.
+//
+// Since the written data is buffered, do not forget calling w.Flush
+// when the data must be propagated to reader.
+type StreamWriter func(w *bufio.Writer)
+
+// NewStreamReader returns a reader, which replays all the data generated by sw.
+//
+// The returned reader may be passed to Response.SetBodyStream.
+//
+// Close must be called on the returned reader after all the required data
+// has been read. Otherwise goroutine leak may occur.
+//
+// See also Response.SetBodyStreamWriter.
+func NewStreamReader(sw StreamWriter) io.ReadCloser {
+ pc := fasthttputil.NewPipeConns()
+ pw := pc.Conn1()
+ pr := pc.Conn2()
+
+ var bw *bufio.Writer
+ v := streamWriterBufPool.Get()
+ if v == nil {
+ bw = bufio.NewWriter(pw)
+ } else {
+ bw = v.(*bufio.Writer)
+ bw.Reset(pw)
+ }
+
+ go func() {
+ sw(bw)
+ bw.Flush()
+ pw.Close()
+
+ streamWriterBufPool.Put(bw)
+ }()
+
+ return pr
+}
+
+var streamWriterBufPool sync.Pool
diff --git a/vendor/github.com/valyala/fasthttp/streaming.go b/vendor/github.com/valyala/fasthttp/streaming.go
new file mode 100644
index 0000000..119560a
--- /dev/null
+++ b/vendor/github.com/valyala/fasthttp/streaming.go
@@ -0,0 +1,113 @@
+package fasthttp
+
+import (
+ "bufio"
+ "bytes"
+ "io"
+ "sync"
+
+ "github.com/valyala/bytebufferpool"
+)
+
+type headerInterface interface {
+ ContentLength() int
+ ReadTrailer(r *bufio.Reader) error
+}
+
+type requestStream struct {
+ header headerInterface
+ prefetchedBytes *bytes.Reader
+ reader *bufio.Reader
+ totalBytesRead int
+ chunkLeft int
+}
+
+func (rs *requestStream) Read(p []byte) (int, error) {
+ var (
+ n int
+ err error
+ )
+ if rs.header.ContentLength() == -1 {
+ if rs.chunkLeft == 0 {
+ chunkSize, err := parseChunkSize(rs.reader)
+ if err != nil {
+ return 0, err
+ }
+ if chunkSize == 0 {
+ err = rs.header.ReadTrailer(rs.reader)
+ if err != nil && err != io.EOF {
+ return 0, err
+ }
+ return 0, io.EOF
+ }
+ rs.chunkLeft = chunkSize
+ }
+ bytesToRead := len(p)
+ if rs.chunkLeft < len(p) {
+ bytesToRead = rs.chunkLeft
+ }
+ n, err = rs.reader.Read(p[:bytesToRead])
+ rs.totalBytesRead += n
+ rs.chunkLeft -= n
+ if err == io.EOF {
+ err = io.ErrUnexpectedEOF
+ }
+ if err == nil && rs.chunkLeft == 0 {
+ err = readCrLf(rs.reader)
+ }
+ return n, err
+ }
+ if rs.totalBytesRead == rs.header.ContentLength() {
+ return 0, io.EOF
+ }
+ prefetchedSize := int(rs.prefetchedBytes.Size())
+ if prefetchedSize > rs.totalBytesRead {
+ left := prefetchedSize - rs.totalBytesRead
+ if len(p) > left {
+ p = p[:left]
+ }
+ n, err := rs.prefetchedBytes.Read(p)
+ rs.totalBytesRead += n
+ if n == rs.header.ContentLength() {
+ return n, io.EOF
+ }
+ return n, err
+ }
+ left := rs.header.ContentLength() - rs.totalBytesRead
+ if len(p) > left {
+ p = p[:left]
+ }
+ n, err = rs.reader.Read(p)
+ rs.totalBytesRead += n
+ if err != nil {
+ return n, err
+ }
+
+ if rs.totalBytesRead == rs.header.ContentLength() {
+ err = io.EOF
+ }
+ return n, err
+}
+
+func acquireRequestStream(b *bytebufferpool.ByteBuffer, r *bufio.Reader, h headerInterface) *requestStream {
+ rs := requestStreamPool.Get().(*requestStream)
+ rs.prefetchedBytes = bytes.NewReader(b.B)
+ rs.reader = r
+ rs.header = h
+ return rs
+}
+
+func releaseRequestStream(rs *requestStream) {
+ rs.prefetchedBytes = nil
+ rs.totalBytesRead = 0
+ rs.chunkLeft = 0
+ rs.reader = nil
+ rs.header = nil
+ requestStreamPool.Put(rs)
+}
+
+var requestStreamPool = sync.Pool{
+ New: func() interface{} {
+ return &requestStream{}
+ },
+}
diff --git a/vendor/github.com/valyala/fasthttp/strings.go b/vendor/github.com/valyala/fasthttp/strings.go
new file mode 100644
index 0000000..3cec8ed
--- /dev/null
+++ b/vendor/github.com/valyala/fasthttp/strings.go
@@ -0,0 +1,95 @@
+package fasthttp
+
+var (
+ defaultServerName = "fasthttp"
+ defaultUserAgent = "fasthttp"
+ defaultContentType = []byte("text/plain; charset=utf-8")
+)
+
+var (
+ strSlash = []byte("/")
+ strSlashSlash = []byte("//")
+ strSlashDotDot = []byte("/..")
+ strSlashDotSlash = []byte("/./")
+ strSlashDotDotSlash = []byte("/../")
+ strBackSlashDotDot = []byte(`\..`)
+ strBackSlashDotBackSlash = []byte(`\.\`)
+ strSlashDotDotBackSlash = []byte(`/..\`)
+ strBackSlashDotDotBackSlash = []byte(`\..\`)
+ strCRLF = []byte("\r\n")
+ strHTTP = []byte("http")
+ strHTTPS = []byte("https")
+ strHTTP10 = []byte("HTTP/1.0")
+ strHTTP11 = []byte("HTTP/1.1")
+ strColon = []byte(":")
+ strColonSlashSlash = []byte("://")
+ strColonSpace = []byte(": ")
+ strCommaSpace = []byte(", ")
+ strGMT = []byte("GMT")
+
+ strResponseContinue = []byte("HTTP/1.1 100 Continue\r\n\r\n")
+
+ strExpect = []byte(HeaderExpect)
+ strConnection = []byte(HeaderConnection)
+ strContentLength = []byte(HeaderContentLength)
+ strContentType = []byte(HeaderContentType)
+ strDate = []byte(HeaderDate)
+ strHost = []byte(HeaderHost)
+ strReferer = []byte(HeaderReferer)
+ strServer = []byte(HeaderServer)
+ strTransferEncoding = []byte(HeaderTransferEncoding)
+ strContentEncoding = []byte(HeaderContentEncoding)
+ strAcceptEncoding = []byte(HeaderAcceptEncoding)
+ strUserAgent = []byte(HeaderUserAgent)
+ strCookie = []byte(HeaderCookie)
+ strSetCookie = []byte(HeaderSetCookie)
+ strLocation = []byte(HeaderLocation)
+ strIfModifiedSince = []byte(HeaderIfModifiedSince)
+ strLastModified = []byte(HeaderLastModified)
+ strAcceptRanges = []byte(HeaderAcceptRanges)
+ strRange = []byte(HeaderRange)
+ strContentRange = []byte(HeaderContentRange)
+ strAuthorization = []byte(HeaderAuthorization)
+ strTE = []byte(HeaderTE)
+ strTrailer = []byte(HeaderTrailer)
+ strMaxForwards = []byte(HeaderMaxForwards)
+ strProxyConnection = []byte(HeaderProxyConnection)
+ strProxyAuthenticate = []byte(HeaderProxyAuthenticate)
+ strProxyAuthorization = []byte(HeaderProxyAuthorization)
+ strWWWAuthenticate = []byte(HeaderWWWAuthenticate)
+ strVary = []byte(HeaderVary)
+
+ strCookieExpires = []byte("expires")
+ strCookieDomain = []byte("domain")
+ strCookiePath = []byte("path")
+ strCookieHTTPOnly = []byte("HttpOnly")
+ strCookieSecure = []byte("secure")
+ strCookieMaxAge = []byte("max-age")
+ strCookieSameSite = []byte("SameSite")
+ strCookieSameSiteLax = []byte("Lax")
+ strCookieSameSiteStrict = []byte("Strict")
+ strCookieSameSiteNone = []byte("None")
+
+ strClose = []byte("close")
+ strGzip = []byte("gzip")
+ strBr = []byte("br")
+ strDeflate = []byte("deflate")
+ strKeepAlive = []byte("keep-alive")
+ strUpgrade = []byte("Upgrade")
+ strChunked = []byte("chunked")
+ strIdentity = []byte("identity")
+ str100Continue = []byte("100-continue")
+ strPostArgsContentType = []byte("application/x-www-form-urlencoded")
+ strDefaultContentType = []byte("application/octet-stream")
+ strMultipartFormData = []byte("multipart/form-data")
+ strBoundary = []byte("boundary")
+ strBytes = []byte("bytes")
+ strBasicSpace = []byte("Basic ")
+
+ strApplicationSlash = []byte("application/")
+ strImageSVG = []byte("image/svg")
+ strImageIcon = []byte("image/x-icon")
+ strFontSlash = []byte("font/")
+ strMultipartSlash = []byte("multipart/")
+ strTextSlash = []byte("text/")
+)
diff --git a/vendor/github.com/valyala/fasthttp/tcp.go b/vendor/github.com/valyala/fasthttp/tcp.go
new file mode 100644
index 0000000..7e80437
--- /dev/null
+++ b/vendor/github.com/valyala/fasthttp/tcp.go
@@ -0,0 +1,12 @@
+//go:build !windows
+
+package fasthttp
+
+import (
+ "errors"
+ "syscall"
+)
+
+func isConnectionReset(err error) bool {
+ return errors.Is(err, syscall.ECONNRESET)
+}
diff --git a/vendor/github.com/valyala/fasthttp/tcp_windows.go b/vendor/github.com/valyala/fasthttp/tcp_windows.go
new file mode 100644
index 0000000..d71950b
--- /dev/null
+++ b/vendor/github.com/valyala/fasthttp/tcp_windows.go
@@ -0,0 +1,10 @@
+package fasthttp
+
+import (
+ "errors"
+ "syscall"
+)
+
+func isConnectionReset(err error) bool {
+ return errors.Is(err, syscall.WSAECONNRESET)
+}
diff --git a/vendor/github.com/valyala/fasthttp/tcpdialer.go b/vendor/github.com/valyala/fasthttp/tcpdialer.go
new file mode 100644
index 0000000..5c7531e
--- /dev/null
+++ b/vendor/github.com/valyala/fasthttp/tcpdialer.go
@@ -0,0 +1,455 @@
+package fasthttp
+
+import (
+ "context"
+ "errors"
+ "net"
+ "strconv"
+ "sync"
+ "sync/atomic"
+ "time"
+)
+
+// Dial dials the given TCP addr using tcp4.
+//
+// This function has the following additional features comparing to net.Dial:
+//
+// - It reduces load on DNS resolver by caching resolved TCP addressed
+// for DNSCacheDuration.
+// - It dials all the resolved TCP addresses in round-robin manner until
+// connection is established. This may be useful if certain addresses
+// are temporarily unreachable.
+// - It returns ErrDialTimeout if connection cannot be established during
+// DefaultDialTimeout seconds. Use DialTimeout for customizing dial timeout.
+//
+// This dialer is intended for custom code wrapping before passing
+// to Client.Dial or HostClient.Dial.
+//
+// For instance, per-host counters and/or limits may be implemented
+// by such wrappers.
+//
+// The addr passed to the function must contain port. Example addr values:
+//
+// - foobar.baz:443
+// - foo.bar:80
+// - aaa.com:8080
+func Dial(addr string) (net.Conn, error) {
+ return defaultDialer.Dial(addr)
+}
+
+// DialTimeout dials the given TCP addr using tcp4 using the given timeout.
+//
+// This function has the following additional features comparing to net.Dial:
+//
+// - It reduces load on DNS resolver by caching resolved TCP addressed
+// for DNSCacheDuration.
+// - It dials all the resolved TCP addresses in round-robin manner until
+// connection is established. This may be useful if certain addresses
+// are temporarily unreachable.
+//
+// This dialer is intended for custom code wrapping before passing
+// to Client.Dial or HostClient.Dial.
+//
+// For instance, per-host counters and/or limits may be implemented
+// by such wrappers.
+//
+// The addr passed to the function must contain port. Example addr values:
+//
+// - foobar.baz:443
+// - foo.bar:80
+// - aaa.com:8080
+func DialTimeout(addr string, timeout time.Duration) (net.Conn, error) {
+ return defaultDialer.DialTimeout(addr, timeout)
+}
+
+// DialDualStack dials the given TCP addr using both tcp4 and tcp6.
+//
+// This function has the following additional features comparing to net.Dial:
+//
+// - It reduces load on DNS resolver by caching resolved TCP addressed
+// for DNSCacheDuration.
+// - It dials all the resolved TCP addresses in round-robin manner until
+// connection is established. This may be useful if certain addresses
+// are temporarily unreachable.
+// - It returns ErrDialTimeout if connection cannot be established during
+// DefaultDialTimeout seconds. Use DialDualStackTimeout for custom dial
+// timeout.
+//
+// This dialer is intended for custom code wrapping before passing
+// to Client.Dial or HostClient.Dial.
+//
+// For instance, per-host counters and/or limits may be implemented
+// by such wrappers.
+//
+// The addr passed to the function must contain port. Example addr values:
+//
+// - foobar.baz:443
+// - foo.bar:80
+// - aaa.com:8080
+func DialDualStack(addr string) (net.Conn, error) {
+ return defaultDialer.DialDualStack(addr)
+}
+
+// DialDualStackTimeout dials the given TCP addr using both tcp4 and tcp6
+// using the given timeout.
+//
+// This function has the following additional features comparing to net.Dial:
+//
+// - It reduces load on DNS resolver by caching resolved TCP addressed
+// for DNSCacheDuration.
+// - It dials all the resolved TCP addresses in round-robin manner until
+// connection is established. This may be useful if certain addresses
+// are temporarily unreachable.
+//
+// This dialer is intended for custom code wrapping before passing
+// to Client.Dial or HostClient.Dial.
+//
+// For instance, per-host counters and/or limits may be implemented
+// by such wrappers.
+//
+// The addr passed to the function must contain port. Example addr values:
+//
+// - foobar.baz:443
+// - foo.bar:80
+// - aaa.com:8080
+func DialDualStackTimeout(addr string, timeout time.Duration) (net.Conn, error) {
+ return defaultDialer.DialDualStackTimeout(addr, timeout)
+}
+
+var defaultDialer = &TCPDialer{Concurrency: 1000}
+
+// Resolver represents interface of the tcp resolver.
+type Resolver interface {
+ LookupIPAddr(context.Context, string) (names []net.IPAddr, err error)
+}
+
+// TCPDialer contains options to control a group of Dial calls.
+type TCPDialer struct {
+ // Concurrency controls the maximum number of concurrent Dials
+ // that can be performed using this object.
+ // Setting this to 0 means unlimited.
+ //
+ // WARNING: This can only be changed before the first Dial.
+ // Changes made after the first Dial will not affect anything.
+ Concurrency int
+
+ // LocalAddr is the local address to use when dialing an
+ // address.
+ // If nil, a local address is automatically chosen.
+ LocalAddr *net.TCPAddr
+
+ // This may be used to override DNS resolving policy, like this:
+ // var dialer = &fasthttp.TCPDialer{
+ // Resolver: &net.Resolver{
+ // PreferGo: true,
+ // StrictErrors: false,
+ // Dial: func (ctx context.Context, network, address string) (net.Conn, error) {
+ // d := net.Dialer{}
+ // return d.DialContext(ctx, "udp", "8.8.8.8:53")
+ // },
+ // },
+ // }
+ Resolver Resolver
+
+ // DNSCacheDuration may be used to override the default DNS cache duration (DefaultDNSCacheDuration)
+ DNSCacheDuration time.Duration
+
+ tcpAddrsMap sync.Map
+
+ concurrencyCh chan struct{}
+
+ once sync.Once
+}
+
+// Dial dials the given TCP addr using tcp4.
+//
+// This function has the following additional features comparing to net.Dial:
+//
+// - It reduces load on DNS resolver by caching resolved TCP addressed
+// for DNSCacheDuration.
+// - It dials all the resolved TCP addresses in round-robin manner until
+// connection is established. This may be useful if certain addresses
+// are temporarily unreachable.
+// - It returns ErrDialTimeout if connection cannot be established during
+// DefaultDialTimeout seconds. Use DialTimeout for customizing dial timeout.
+//
+// This dialer is intended for custom code wrapping before passing
+// to Client.Dial or HostClient.Dial.
+//
+// For instance, per-host counters and/or limits may be implemented
+// by such wrappers.
+//
+// The addr passed to the function must contain port. Example addr values:
+//
+// - foobar.baz:443
+// - foo.bar:80
+// - aaa.com:8080
+func (d *TCPDialer) Dial(addr string) (net.Conn, error) {
+ return d.dial(addr, false, DefaultDialTimeout)
+}
+
+// DialTimeout dials the given TCP addr using tcp4 using the given timeout.
+//
+// This function has the following additional features comparing to net.Dial:
+//
+// - It reduces load on DNS resolver by caching resolved TCP addressed
+// for DNSCacheDuration.
+// - It dials all the resolved TCP addresses in round-robin manner until
+// connection is established. This may be useful if certain addresses
+// are temporarily unreachable.
+//
+// This dialer is intended for custom code wrapping before passing
+// to Client.Dial or HostClient.Dial.
+//
+// For instance, per-host counters and/or limits may be implemented
+// by such wrappers.
+//
+// The addr passed to the function must contain port. Example addr values:
+//
+// - foobar.baz:443
+// - foo.bar:80
+// - aaa.com:8080
+func (d *TCPDialer) DialTimeout(addr string, timeout time.Duration) (net.Conn, error) {
+ return d.dial(addr, false, timeout)
+}
+
+// DialDualStack dials the given TCP addr using both tcp4 and tcp6.
+//
+// This function has the following additional features comparing to net.Dial:
+//
+// - It reduces load on DNS resolver by caching resolved TCP addressed
+// for DNSCacheDuration.
+// - It dials all the resolved TCP addresses in round-robin manner until
+// connection is established. This may be useful if certain addresses
+// are temporarily unreachable.
+// - It returns ErrDialTimeout if connection cannot be established during
+// DefaultDialTimeout seconds. Use DialDualStackTimeout for custom dial
+// timeout.
+//
+// This dialer is intended for custom code wrapping before passing
+// to Client.Dial or HostClient.Dial.
+//
+// For instance, per-host counters and/or limits may be implemented
+// by such wrappers.
+//
+// The addr passed to the function must contain port. Example addr values:
+//
+// - foobar.baz:443
+// - foo.bar:80
+// - aaa.com:8080
+func (d *TCPDialer) DialDualStack(addr string) (net.Conn, error) {
+ return d.dial(addr, true, DefaultDialTimeout)
+}
+
+// DialDualStackTimeout dials the given TCP addr using both tcp4 and tcp6
+// using the given timeout.
+//
+// This function has the following additional features comparing to net.Dial:
+//
+// - It reduces load on DNS resolver by caching resolved TCP addressed
+// for DNSCacheDuration.
+// - It dials all the resolved TCP addresses in round-robin manner until
+// connection is established. This may be useful if certain addresses
+// are temporarily unreachable.
+//
+// This dialer is intended for custom code wrapping before passing
+// to Client.Dial or HostClient.Dial.
+//
+// For instance, per-host counters and/or limits may be implemented
+// by such wrappers.
+//
+// The addr passed to the function must contain port. Example addr values:
+//
+// - foobar.baz:443
+// - foo.bar:80
+// - aaa.com:8080
+func (d *TCPDialer) DialDualStackTimeout(addr string, timeout time.Duration) (net.Conn, error) {
+ return d.dial(addr, true, timeout)
+}
+
+func (d *TCPDialer) dial(addr string, dualStack bool, timeout time.Duration) (net.Conn, error) {
+ d.once.Do(func() {
+ if d.Concurrency > 0 {
+ d.concurrencyCh = make(chan struct{}, d.Concurrency)
+ }
+
+ if d.DNSCacheDuration == 0 {
+ d.DNSCacheDuration = DefaultDNSCacheDuration
+ }
+
+ go d.tcpAddrsClean()
+ })
+
+ deadline := time.Now().Add(timeout)
+ addrs, idx, err := d.getTCPAddrs(addr, dualStack, deadline)
+ if err != nil {
+ return nil, err
+ }
+ network := "tcp4"
+ if dualStack {
+ network = "tcp"
+ }
+
+ var conn net.Conn
+ n := uint32(len(addrs))
+ for n > 0 {
+ conn, err = d.tryDial(network, &addrs[idx%n], deadline, d.concurrencyCh)
+ if err == nil {
+ return conn, nil
+ }
+ if err == ErrDialTimeout {
+ return nil, err
+ }
+ idx++
+ n--
+ }
+ return nil, err
+}
+
+func (d *TCPDialer) tryDial(network string, addr *net.TCPAddr, deadline time.Time, concurrencyCh chan struct{}) (net.Conn, error) {
+ timeout := time.Until(deadline)
+ if timeout <= 0 {
+ return nil, ErrDialTimeout
+ }
+
+ if concurrencyCh != nil {
+ select {
+ case concurrencyCh <- struct{}{}:
+ default:
+ tc := AcquireTimer(timeout)
+ isTimeout := false
+ select {
+ case concurrencyCh <- struct{}{}:
+ case <-tc.C:
+ isTimeout = true
+ }
+ ReleaseTimer(tc)
+ if isTimeout {
+ return nil, ErrDialTimeout
+ }
+ }
+ defer func() { <-concurrencyCh }()
+ }
+
+ dialer := net.Dialer{}
+ if d.LocalAddr != nil {
+ dialer.LocalAddr = d.LocalAddr
+ }
+
+ ctx, cancelCtx := context.WithDeadline(context.Background(), deadline)
+ defer cancelCtx()
+ conn, err := dialer.DialContext(ctx, network, addr.String())
+ if err != nil && ctx.Err() == context.DeadlineExceeded {
+ return nil, ErrDialTimeout
+ }
+ return conn, err
+}
+
+// ErrDialTimeout is returned when TCP dialing is timed out.
+var ErrDialTimeout = errors.New("dialing to the given TCP address timed out")
+
+// DefaultDialTimeout is timeout used by Dial and DialDualStack
+// for establishing TCP connections.
+const DefaultDialTimeout = 3 * time.Second
+
+type tcpAddrEntry struct {
+ addrs []net.TCPAddr
+ addrsIdx uint32
+
+ pending int32
+ resolveTime time.Time
+}
+
+// DefaultDNSCacheDuration is the duration for caching resolved TCP addresses
+// by Dial* functions.
+const DefaultDNSCacheDuration = time.Minute
+
+func (d *TCPDialer) tcpAddrsClean() {
+ expireDuration := 2 * d.DNSCacheDuration
+ for {
+ time.Sleep(time.Second)
+ t := time.Now()
+ d.tcpAddrsMap.Range(func(k, v interface{}) bool {
+ if e, ok := v.(*tcpAddrEntry); ok && t.Sub(e.resolveTime) > expireDuration {
+ d.tcpAddrsMap.Delete(k)
+ }
+ return true
+ })
+
+ }
+}
+
+func (d *TCPDialer) getTCPAddrs(addr string, dualStack bool, deadline time.Time) ([]net.TCPAddr, uint32, error) {
+ item, exist := d.tcpAddrsMap.Load(addr)
+ e, ok := item.(*tcpAddrEntry)
+ if exist && ok && e != nil && time.Since(e.resolveTime) > d.DNSCacheDuration {
+ // Only let one goroutine re-resolve at a time.
+ if atomic.SwapInt32(&e.pending, 1) == 0 {
+ e = nil
+ }
+ }
+
+ if e == nil {
+ addrs, err := resolveTCPAddrs(addr, dualStack, d.Resolver, deadline)
+ if err != nil {
+ item, exist := d.tcpAddrsMap.Load(addr)
+ e, ok = item.(*tcpAddrEntry)
+ if exist && ok && e != nil {
+ // Set pending to 0 so another goroutine can retry.
+ atomic.StoreInt32(&e.pending, 0)
+ }
+ return nil, 0, err
+ }
+
+ e = &tcpAddrEntry{
+ addrs: addrs,
+ resolveTime: time.Now(),
+ }
+ d.tcpAddrsMap.Store(addr, e)
+ }
+
+ idx := atomic.AddUint32(&e.addrsIdx, 1)
+ return e.addrs, idx, nil
+}
+
+func resolveTCPAddrs(addr string, dualStack bool, resolver Resolver, deadline time.Time) ([]net.TCPAddr, error) {
+ host, portS, err := net.SplitHostPort(addr)
+ if err != nil {
+ return nil, err
+ }
+ port, err := strconv.Atoi(portS)
+ if err != nil {
+ return nil, err
+ }
+
+ if resolver == nil {
+ resolver = net.DefaultResolver
+ }
+
+ ctx, cancel := context.WithDeadline(context.Background(), deadline)
+ defer cancel()
+ ipaddrs, err := resolver.LookupIPAddr(ctx, host)
+ if err != nil {
+ return nil, err
+ }
+
+ n := len(ipaddrs)
+ addrs := make([]net.TCPAddr, 0, n)
+ for i := 0; i < n; i++ {
+ ip := ipaddrs[i]
+ if !dualStack && ip.IP.To4() == nil {
+ continue
+ }
+ addrs = append(addrs, net.TCPAddr{
+ IP: ip.IP,
+ Port: port,
+ Zone: ip.Zone,
+ })
+ }
+ if len(addrs) == 0 {
+ return nil, errNoDNSEntries
+ }
+ return addrs, nil
+}
+
+var errNoDNSEntries = errors.New("couldn't find DNS entries for the given domain. Try using DialDualStack")
diff --git a/vendor/github.com/valyala/fasthttp/timer.go b/vendor/github.com/valyala/fasthttp/timer.go
new file mode 100644
index 0000000..6c06ba0
--- /dev/null
+++ b/vendor/github.com/valyala/fasthttp/timer.go
@@ -0,0 +1,55 @@
+package fasthttp
+
+import (
+ "sync"
+ "time"
+)
+
+func initTimer(t *time.Timer, timeout time.Duration) *time.Timer {
+ if t == nil {
+ return time.NewTimer(timeout)
+ }
+ if t.Reset(timeout) {
+ // developer sanity-check
+ panic("BUG: active timer trapped into initTimer()")
+ }
+ return t
+}
+
+func stopTimer(t *time.Timer) {
+ if !t.Stop() {
+ // Collect possibly added time from the channel
+ // if timer has been stopped and nobody collected its value.
+ select {
+ case <-t.C:
+ default:
+ }
+ }
+}
+
+// AcquireTimer returns a time.Timer from the pool and updates it to
+// send the current time on its channel after at least timeout.
+//
+// The returned Timer may be returned to the pool with ReleaseTimer
+// when no longer needed. This allows reducing GC load.
+func AcquireTimer(timeout time.Duration) *time.Timer {
+ v := timerPool.Get()
+ if v == nil {
+ return time.NewTimer(timeout)
+ }
+ t := v.(*time.Timer)
+ initTimer(t, timeout)
+ return t
+}
+
+// ReleaseTimer returns the time.Timer acquired via AcquireTimer to the pool
+// and prevents the Timer from firing.
+//
+// Do not access the released time.Timer or read from its channel otherwise
+// data races may occur.
+func ReleaseTimer(t *time.Timer) {
+ stopTimer(t)
+ timerPool.Put(t)
+}
+
+var timerPool sync.Pool
diff --git a/vendor/github.com/valyala/fasthttp/tls.go b/vendor/github.com/valyala/fasthttp/tls.go
new file mode 100644
index 0000000..08b03ce
--- /dev/null
+++ b/vendor/github.com/valyala/fasthttp/tls.go
@@ -0,0 +1,60 @@
+package fasthttp
+
+import (
+ "crypto/rand"
+ "crypto/rsa"
+ "crypto/x509"
+ "crypto/x509/pkix"
+ "encoding/pem"
+ "math/big"
+ "time"
+)
+
+// GenerateTestCertificate generates a test certificate and private key based on the given host.
+func GenerateTestCertificate(host string) ([]byte, []byte, error) {
+ priv, err := rsa.GenerateKey(rand.Reader, 2048)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
+ serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ cert := &x509.Certificate{
+ SerialNumber: serialNumber,
+ Subject: pkix.Name{
+ Organization: []string{"fasthttp test"},
+ },
+ NotBefore: time.Now(),
+ NotAfter: time.Now().Add(365 * 24 * time.Hour),
+ KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageDigitalSignature,
+ ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth},
+ SignatureAlgorithm: x509.SHA256WithRSA,
+ DNSNames: []string{host},
+ BasicConstraintsValid: true,
+ IsCA: true,
+ }
+
+ certBytes, err := x509.CreateCertificate(
+ rand.Reader, cert, cert, &priv.PublicKey, priv,
+ )
+
+ p := pem.EncodeToMemory(
+ &pem.Block{
+ Type: "PRIVATE KEY",
+ Bytes: x509.MarshalPKCS1PrivateKey(priv),
+ },
+ )
+
+ b := pem.EncodeToMemory(
+ &pem.Block{
+ Type: "CERTIFICATE",
+ Bytes: certBytes,
+ },
+ )
+
+ return b, p, err
+}
diff --git a/vendor/github.com/valyala/fasthttp/uri.go b/vendor/github.com/valyala/fasthttp/uri.go
new file mode 100644
index 0000000..f1ca6d9
--- /dev/null
+++ b/vendor/github.com/valyala/fasthttp/uri.go
@@ -0,0 +1,909 @@
+package fasthttp
+
+import (
+ "bytes"
+ "errors"
+ "fmt"
+ "io"
+ "path/filepath"
+ "strconv"
+ "sync"
+)
+
+// AcquireURI returns an empty URI instance from the pool.
+//
+// Release the URI with ReleaseURI after the URI is no longer needed.
+// This allows reducing GC load.
+func AcquireURI() *URI {
+ return uriPool.Get().(*URI)
+}
+
+// ReleaseURI releases the URI acquired via AcquireURI.
+//
+// The released URI mustn't be used after releasing it, otherwise data races
+// may occur.
+func ReleaseURI(u *URI) {
+ u.Reset()
+ uriPool.Put(u)
+}
+
+var uriPool = &sync.Pool{
+ New: func() interface{} {
+ return &URI{}
+ },
+}
+
+// URI represents URI :) .
+//
+// It is forbidden copying URI instances. Create new instance and use CopyTo
+// instead.
+//
+// URI instance MUST NOT be used from concurrently running goroutines.
+type URI struct {
+ noCopy noCopy
+
+ pathOriginal []byte
+ scheme []byte
+ path []byte
+ queryString []byte
+ hash []byte
+ host []byte
+
+ queryArgs Args
+ parsedQueryArgs bool
+
+ // Path values are sent as-is without normalization
+ //
+ // Disabled path normalization may be useful for proxying incoming requests
+ // to servers that are expecting paths to be forwarded as-is.
+ //
+ // By default path values are normalized, i.e.
+ // extra slashes are removed, special characters are encoded.
+ DisablePathNormalizing bool
+
+ fullURI []byte
+ requestURI []byte
+
+ username []byte
+ password []byte
+}
+
+// CopyTo copies uri contents to dst.
+func (u *URI) CopyTo(dst *URI) {
+ dst.Reset()
+ dst.pathOriginal = append(dst.pathOriginal, u.pathOriginal...)
+ dst.scheme = append(dst.scheme, u.scheme...)
+ dst.path = append(dst.path, u.path...)
+ dst.queryString = append(dst.queryString, u.queryString...)
+ dst.hash = append(dst.hash, u.hash...)
+ dst.host = append(dst.host, u.host...)
+ dst.username = append(dst.username, u.username...)
+ dst.password = append(dst.password, u.password...)
+
+ u.queryArgs.CopyTo(&dst.queryArgs)
+ dst.parsedQueryArgs = u.parsedQueryArgs
+ dst.DisablePathNormalizing = u.DisablePathNormalizing
+
+ // fullURI and requestURI shouldn't be copied, since they are created
+ // from scratch on each FullURI() and RequestURI() call.
+}
+
+// Hash returns URI hash, i.e. qwe of http://aaa.com/foo/bar?baz=123#qwe .
+//
+// The returned bytes are valid until the next URI method call.
+func (u *URI) Hash() []byte {
+ return u.hash
+}
+
+// SetHash sets URI hash.
+func (u *URI) SetHash(hash string) {
+ u.hash = append(u.hash[:0], hash...)
+}
+
+// SetHashBytes sets URI hash.
+func (u *URI) SetHashBytes(hash []byte) {
+ u.hash = append(u.hash[:0], hash...)
+}
+
+// Username returns URI username
+//
+// The returned bytes are valid until the next URI method call.
+func (u *URI) Username() []byte {
+ return u.username
+}
+
+// SetUsername sets URI username.
+func (u *URI) SetUsername(username string) {
+ u.username = append(u.username[:0], username...)
+}
+
+// SetUsernameBytes sets URI username.
+func (u *URI) SetUsernameBytes(username []byte) {
+ u.username = append(u.username[:0], username...)
+}
+
+// Password returns URI password
+//
+// The returned bytes are valid until the next URI method call.
+func (u *URI) Password() []byte {
+ return u.password
+}
+
+// SetPassword sets URI password.
+func (u *URI) SetPassword(password string) {
+ u.password = append(u.password[:0], password...)
+}
+
+// SetPasswordBytes sets URI password.
+func (u *URI) SetPasswordBytes(password []byte) {
+ u.password = append(u.password[:0], password...)
+}
+
+// QueryString returns URI query string,
+// i.e. baz=123 of http://aaa.com/foo/bar?baz=123#qwe .
+//
+// The returned bytes are valid until the next URI method call.
+func (u *URI) QueryString() []byte {
+ return u.queryString
+}
+
+// SetQueryString sets URI query string.
+func (u *URI) SetQueryString(queryString string) {
+ u.queryString = append(u.queryString[:0], queryString...)
+ u.parsedQueryArgs = false
+}
+
+// SetQueryStringBytes sets URI query string.
+func (u *URI) SetQueryStringBytes(queryString []byte) {
+ u.queryString = append(u.queryString[:0], queryString...)
+ u.parsedQueryArgs = false
+}
+
+// Path returns URI path, i.e. /foo/bar of http://aaa.com/foo/bar?baz=123#qwe .
+//
+// The returned path is always urldecoded and normalized,
+// i.e. '//f%20obar/baz/../zzz' becomes '/f obar/zzz'.
+//
+// The returned bytes are valid until the next URI method call.
+func (u *URI) Path() []byte {
+ path := u.path
+ if len(path) == 0 {
+ path = strSlash
+ }
+ return path
+}
+
+// SetPath sets URI path.
+func (u *URI) SetPath(path string) {
+ u.pathOriginal = append(u.pathOriginal[:0], path...)
+ u.path = normalizePath(u.path, u.pathOriginal)
+}
+
+// SetPathBytes sets URI path.
+func (u *URI) SetPathBytes(path []byte) {
+ u.pathOriginal = append(u.pathOriginal[:0], path...)
+ u.path = normalizePath(u.path, u.pathOriginal)
+}
+
+// PathOriginal returns the original path from requestURI passed to URI.Parse().
+//
+// The returned bytes are valid until the next URI method call.
+func (u *URI) PathOriginal() []byte {
+ return u.pathOriginal
+}
+
+// Scheme returns URI scheme, i.e. http of http://aaa.com/foo/bar?baz=123#qwe .
+//
+// Returned scheme is always lowercased.
+//
+// The returned bytes are valid until the next URI method call.
+func (u *URI) Scheme() []byte {
+ scheme := u.scheme
+ if len(scheme) == 0 {
+ scheme = strHTTP
+ }
+ return scheme
+}
+
+// SetScheme sets URI scheme, i.e. http, https, ftp, etc.
+func (u *URI) SetScheme(scheme string) {
+ u.scheme = append(u.scheme[:0], scheme...)
+ lowercaseBytes(u.scheme)
+}
+
+// SetSchemeBytes sets URI scheme, i.e. http, https, ftp, etc.
+func (u *URI) SetSchemeBytes(scheme []byte) {
+ u.scheme = append(u.scheme[:0], scheme...)
+ lowercaseBytes(u.scheme)
+}
+
+func (u *URI) isHTTPS() bool {
+ return bytes.Equal(u.scheme, strHTTPS)
+}
+
+func (u *URI) isHTTP() bool {
+ return len(u.scheme) == 0 || bytes.Equal(u.scheme, strHTTP)
+}
+
+// Reset clears uri.
+func (u *URI) Reset() {
+ u.pathOriginal = u.pathOriginal[:0]
+ u.scheme = u.scheme[:0]
+ u.path = u.path[:0]
+ u.queryString = u.queryString[:0]
+ u.hash = u.hash[:0]
+ u.username = u.username[:0]
+ u.password = u.password[:0]
+
+ u.host = u.host[:0]
+ u.queryArgs.Reset()
+ u.parsedQueryArgs = false
+ u.DisablePathNormalizing = false
+
+ // There is no need in u.fullURI = u.fullURI[:0], since full uri
+ // is calculated on each call to FullURI().
+
+ // There is no need in u.requestURI = u.requestURI[:0], since requestURI
+ // is calculated on each call to RequestURI().
+}
+
+// Host returns host part, i.e. aaa.com of http://aaa.com/foo/bar?baz=123#qwe .
+//
+// Host is always lowercased.
+//
+// The returned bytes are valid until the next URI method call.
+func (u *URI) Host() []byte {
+ return u.host
+}
+
+// SetHost sets host for the uri.
+func (u *URI) SetHost(host string) {
+ u.host = append(u.host[:0], host...)
+ lowercaseBytes(u.host)
+}
+
+// SetHostBytes sets host for the uri.
+func (u *URI) SetHostBytes(host []byte) {
+ u.host = append(u.host[:0], host...)
+ lowercaseBytes(u.host)
+}
+
+var ErrorInvalidURI = errors.New("invalid uri")
+
+// Parse initializes URI from the given host and uri.
+//
+// host may be nil. In this case uri must contain fully qualified uri,
+// i.e. with scheme and host. http is assumed if scheme is omitted.
+//
+// uri may contain e.g. RequestURI without scheme and host if host is non-empty.
+func (u *URI) Parse(host, uri []byte) error {
+ return u.parse(host, uri, false)
+}
+
+func (u *URI) parse(host, uri []byte, isTLS bool) error {
+ u.Reset()
+
+ if stringContainsCTLByte(uri) {
+ return ErrorInvalidURI
+ }
+
+ if len(host) == 0 || bytes.Contains(uri, strColonSlashSlash) {
+ scheme, newHost, newURI := splitHostURI(host, uri)
+ u.SetSchemeBytes(scheme)
+ host = newHost
+ uri = newURI
+ }
+
+ if isTLS {
+ u.SetSchemeBytes(strHTTPS)
+ }
+
+ if n := bytes.IndexByte(host, '@'); n >= 0 {
+ auth := host[:n]
+ host = host[n+1:]
+
+ if n := bytes.IndexByte(auth, ':'); n >= 0 {
+ u.username = append(u.username[:0], auth[:n]...)
+ u.password = append(u.password[:0], auth[n+1:]...)
+ } else {
+ u.username = append(u.username[:0], auth...)
+ u.password = u.password[:0]
+ }
+ }
+
+ u.host = append(u.host, host...)
+ if parsedHost, err := parseHost(u.host); err != nil {
+ return err
+ } else {
+ u.host = parsedHost
+ }
+ lowercaseBytes(u.host)
+
+ b := uri
+ queryIndex := bytes.IndexByte(b, '?')
+ fragmentIndex := bytes.IndexByte(b, '#')
+ // Ignore query in fragment part
+ if fragmentIndex >= 0 && queryIndex > fragmentIndex {
+ queryIndex = -1
+ }
+
+ if queryIndex < 0 && fragmentIndex < 0 {
+ u.pathOriginal = append(u.pathOriginal, b...)
+ u.path = normalizePath(u.path, u.pathOriginal)
+ return nil
+ }
+
+ if queryIndex >= 0 {
+ // Path is everything up to the start of the query
+ u.pathOriginal = append(u.pathOriginal, b[:queryIndex]...)
+ u.path = normalizePath(u.path, u.pathOriginal)
+
+ if fragmentIndex < 0 {
+ u.queryString = append(u.queryString, b[queryIndex+1:]...)
+ } else {
+ u.queryString = append(u.queryString, b[queryIndex+1:fragmentIndex]...)
+ u.hash = append(u.hash, b[fragmentIndex+1:]...)
+ }
+ return nil
+ }
+
+ // fragmentIndex >= 0 && queryIndex < 0
+ // Path is up to the start of fragment
+ u.pathOriginal = append(u.pathOriginal, b[:fragmentIndex]...)
+ u.path = normalizePath(u.path, u.pathOriginal)
+ u.hash = append(u.hash, b[fragmentIndex+1:]...)
+
+ return nil
+}
+
+// parseHost parses host as an authority without user
+// information. That is, as host[:port].
+//
+// Based on https://github.com/golang/go/blob/8ac5cbe05d61df0a7a7c9a38ff33305d4dcfea32/src/net/url/url.go#L619
+//
+// The host is parsed and unescaped in place overwriting the contents of the host parameter.
+func parseHost(host []byte) ([]byte, error) {
+ if len(host) > 0 && host[0] == '[' {
+ // Parse an IP-Literal in RFC 3986 and RFC 6874.
+ // E.g., "[fe80::1]", "[fe80::1%25en0]", "[fe80::1]:80".
+ i := bytes.LastIndexByte(host, ']')
+ if i < 0 {
+ return nil, errors.New("missing ']' in host")
+ }
+ colonPort := host[i+1:]
+ if !validOptionalPort(colonPort) {
+ return nil, fmt.Errorf("invalid port %q after host", colonPort)
+ }
+
+ // RFC 6874 defines that %25 (%-encoded percent) introduces
+ // the zone identifier, and the zone identifier can use basically
+ // any %-encoding it likes. That's different from the host, which
+ // can only %-encode non-ASCII bytes.
+ // We do impose some restrictions on the zone, to avoid stupidity
+ // like newlines.
+ zone := bytes.Index(host[:i], []byte("%25"))
+ if zone >= 0 {
+ host1, err := unescape(host[:zone], encodeHost)
+ if err != nil {
+ return nil, err
+ }
+ host2, err := unescape(host[zone:i], encodeZone)
+ if err != nil {
+ return nil, err
+ }
+ host3, err := unescape(host[i:], encodeHost)
+ if err != nil {
+ return nil, err
+ }
+ return append(host1, append(host2, host3...)...), nil
+ }
+ } else if i := bytes.LastIndexByte(host, ':'); i != -1 {
+ colonPort := host[i:]
+ if !validOptionalPort(colonPort) {
+ return nil, fmt.Errorf("invalid port %q after host", colonPort)
+ }
+ }
+
+ var err error
+ if host, err = unescape(host, encodeHost); err != nil {
+ return nil, err
+ }
+ return host, nil
+}
+
+type encoding int
+
+const (
+ encodeHost encoding = 1 + iota
+ encodeZone
+)
+
+type EscapeError string
+
+func (e EscapeError) Error() string {
+ return "invalid URL escape " + strconv.Quote(string(e))
+}
+
+type InvalidHostError string
+
+func (e InvalidHostError) Error() string {
+ return "invalid character " + strconv.Quote(string(e)) + " in host name"
+}
+
+// unescape unescapes a string; the mode specifies
+// which section of the URL string is being unescaped.
+//
+// Based on https://github.com/golang/go/blob/8ac5cbe05d61df0a7a7c9a38ff33305d4dcfea32/src/net/url/url.go#L199
+//
+// Unescapes in place overwriting the contents of s and returning it.
+func unescape(s []byte, mode encoding) ([]byte, error) {
+ // Count %, check that they're well-formed.
+ n := 0
+ for i := 0; i < len(s); {
+ switch s[i] {
+ case '%':
+ n++
+ if i+2 >= len(s) || !ishex(s[i+1]) || !ishex(s[i+2]) {
+ s = s[i:]
+ if len(s) > 3 {
+ s = s[:3]
+ }
+ return nil, EscapeError(s)
+ }
+ // Per https://tools.ietf.org/html/rfc3986#page-21
+ // in the host component %-encoding can only be used
+ // for non-ASCII bytes.
+ // But https://tools.ietf.org/html/rfc6874#section-2
+ // introduces %25 being allowed to escape a percent sign
+ // in IPv6 scoped-address literals. Yay.
+ if mode == encodeHost && unhex(s[i+1]) < 8 && !bytes.Equal(s[i:i+3], []byte("%25")) {
+ return nil, EscapeError(s[i : i+3])
+ }
+ if mode == encodeZone {
+ // RFC 6874 says basically "anything goes" for zone identifiers
+ // and that even non-ASCII can be redundantly escaped,
+ // but it seems prudent to restrict %-escaped bytes here to those
+ // that are valid host name bytes in their unescaped form.
+ // That is, you can use escaping in the zone identifier but not
+ // to introduce bytes you couldn't just write directly.
+ // But Windows puts spaces here! Yay.
+ v := unhex(s[i+1])<<4 | unhex(s[i+2])
+ if !bytes.Equal(s[i:i+3], []byte("%25")) && v != ' ' && shouldEscape(v, encodeHost) {
+ return nil, EscapeError(s[i : i+3])
+ }
+ }
+ i += 3
+ default:
+ if (mode == encodeHost || mode == encodeZone) && s[i] < 0x80 && shouldEscape(s[i], mode) {
+ return nil, InvalidHostError(s[i : i+1])
+ }
+ i++
+ }
+ }
+
+ if n == 0 {
+ return s, nil
+ }
+
+ t := s[:0]
+ for i := 0; i < len(s); i++ {
+ switch s[i] {
+ case '%':
+ t = append(t, unhex(s[i+1])<<4|unhex(s[i+2]))
+ i += 2
+ default:
+ t = append(t, s[i])
+ }
+ }
+ return t, nil
+}
+
+// Return true if the specified character should be escaped when
+// appearing in a URL string, according to RFC 3986.
+//
+// Please be informed that for now shouldEscape does not check all
+// reserved characters correctly. See https://github.com/golang/go/issues/5684.
+//
+// Based on https://github.com/golang/go/blob/8ac5cbe05d61df0a7a7c9a38ff33305d4dcfea32/src/net/url/url.go#L100
+func shouldEscape(c byte, mode encoding) bool {
+ // §2.3 Unreserved characters (alphanum)
+ if 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || '0' <= c && c <= '9' {
+ return false
+ }
+
+ if mode == encodeHost || mode == encodeZone {
+ // §3.2.2 Host allows
+ // sub-delims = "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / ";" / "="
+ // as part of reg-name.
+ // We add : because we include :port as part of host.
+ // We add [ ] because we include [ipv6]:port as part of host.
+ // We add < > because they're the only characters left that
+ // we could possibly allow, and Parse will reject them if we
+ // escape them (because hosts can't use %-encoding for
+ // ASCII bytes).
+ switch c {
+ case '!', '$', '&', '\'', '(', ')', '*', '+', ',', ';', '=', ':', '[', ']', '<', '>', '"':
+ return false
+ }
+ }
+
+ if c == '-' || c == '_' || c == '.' || c == '~' { // §2.3 Unreserved characters (mark)
+ return false
+ }
+
+ // Everything else must be escaped.
+ return true
+}
+
+func ishex(c byte) bool {
+ return ('0' <= c && c <= '9') ||
+ ('a' <= c && c <= 'f') ||
+ ('A' <= c && c <= 'F')
+}
+
+func unhex(c byte) byte {
+ switch {
+ case '0' <= c && c <= '9':
+ return c - '0'
+ case 'a' <= c && c <= 'f':
+ return c - 'a' + 10
+ case 'A' <= c && c <= 'F':
+ return c - 'A' + 10
+ }
+ return 0
+}
+
+// validOptionalPort reports whether port is either an empty string
+// or matches /^:\d*$/
+func validOptionalPort(port []byte) bool {
+ if len(port) == 0 {
+ return true
+ }
+ if port[0] != ':' {
+ return false
+ }
+ for _, b := range port[1:] {
+ if b < '0' || b > '9' {
+ return false
+ }
+ }
+ return true
+}
+
+func normalizePath(dst, src []byte) []byte {
+ dst = dst[:0]
+ dst = addLeadingSlash(dst, src)
+ dst = decodeArgAppendNoPlus(dst, src)
+
+ // remove duplicate slashes
+ b := dst
+ bSize := len(b)
+ for {
+ n := bytes.Index(b, strSlashSlash)
+ if n < 0 {
+ break
+ }
+ b = b[n:]
+ copy(b, b[1:])
+ b = b[:len(b)-1]
+ bSize--
+ }
+ dst = dst[:bSize]
+
+ // remove /./ parts
+ b = dst
+ for {
+ n := bytes.Index(b, strSlashDotSlash)
+ if n < 0 {
+ break
+ }
+ nn := n + len(strSlashDotSlash) - 1
+ copy(b[n:], b[nn:])
+ b = b[:len(b)-nn+n]
+ }
+
+ // remove /foo/../ parts
+ for {
+ n := bytes.Index(b, strSlashDotDotSlash)
+ if n < 0 {
+ break
+ }
+ nn := bytes.LastIndexByte(b[:n], '/')
+ if nn < 0 {
+ nn = 0
+ }
+ n += len(strSlashDotDotSlash) - 1
+ copy(b[nn:], b[n:])
+ b = b[:len(b)-n+nn]
+ }
+
+ // remove trailing /foo/..
+ n := bytes.LastIndex(b, strSlashDotDot)
+ if n >= 0 && n+len(strSlashDotDot) == len(b) {
+ nn := bytes.LastIndexByte(b[:n], '/')
+ if nn < 0 {
+ return append(dst[:0], strSlash...)
+ }
+ b = b[:nn+1]
+ }
+
+ if filepath.Separator == '\\' {
+ // remove \.\ parts
+ for {
+ n := bytes.Index(b, strBackSlashDotBackSlash)
+ if n < 0 {
+ break
+ }
+ nn := n + len(strSlashDotSlash) - 1
+ copy(b[n:], b[nn:])
+ b = b[:len(b)-nn+n]
+ }
+
+ // remove /foo/..\ parts
+ for {
+ n := bytes.Index(b, strSlashDotDotBackSlash)
+ if n < 0 {
+ break
+ }
+ nn := bytes.LastIndexByte(b[:n], '/')
+ if nn < 0 {
+ nn = 0
+ }
+ nn++
+ n += len(strSlashDotDotBackSlash)
+ copy(b[nn:], b[n:])
+ b = b[:len(b)-n+nn]
+ }
+
+ // remove /foo\..\ parts
+ for {
+ n := bytes.Index(b, strBackSlashDotDotBackSlash)
+ if n < 0 {
+ break
+ }
+ nn := bytes.LastIndexByte(b[:n], '/')
+ if nn < 0 {
+ nn = 0
+ }
+ n += len(strBackSlashDotDotBackSlash) - 1
+ copy(b[nn:], b[n:])
+ b = b[:len(b)-n+nn]
+ }
+
+ // remove trailing \foo\..
+ n := bytes.LastIndex(b, strBackSlashDotDot)
+ if n >= 0 && n+len(strSlashDotDot) == len(b) {
+ nn := bytes.LastIndexByte(b[:n], '/')
+ if nn < 0 {
+ return append(dst[:0], strSlash...)
+ }
+ b = b[:nn+1]
+ }
+ }
+
+ return b
+}
+
+// RequestURI returns RequestURI - i.e. URI without Scheme and Host.
+func (u *URI) RequestURI() []byte {
+ var dst []byte
+ if u.DisablePathNormalizing {
+ dst = u.requestURI[:0]
+ dst = append(dst, u.PathOriginal()...)
+ } else {
+ dst = appendQuotedPath(u.requestURI[:0], u.Path())
+ }
+ if u.parsedQueryArgs && u.queryArgs.Len() > 0 {
+ dst = append(dst, '?')
+ dst = u.queryArgs.AppendBytes(dst)
+ } else if len(u.queryString) > 0 {
+ dst = append(dst, '?')
+ dst = append(dst, u.queryString...)
+ }
+ u.requestURI = dst
+ return u.requestURI
+}
+
+// LastPathSegment returns the last part of uri path after '/'.
+//
+// Examples:
+//
+// - For /foo/bar/baz.html path returns baz.html.
+// - For /foo/bar/ returns empty byte slice.
+// - For /foobar.js returns foobar.js.
+//
+// The returned bytes are valid until the next URI method call.
+func (u *URI) LastPathSegment() []byte {
+ path := u.Path()
+ n := bytes.LastIndexByte(path, '/')
+ if n < 0 {
+ return path
+ }
+ return path[n+1:]
+}
+
+// Update updates uri.
+//
+// The following newURI types are accepted:
+//
+// - Absolute, i.e. http://foobar.com/aaa/bb?cc . In this case the original
+// uri is replaced by newURI.
+// - Absolute without scheme, i.e. //foobar.com/aaa/bb?cc. In this case
+// the original scheme is preserved.
+// - Missing host, i.e. /aaa/bb?cc . In this case only RequestURI part
+// of the original uri is replaced.
+// - Relative path, i.e. xx?yy=abc . In this case the original RequestURI
+// is updated according to the new relative path.
+func (u *URI) Update(newURI string) {
+ u.UpdateBytes(s2b(newURI))
+}
+
+// UpdateBytes updates uri.
+//
+// The following newURI types are accepted:
+//
+// - Absolute, i.e. http://foobar.com/aaa/bb?cc . In this case the original
+// uri is replaced by newURI.
+// - Absolute without scheme, i.e. //foobar.com/aaa/bb?cc. In this case
+// the original scheme is preserved.
+// - Missing host, i.e. /aaa/bb?cc . In this case only RequestURI part
+// of the original uri is replaced.
+// - Relative path, i.e. xx?yy=abc . In this case the original RequestURI
+// is updated according to the new relative path.
+func (u *URI) UpdateBytes(newURI []byte) {
+ u.requestURI = u.updateBytes(newURI, u.requestURI)
+}
+
+func (u *URI) updateBytes(newURI, buf []byte) []byte {
+ if len(newURI) == 0 {
+ return buf
+ }
+
+ n := bytes.Index(newURI, strSlashSlash)
+ if n >= 0 {
+ // absolute uri
+ var b [32]byte
+ schemeOriginal := b[:0]
+ if len(u.scheme) > 0 {
+ schemeOriginal = append([]byte(nil), u.scheme...)
+ }
+ if err := u.Parse(nil, newURI); err != nil {
+ return nil
+ }
+ if len(schemeOriginal) > 0 && len(u.scheme) == 0 {
+ u.scheme = append(u.scheme[:0], schemeOriginal...)
+ }
+ return buf
+ }
+
+ if newURI[0] == '/' {
+ // uri without host
+ buf = u.appendSchemeHost(buf[:0])
+ buf = append(buf, newURI...)
+ if err := u.Parse(nil, buf); err != nil {
+ return nil
+ }
+ return buf
+ }
+
+ // relative path
+ switch newURI[0] {
+ case '?':
+ // query string only update
+ u.SetQueryStringBytes(newURI[1:])
+ return append(buf[:0], u.FullURI()...)
+ case '#':
+ // update only hash
+ u.SetHashBytes(newURI[1:])
+ return append(buf[:0], u.FullURI()...)
+ default:
+ // update the last path part after the slash
+ path := u.Path()
+ n = bytes.LastIndexByte(path, '/')
+ if n < 0 {
+ panic(fmt.Sprintf("BUG: path must contain at least one slash: %q %q", u.Path(), newURI))
+ }
+ buf = u.appendSchemeHost(buf[:0])
+ buf = appendQuotedPath(buf, path[:n+1])
+ buf = append(buf, newURI...)
+ if err := u.Parse(nil, buf); err != nil {
+ return nil
+ }
+ return buf
+ }
+}
+
+// FullURI returns full uri in the form {Scheme}://{Host}{RequestURI}#{Hash}.
+//
+// The returned bytes are valid until the next URI method call.
+func (u *URI) FullURI() []byte {
+ u.fullURI = u.AppendBytes(u.fullURI[:0])
+ return u.fullURI
+}
+
+// AppendBytes appends full uri to dst and returns the extended dst.
+func (u *URI) AppendBytes(dst []byte) []byte {
+ dst = u.appendSchemeHost(dst)
+ dst = append(dst, u.RequestURI()...)
+ if len(u.hash) > 0 {
+ dst = append(dst, '#')
+ dst = append(dst, u.hash...)
+ }
+ return dst
+}
+
+func (u *URI) appendSchemeHost(dst []byte) []byte {
+ dst = append(dst, u.Scheme()...)
+ dst = append(dst, strColonSlashSlash...)
+ return append(dst, u.Host()...)
+}
+
+// WriteTo writes full uri to w.
+//
+// WriteTo implements io.WriterTo interface.
+func (u *URI) WriteTo(w io.Writer) (int64, error) {
+ n, err := w.Write(u.FullURI())
+ return int64(n), err
+}
+
+// String returns full uri.
+func (u *URI) String() string {
+ return string(u.FullURI())
+}
+
+func splitHostURI(host, uri []byte) ([]byte, []byte, []byte) {
+ n := bytes.Index(uri, strSlashSlash)
+ if n < 0 {
+ return strHTTP, host, uri
+ }
+ scheme := uri[:n]
+ if bytes.IndexByte(scheme, '/') >= 0 {
+ return strHTTP, host, uri
+ }
+ if len(scheme) > 0 && scheme[len(scheme)-1] == ':' {
+ scheme = scheme[:len(scheme)-1]
+ }
+ n += len(strSlashSlash)
+ uri = uri[n:]
+ n = bytes.IndexByte(uri, '/')
+ nq := bytes.IndexByte(uri, '?')
+ if nq >= 0 && nq < n {
+ // A hack for urls like foobar.com?a=b/xyz
+ n = nq
+ } else if n < 0 {
+ // A hack for bogus urls like foobar.com?a=b without
+ // slash after host.
+ if nq >= 0 {
+ return scheme, uri[:nq], uri[nq:]
+ }
+ return scheme, uri, strSlash
+ }
+ return scheme, uri[:n], uri[n:]
+}
+
+// QueryArgs returns query args.
+//
+// The returned args are valid until the next URI method call.
+func (u *URI) QueryArgs() *Args {
+ u.parseQueryArgs()
+ return &u.queryArgs
+}
+
+func (u *URI) parseQueryArgs() {
+ if u.parsedQueryArgs {
+ return
+ }
+ u.queryArgs.ParseBytes(u.queryString)
+ u.parsedQueryArgs = true
+}
+
+// stringContainsCTLByte reports whether s contains any ASCII control character.
+func stringContainsCTLByte(s []byte) bool {
+ for i := 0; i < len(s); i++ {
+ b := s[i]
+ if b < ' ' || b == 0x7f {
+ return true
+ }
+ }
+ return false
+}
diff --git a/vendor/github.com/valyala/fasthttp/uri_unix.go b/vendor/github.com/valyala/fasthttp/uri_unix.go
new file mode 100644
index 0000000..1226fc9
--- /dev/null
+++ b/vendor/github.com/valyala/fasthttp/uri_unix.go
@@ -0,0 +1,12 @@
+//go:build !windows
+
+package fasthttp
+
+func addLeadingSlash(dst, src []byte) []byte {
+ // add leading slash for unix paths
+ if len(src) == 0 || src[0] != '/' {
+ dst = append(dst, '/')
+ }
+
+ return dst
+}
diff --git a/vendor/github.com/valyala/fasthttp/uri_windows.go b/vendor/github.com/valyala/fasthttp/uri_windows.go
new file mode 100644
index 0000000..46f4b07
--- /dev/null
+++ b/vendor/github.com/valyala/fasthttp/uri_windows.go
@@ -0,0 +1,11 @@
+package fasthttp
+
+func addLeadingSlash(dst, src []byte) []byte {
+ // zero length 、"C:/" and "a" case
+ isDisk := len(src) > 2 && src[1] == ':'
+ if len(src) == 0 || (!isDisk && src[0] != '/') {
+ dst = append(dst, '/')
+ }
+
+ return dst
+}
diff --git a/vendor/github.com/valyala/fasthttp/userdata.go b/vendor/github.com/valyala/fasthttp/userdata.go
new file mode 100644
index 0000000..5561cda
--- /dev/null
+++ b/vendor/github.com/valyala/fasthttp/userdata.go
@@ -0,0 +1,105 @@
+package fasthttp
+
+import (
+ "io"
+)
+
+type userDataKV struct {
+ key interface{}
+ value interface{}
+}
+
+type userData []userDataKV
+
+func (d *userData) Set(key interface{}, value interface{}) {
+ if b, ok := key.([]byte); ok {
+ key = string(b)
+ }
+ args := *d
+ n := len(args)
+ for i := 0; i < n; i++ {
+ kv := &args[i]
+ if kv.key == key {
+ kv.value = value
+ return
+ }
+ }
+
+ if value == nil {
+ return
+ }
+
+ c := cap(args)
+ if c > n {
+ args = args[:n+1]
+ kv := &args[n]
+ kv.key = key
+ kv.value = value
+ *d = args
+ return
+ }
+
+ kv := userDataKV{}
+ kv.key = key
+ kv.value = value
+ args = append(args, kv)
+ *d = args
+}
+
+func (d *userData) SetBytes(key []byte, value interface{}) {
+ d.Set(key, value)
+}
+
+func (d *userData) Get(key interface{}) interface{} {
+ if b, ok := key.([]byte); ok {
+ key = b2s(b)
+ }
+ args := *d
+ n := len(args)
+ for i := 0; i < n; i++ {
+ kv := &args[i]
+ if kv.key == key {
+ return kv.value
+ }
+ }
+ return nil
+}
+
+func (d *userData) GetBytes(key []byte) interface{} {
+ return d.Get(key)
+}
+
+func (d *userData) Reset() {
+ args := *d
+ n := len(args)
+ for i := 0; i < n; i++ {
+ v := args[i].value
+ if vc, ok := v.(io.Closer); ok {
+ vc.Close()
+ }
+ }
+ *d = (*d)[:0]
+}
+
+func (d *userData) Remove(key interface{}) {
+ if b, ok := key.([]byte); ok {
+ key = b2s(b)
+ }
+ args := *d
+ n := len(args)
+ for i := 0; i < n; i++ {
+ kv := &args[i]
+ if kv.key == key {
+ n--
+ args[i], args[n] = args[n], args[i]
+ args[n].value = nil
+ args = args[:n]
+ *d = args
+ return
+ }
+ }
+}
+
+func (d *userData) RemoveBytes(key []byte) {
+ d.Remove(key)
+}
diff --git a/vendor/github.com/valyala/fasthttp/workerpool.go b/vendor/github.com/valyala/fasthttp/workerpool.go
new file mode 100644
index 0000000..71da1f2
--- /dev/null
+++ b/vendor/github.com/valyala/fasthttp/workerpool.go
@@ -0,0 +1,251 @@
+package fasthttp
+
+import (
+ "errors"
+ "net"
+ "runtime"
+ "strings"
+ "sync"
+ "time"
+)
+
+// workerPool serves incoming connections via a pool of workers
+// in FILO order, i.e. the most recently stopped worker will serve the next
+// incoming connection.
+//
+// Such a scheme keeps CPU caches hot (in theory).
+type workerPool struct {
+ // Function for serving server connections.
+ // It must leave c unclosed.
+ WorkerFunc ServeHandler
+
+ MaxWorkersCount int
+
+ LogAllErrors bool
+
+ MaxIdleWorkerDuration time.Duration
+
+ Logger Logger
+
+ lock sync.Mutex
+ workersCount int
+ mustStop bool
+
+ ready []*workerChan
+
+ stopCh chan struct{}
+
+ workerChanPool sync.Pool
+
+ connState func(net.Conn, ConnState)
+}
+
+type workerChan struct {
+ lastUseTime time.Time
+ ch chan net.Conn
+}
+
+func (wp *workerPool) Start() {
+ if wp.stopCh != nil {
+ return
+ }
+ wp.stopCh = make(chan struct{})
+ stopCh := wp.stopCh
+ wp.workerChanPool.New = func() interface{} {
+ return &workerChan{
+ ch: make(chan net.Conn, workerChanCap),
+ }
+ }
+ go func() {
+ var scratch []*workerChan
+ for {
+ wp.clean(&scratch)
+ select {
+ case <-stopCh:
+ return
+ default:
+ time.Sleep(wp.getMaxIdleWorkerDuration())
+ }
+ }
+ }()
+}
+
+func (wp *workerPool) Stop() {
+ if wp.stopCh == nil {
+ return
+ }
+ close(wp.stopCh)
+ wp.stopCh = nil
+
+ // Stop all the workers waiting for incoming connections.
+ // Do not wait for busy workers - they will stop after
+ // serving the connection and noticing wp.mustStop = true.
+ wp.lock.Lock()
+ ready := wp.ready
+ for i := range ready {
+ ready[i].ch <- nil
+ ready[i] = nil
+ }
+ wp.ready = ready[:0]
+ wp.mustStop = true
+ wp.lock.Unlock()
+}
+
+func (wp *workerPool) getMaxIdleWorkerDuration() time.Duration {
+ if wp.MaxIdleWorkerDuration <= 0 {
+ return 10 * time.Second
+ }
+ return wp.MaxIdleWorkerDuration
+}
+
+func (wp *workerPool) clean(scratch *[]*workerChan) {
+ maxIdleWorkerDuration := wp.getMaxIdleWorkerDuration()
+
+ // Clean least recently used workers if they didn't serve connections
+ // for more than maxIdleWorkerDuration.
+ criticalTime := time.Now().Add(-maxIdleWorkerDuration)
+
+ wp.lock.Lock()
+ ready := wp.ready
+ n := len(ready)
+
+ // Use binary-search algorithm to find out the index of the least recently worker which can be cleaned up.
+ l, r, mid := 0, n-1, 0
+ for l <= r {
+ mid = (l + r) / 2
+ if criticalTime.After(wp.ready[mid].lastUseTime) {
+ l = mid + 1
+ } else {
+ r = mid - 1
+ }
+ }
+ i := r
+ if i == -1 {
+ wp.lock.Unlock()
+ return
+ }
+
+ *scratch = append((*scratch)[:0], ready[:i+1]...)
+ m := copy(ready, ready[i+1:])
+ for i = m; i < n; i++ {
+ ready[i] = nil
+ }
+ wp.ready = ready[:m]
+ wp.lock.Unlock()
+
+ // Notify obsolete workers to stop.
+ // This notification must be outside the wp.lock, since ch.ch
+ // may be blocking and may consume a lot of time if many workers
+ // are located on non-local CPUs.
+ tmp := *scratch
+ for i := range tmp {
+ tmp[i].ch <- nil
+ tmp[i] = nil
+ }
+}
+
+func (wp *workerPool) Serve(c net.Conn) bool {
+ ch := wp.getCh()
+ if ch == nil {
+ return false
+ }
+ ch.ch <- c
+ return true
+}
+
+var workerChanCap = func() int {
+ // Use blocking workerChan if GOMAXPROCS=1.
+ // This immediately switches Serve to WorkerFunc, which results
+ // in higher performance (under go1.5 at least).
+ if runtime.GOMAXPROCS(0) == 1 {
+ return 0
+ }
+
+ // Use non-blocking workerChan if GOMAXPROCS>1,
+ // since otherwise the Serve caller (Acceptor) may lag accepting
+ // new connections if WorkerFunc is CPU-bound.
+ return 1
+}()
+
+func (wp *workerPool) getCh() *workerChan {
+ var ch *workerChan
+ createWorker := false
+
+ wp.lock.Lock()
+ ready := wp.ready
+ n := len(ready) - 1
+ if n < 0 {
+ if wp.workersCount < wp.MaxWorkersCount {
+ createWorker = true
+ wp.workersCount++
+ }
+ } else {
+ ch = ready[n]
+ ready[n] = nil
+ wp.ready = ready[:n]
+ }
+ wp.lock.Unlock()
+
+ if ch == nil {
+ if !createWorker {
+ return nil
+ }
+ vch := wp.workerChanPool.Get()
+ ch = vch.(*workerChan)
+ go func() {
+ wp.workerFunc(ch)
+ wp.workerChanPool.Put(vch)
+ }()
+ }
+ return ch
+}
+
+func (wp *workerPool) release(ch *workerChan) bool {
+ ch.lastUseTime = time.Now()
+ wp.lock.Lock()
+ if wp.mustStop {
+ wp.lock.Unlock()
+ return false
+ }
+ wp.ready = append(wp.ready, ch)
+ wp.lock.Unlock()
+ return true
+}
+
+func (wp *workerPool) workerFunc(ch *workerChan) {
+ var c net.Conn
+
+ var err error
+ for c = range ch.ch {
+ if c == nil {
+ break
+ }
+
+ if err = wp.WorkerFunc(c); err != nil && err != errHijacked {
+ errStr := err.Error()
+ if wp.LogAllErrors || !(strings.Contains(errStr, "broken pipe") ||
+ strings.Contains(errStr, "reset by peer") ||
+ strings.Contains(errStr, "request headers: small read buffer") ||
+ strings.Contains(errStr, "unexpected EOF") ||
+ strings.Contains(errStr, "i/o timeout") ||
+ errors.Is(err, ErrBadTrailer)) {
+ wp.Logger.Printf("error when serving connection %q<->%q: %v", c.LocalAddr(), c.RemoteAddr(), err)
+ }
+ }
+ if err == errHijacked {
+ wp.connState(c, StateHijacked)
+ } else {
+ _ = c.Close()
+ wp.connState(c, StateClosed)
+ }
+ c = nil
+
+ if !wp.release(ch) {
+ break
+ }
+ }
+
+ wp.lock.Lock()
+ wp.workersCount--
+ wp.lock.Unlock()
+}
diff --git a/vendor/golang.org/x/exp/LICENSE b/vendor/golang.org/x/exp/LICENSE
new file mode 100644
index 0000000..2a7cf70
--- /dev/null
+++ b/vendor/golang.org/x/exp/LICENSE
@@ -0,0 +1,27 @@
+Copyright 2009 The Go Authors.
+
+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 LLC 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.
diff --git a/vendor/golang.org/x/exp/PATENTS b/vendor/golang.org/x/exp/PATENTS
new file mode 100644
index 0000000..7330990
--- /dev/null
+++ b/vendor/golang.org/x/exp/PATENTS
@@ -0,0 +1,22 @@
+Additional IP Rights Grant (Patents)
+
+"This implementation" means the copyrightable works distributed by
+Google as part of the Go project.
+
+Google 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,
+transfer and otherwise run, modify and propagate the contents of this
+implementation of Go, where such license applies only to those patent
+claims, both currently owned or controlled by Google and acquired in
+the future, licensable by Google that are necessarily infringed by this
+implementation of Go. This grant does not include claims that would be
+infringed only as a consequence of further modification of this
+implementation. If you or your agent or exclusive licensee institute or
+order or agree to the institution of patent litigation against any
+entity (including a cross-claim or counterclaim in a lawsuit) alleging
+that this implementation of Go or any code incorporated within this
+implementation of Go constitutes direct or contributory patent
+infringement, or inducement of patent infringement, then any patent
+rights granted to you under this License for this implementation of Go
+shall terminate as of the date such litigation is filed.
diff --git a/vendor/golang.org/x/exp/constraints/constraints.go b/vendor/golang.org/x/exp/constraints/constraints.go
new file mode 100644
index 0000000..2c033df
--- /dev/null
+++ b/vendor/golang.org/x/exp/constraints/constraints.go
@@ -0,0 +1,50 @@
+// Copyright 2021 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 constraints defines a set of useful constraints to be used
+// with type parameters.
+package constraints
+
+// Signed is a constraint that permits any signed integer type.
+// If future releases of Go add new predeclared signed integer types,
+// this constraint will be modified to include them.
+type Signed interface {
+ ~int | ~int8 | ~int16 | ~int32 | ~int64
+}
+
+// Unsigned is a constraint that permits any unsigned integer type.
+// If future releases of Go add new predeclared unsigned integer types,
+// this constraint will be modified to include them.
+type Unsigned interface {
+ ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr
+}
+
+// Integer is a constraint that permits any integer type.
+// If future releases of Go add new predeclared integer types,
+// this constraint will be modified to include them.
+type Integer interface {
+ Signed | Unsigned
+}
+
+// Float is a constraint that permits any floating-point type.
+// If future releases of Go add new predeclared floating-point types,
+// this constraint will be modified to include them.
+type Float interface {
+ ~float32 | ~float64
+}
+
+// Complex is a constraint that permits any complex numeric type.
+// If future releases of Go add new predeclared complex numeric types,
+// this constraint will be modified to include them.
+type Complex interface {
+ ~complex64 | ~complex128
+}
+
+// Ordered is a constraint that permits any ordered type: any type
+// that supports the operators < <= >= >.
+// If future releases of Go add new ordered types,
+// this constraint will be modified to include them.
+type Ordered interface {
+ Integer | Float | ~string
+}
diff --git a/vendor/golang.org/x/net/LICENSE b/vendor/golang.org/x/net/LICENSE
new file mode 100644
index 0000000..6a66aea
--- /dev/null
+++ b/vendor/golang.org/x/net/LICENSE
@@ -0,0 +1,27 @@
+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.
diff --git a/vendor/golang.org/x/net/PATENTS b/vendor/golang.org/x/net/PATENTS
new file mode 100644
index 0000000..7330990
--- /dev/null
+++ b/vendor/golang.org/x/net/PATENTS
@@ -0,0 +1,22 @@
+Additional IP Rights Grant (Patents)
+
+"This implementation" means the copyrightable works distributed by
+Google as part of the Go project.
+
+Google 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,
+transfer and otherwise run, modify and propagate the contents of this
+implementation of Go, where such license applies only to those patent
+claims, both currently owned or controlled by Google and acquired in
+the future, licensable by Google that are necessarily infringed by this
+implementation of Go. This grant does not include claims that would be
+infringed only as a consequence of further modification of this
+implementation. If you or your agent or exclusive licensee institute or
+order or agree to the institution of patent litigation against any
+entity (including a cross-claim or counterclaim in a lawsuit) alleging
+that this implementation of Go or any code incorporated within this
+implementation of Go constitutes direct or contributory patent
+infringement, or inducement of patent infringement, then any patent
+rights granted to you under this License for this implementation of Go
+shall terminate as of the date such litigation is filed.
diff --git a/vendor/golang.org/x/net/internal/socks/client.go b/vendor/golang.org/x/net/internal/socks/client.go
new file mode 100644
index 0000000..3d6f516
--- /dev/null
+++ b/vendor/golang.org/x/net/internal/socks/client.go
@@ -0,0 +1,168 @@
+// Copyright 2018 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 socks
+
+import (
+ "context"
+ "errors"
+ "io"
+ "net"
+ "strconv"
+ "time"
+)
+
+var (
+ noDeadline = time.Time{}
+ aLongTimeAgo = time.Unix(1, 0)
+)
+
+func (d *Dialer) connect(ctx context.Context, c net.Conn, address string) (_ net.Addr, ctxErr error) {
+ host, port, err := splitHostPort(address)
+ if err != nil {
+ return nil, err
+ }
+ if deadline, ok := ctx.Deadline(); ok && !deadline.IsZero() {
+ c.SetDeadline(deadline)
+ defer c.SetDeadline(noDeadline)
+ }
+ if ctx != context.Background() {
+ errCh := make(chan error, 1)
+ done := make(chan struct{})
+ defer func() {
+ close(done)
+ if ctxErr == nil {
+ ctxErr = <-errCh
+ }
+ }()
+ go func() {
+ select {
+ case <-ctx.Done():
+ c.SetDeadline(aLongTimeAgo)
+ errCh <- ctx.Err()
+ case <-done:
+ errCh <- nil
+ }
+ }()
+ }
+
+ b := make([]byte, 0, 6+len(host)) // the size here is just an estimate
+ b = append(b, Version5)
+ if len(d.AuthMethods) == 0 || d.Authenticate == nil {
+ b = append(b, 1, byte(AuthMethodNotRequired))
+ } else {
+ ams := d.AuthMethods
+ if len(ams) > 255 {
+ return nil, errors.New("too many authentication methods")
+ }
+ b = append(b, byte(len(ams)))
+ for _, am := range ams {
+ b = append(b, byte(am))
+ }
+ }
+ if _, ctxErr = c.Write(b); ctxErr != nil {
+ return
+ }
+
+ if _, ctxErr = io.ReadFull(c, b[:2]); ctxErr != nil {
+ return
+ }
+ if b[0] != Version5 {
+ return nil, errors.New("unexpected protocol version " + strconv.Itoa(int(b[0])))
+ }
+ am := AuthMethod(b[1])
+ if am == AuthMethodNoAcceptableMethods {
+ return nil, errors.New("no acceptable authentication methods")
+ }
+ if d.Authenticate != nil {
+ if ctxErr = d.Authenticate(ctx, c, am); ctxErr != nil {
+ return
+ }
+ }
+
+ b = b[:0]
+ b = append(b, Version5, byte(d.cmd), 0)
+ if ip := net.ParseIP(host); ip != nil {
+ if ip4 := ip.To4(); ip4 != nil {
+ b = append(b, AddrTypeIPv4)
+ b = append(b, ip4...)
+ } else if ip6 := ip.To16(); ip6 != nil {
+ b = append(b, AddrTypeIPv6)
+ b = append(b, ip6...)
+ } else {
+ return nil, errors.New("unknown address type")
+ }
+ } else {
+ if len(host) > 255 {
+ return nil, errors.New("FQDN too long")
+ }
+ b = append(b, AddrTypeFQDN)
+ b = append(b, byte(len(host)))
+ b = append(b, host...)
+ }
+ b = append(b, byte(port>>8), byte(port))
+ if _, ctxErr = c.Write(b); ctxErr != nil {
+ return
+ }
+
+ if _, ctxErr = io.ReadFull(c, b[:4]); ctxErr != nil {
+ return
+ }
+ if b[0] != Version5 {
+ return nil, errors.New("unexpected protocol version " + strconv.Itoa(int(b[0])))
+ }
+ if cmdErr := Reply(b[1]); cmdErr != StatusSucceeded {
+ return nil, errors.New("unknown error " + cmdErr.String())
+ }
+ if b[2] != 0 {
+ return nil, errors.New("non-zero reserved field")
+ }
+ l := 2
+ var a Addr
+ switch b[3] {
+ case AddrTypeIPv4:
+ l += net.IPv4len
+ a.IP = make(net.IP, net.IPv4len)
+ case AddrTypeIPv6:
+ l += net.IPv6len
+ a.IP = make(net.IP, net.IPv6len)
+ case AddrTypeFQDN:
+ if _, err := io.ReadFull(c, b[:1]); err != nil {
+ return nil, err
+ }
+ l += int(b[0])
+ default:
+ return nil, errors.New("unknown address type " + strconv.Itoa(int(b[3])))
+ }
+ if cap(b) < l {
+ b = make([]byte, l)
+ } else {
+ b = b[:l]
+ }
+ if _, ctxErr = io.ReadFull(c, b); ctxErr != nil {
+ return
+ }
+ if a.IP != nil {
+ copy(a.IP, b)
+ } else {
+ a.Name = string(b[:len(b)-2])
+ }
+ a.Port = int(b[len(b)-2])<<8 | int(b[len(b)-1])
+ return &a, nil
+}
+
+func splitHostPort(address string) (string, int, error) {
+ host, port, err := net.SplitHostPort(address)
+ if err != nil {
+ return "", 0, err
+ }
+ portnum, err := strconv.Atoi(port)
+ if err != nil {
+ return "", 0, err
+ }
+ if 1 > portnum || portnum > 0xffff {
+ return "", 0, errors.New("port number out of range " + port)
+ }
+ return host, portnum, nil
+}
diff --git a/vendor/golang.org/x/net/internal/socks/socks.go b/vendor/golang.org/x/net/internal/socks/socks.go
new file mode 100644
index 0000000..84fcc32
--- /dev/null
+++ b/vendor/golang.org/x/net/internal/socks/socks.go
@@ -0,0 +1,317 @@
+// Copyright 2018 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 socks provides a SOCKS version 5 client implementation.
+//
+// SOCKS protocol version 5 is defined in RFC 1928.
+// Username/Password authentication for SOCKS version 5 is defined in
+// RFC 1929.
+package socks
+
+import (
+ "context"
+ "errors"
+ "io"
+ "net"
+ "strconv"
+)
+
+// A Command represents a SOCKS command.
+type Command int
+
+func (cmd Command) String() string {
+ switch cmd {
+ case CmdConnect:
+ return "socks connect"
+ case cmdBind:
+ return "socks bind"
+ default:
+ return "socks " + strconv.Itoa(int(cmd))
+ }
+}
+
+// An AuthMethod represents a SOCKS authentication method.
+type AuthMethod int
+
+// A Reply represents a SOCKS command reply code.
+type Reply int
+
+func (code Reply) String() string {
+ switch code {
+ case StatusSucceeded:
+ return "succeeded"
+ case 0x01:
+ return "general SOCKS server failure"
+ case 0x02:
+ return "connection not allowed by ruleset"
+ case 0x03:
+ return "network unreachable"
+ case 0x04:
+ return "host unreachable"
+ case 0x05:
+ return "connection refused"
+ case 0x06:
+ return "TTL expired"
+ case 0x07:
+ return "command not supported"
+ case 0x08:
+ return "address type not supported"
+ default:
+ return "unknown code: " + strconv.Itoa(int(code))
+ }
+}
+
+// Wire protocol constants.
+const (
+ Version5 = 0x05
+
+ AddrTypeIPv4 = 0x01
+ AddrTypeFQDN = 0x03
+ AddrTypeIPv6 = 0x04
+
+ CmdConnect Command = 0x01 // establishes an active-open forward proxy connection
+ cmdBind Command = 0x02 // establishes a passive-open forward proxy connection
+
+ AuthMethodNotRequired AuthMethod = 0x00 // no authentication required
+ AuthMethodUsernamePassword AuthMethod = 0x02 // use username/password
+ AuthMethodNoAcceptableMethods AuthMethod = 0xff // no acceptable authentication methods
+
+ StatusSucceeded Reply = 0x00
+)
+
+// An Addr represents a SOCKS-specific address.
+// Either Name or IP is used exclusively.
+type Addr struct {
+ Name string // fully-qualified domain name
+ IP net.IP
+ Port int
+}
+
+func (a *Addr) Network() string { return "socks" }
+
+func (a *Addr) String() string {
+ if a == nil {
+ return ""
+ }
+ port := strconv.Itoa(a.Port)
+ if a.IP == nil {
+ return net.JoinHostPort(a.Name, port)
+ }
+ return net.JoinHostPort(a.IP.String(), port)
+}
+
+// A Conn represents a forward proxy connection.
+type Conn struct {
+ net.Conn
+
+ boundAddr net.Addr
+}
+
+// BoundAddr returns the address assigned by the proxy server for
+// connecting to the command target address from the proxy server.
+func (c *Conn) BoundAddr() net.Addr {
+ if c == nil {
+ return nil
+ }
+ return c.boundAddr
+}
+
+// A Dialer holds SOCKS-specific options.
+type Dialer struct {
+ cmd Command // either CmdConnect or cmdBind
+ proxyNetwork string // network between a proxy server and a client
+ proxyAddress string // proxy server address
+
+ // ProxyDial specifies the optional dial function for
+ // establishing the transport connection.
+ ProxyDial func(context.Context, string, string) (net.Conn, error)
+
+ // AuthMethods specifies the list of request authentication
+ // methods.
+ // If empty, SOCKS client requests only AuthMethodNotRequired.
+ AuthMethods []AuthMethod
+
+ // Authenticate specifies the optional authentication
+ // function. It must be non-nil when AuthMethods is not empty.
+ // It must return an error when the authentication is failed.
+ Authenticate func(context.Context, io.ReadWriter, AuthMethod) error
+}
+
+// DialContext connects to the provided address on the provided
+// network.
+//
+// The returned error value may be a net.OpError. When the Op field of
+// net.OpError contains "socks", the Source field contains a proxy
+// server address and the Addr field contains a command target
+// address.
+//
+// See func Dial of the net package of standard library for a
+// description of the network and address parameters.
+func (d *Dialer) DialContext(ctx context.Context, network, address string) (net.Conn, error) {
+ if err := d.validateTarget(network, address); err != nil {
+ proxy, dst, _ := d.pathAddrs(address)
+ return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err}
+ }
+ if ctx == nil {
+ proxy, dst, _ := d.pathAddrs(address)
+ return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: errors.New("nil context")}
+ }
+ var err error
+ var c net.Conn
+ if d.ProxyDial != nil {
+ c, err = d.ProxyDial(ctx, d.proxyNetwork, d.proxyAddress)
+ } else {
+ var dd net.Dialer
+ c, err = dd.DialContext(ctx, d.proxyNetwork, d.proxyAddress)
+ }
+ if err != nil {
+ proxy, dst, _ := d.pathAddrs(address)
+ return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err}
+ }
+ a, err := d.connect(ctx, c, address)
+ if err != nil {
+ c.Close()
+ proxy, dst, _ := d.pathAddrs(address)
+ return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err}
+ }
+ return &Conn{Conn: c, boundAddr: a}, nil
+}
+
+// DialWithConn initiates a connection from SOCKS server to the target
+// network and address using the connection c that is already
+// connected to the SOCKS server.
+//
+// It returns the connection's local address assigned by the SOCKS
+// server.
+func (d *Dialer) DialWithConn(ctx context.Context, c net.Conn, network, address string) (net.Addr, error) {
+ if err := d.validateTarget(network, address); err != nil {
+ proxy, dst, _ := d.pathAddrs(address)
+ return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err}
+ }
+ if ctx == nil {
+ proxy, dst, _ := d.pathAddrs(address)
+ return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: errors.New("nil context")}
+ }
+ a, err := d.connect(ctx, c, address)
+ if err != nil {
+ proxy, dst, _ := d.pathAddrs(address)
+ return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err}
+ }
+ return a, nil
+}
+
+// Dial connects to the provided address on the provided network.
+//
+// Unlike DialContext, it returns a raw transport connection instead
+// of a forward proxy connection.
+//
+// Deprecated: Use DialContext or DialWithConn instead.
+func (d *Dialer) Dial(network, address string) (net.Conn, error) {
+ if err := d.validateTarget(network, address); err != nil {
+ proxy, dst, _ := d.pathAddrs(address)
+ return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err}
+ }
+ var err error
+ var c net.Conn
+ if d.ProxyDial != nil {
+ c, err = d.ProxyDial(context.Background(), d.proxyNetwork, d.proxyAddress)
+ } else {
+ c, err = net.Dial(d.proxyNetwork, d.proxyAddress)
+ }
+ if err != nil {
+ proxy, dst, _ := d.pathAddrs(address)
+ return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err}
+ }
+ if _, err := d.DialWithConn(context.Background(), c, network, address); err != nil {
+ c.Close()
+ return nil, err
+ }
+ return c, nil
+}
+
+func (d *Dialer) validateTarget(network, address string) error {
+ switch network {
+ case "tcp", "tcp6", "tcp4":
+ default:
+ return errors.New("network not implemented")
+ }
+ switch d.cmd {
+ case CmdConnect, cmdBind:
+ default:
+ return errors.New("command not implemented")
+ }
+ return nil
+}
+
+func (d *Dialer) pathAddrs(address string) (proxy, dst net.Addr, err error) {
+ for i, s := range []string{d.proxyAddress, address} {
+ host, port, err := splitHostPort(s)
+ if err != nil {
+ return nil, nil, err
+ }
+ a := &Addr{Port: port}
+ a.IP = net.ParseIP(host)
+ if a.IP == nil {
+ a.Name = host
+ }
+ if i == 0 {
+ proxy = a
+ } else {
+ dst = a
+ }
+ }
+ return
+}
+
+// NewDialer returns a new Dialer that dials through the provided
+// proxy server's network and address.
+func NewDialer(network, address string) *Dialer {
+ return &Dialer{proxyNetwork: network, proxyAddress: address, cmd: CmdConnect}
+}
+
+const (
+ authUsernamePasswordVersion = 0x01
+ authStatusSucceeded = 0x00
+)
+
+// UsernamePassword are the credentials for the username/password
+// authentication method.
+type UsernamePassword struct {
+ Username string
+ Password string
+}
+
+// Authenticate authenticates a pair of username and password with the
+// proxy server.
+func (up *UsernamePassword) Authenticate(ctx context.Context, rw io.ReadWriter, auth AuthMethod) error {
+ switch auth {
+ case AuthMethodNotRequired:
+ return nil
+ case AuthMethodUsernamePassword:
+ if len(up.Username) == 0 || len(up.Username) > 255 || len(up.Password) > 255 {
+ return errors.New("invalid username/password")
+ }
+ b := []byte{authUsernamePasswordVersion}
+ b = append(b, byte(len(up.Username)))
+ b = append(b, up.Username...)
+ b = append(b, byte(len(up.Password)))
+ b = append(b, up.Password...)
+ // TODO(mikio): handle IO deadlines and cancelation if
+ // necessary
+ if _, err := rw.Write(b); err != nil {
+ return err
+ }
+ if _, err := io.ReadFull(rw, b[:2]); err != nil {
+ return err
+ }
+ if b[0] != authUsernamePasswordVersion {
+ return errors.New("invalid username/password version")
+ }
+ if b[1] != authStatusSucceeded {
+ return errors.New("username/password authentication failed")
+ }
+ return nil
+ }
+ return errors.New("unsupported authentication method " + strconv.Itoa(int(auth)))
+}
diff --git a/vendor/golang.org/x/net/proxy/dial.go b/vendor/golang.org/x/net/proxy/dial.go
new file mode 100644
index 0000000..811c2e4
--- /dev/null
+++ b/vendor/golang.org/x/net/proxy/dial.go
@@ -0,0 +1,54 @@
+// Copyright 2019 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 proxy
+
+import (
+ "context"
+ "net"
+)
+
+// A ContextDialer dials using a context.
+type ContextDialer interface {
+ DialContext(ctx context.Context, network, address string) (net.Conn, error)
+}
+
+// Dial works like DialContext on net.Dialer but using a dialer returned by FromEnvironment.
+//
+// The passed ctx is only used for returning the Conn, not the lifetime of the Conn.
+//
+// Custom dialers (registered via RegisterDialerType) that do not implement ContextDialer
+// can leak a goroutine for as long as it takes the underlying Dialer implementation to timeout.
+//
+// A Conn returned from a successful Dial after the context has been cancelled will be immediately closed.
+func Dial(ctx context.Context, network, address string) (net.Conn, error) {
+ d := FromEnvironment()
+ if xd, ok := d.(ContextDialer); ok {
+ return xd.DialContext(ctx, network, address)
+ }
+ return dialContext(ctx, d, network, address)
+}
+
+// WARNING: this can leak a goroutine for as long as the underlying Dialer implementation takes to timeout
+// A Conn returned from a successful Dial after the context has been cancelled will be immediately closed.
+func dialContext(ctx context.Context, d Dialer, network, address string) (net.Conn, error) {
+ var (
+ conn net.Conn
+ done = make(chan struct{}, 1)
+ err error
+ )
+ go func() {
+ conn, err = d.Dial(network, address)
+ close(done)
+ if conn != nil && ctx.Err() != nil {
+ conn.Close()
+ }
+ }()
+ select {
+ case <-ctx.Done():
+ err = ctx.Err()
+ case <-done:
+ }
+ return conn, err
+}
diff --git a/vendor/golang.org/x/net/proxy/direct.go b/vendor/golang.org/x/net/proxy/direct.go
new file mode 100644
index 0000000..3d66bde
--- /dev/null
+++ b/vendor/golang.org/x/net/proxy/direct.go
@@ -0,0 +1,31 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package proxy
+
+import (
+ "context"
+ "net"
+)
+
+type direct struct{}
+
+// Direct implements Dialer by making network connections directly using net.Dial or net.DialContext.
+var Direct = direct{}
+
+var (
+ _ Dialer = Direct
+ _ ContextDialer = Direct
+)
+
+// Dial directly invokes net.Dial with the supplied parameters.
+func (direct) Dial(network, addr string) (net.Conn, error) {
+ return net.Dial(network, addr)
+}
+
+// DialContext instantiates a net.Dialer and invokes its DialContext receiver with the supplied parameters.
+func (direct) DialContext(ctx context.Context, network, addr string) (net.Conn, error) {
+ var d net.Dialer
+ return d.DialContext(ctx, network, addr)
+}
diff --git a/vendor/golang.org/x/net/proxy/per_host.go b/vendor/golang.org/x/net/proxy/per_host.go
new file mode 100644
index 0000000..573fe79
--- /dev/null
+++ b/vendor/golang.org/x/net/proxy/per_host.go
@@ -0,0 +1,155 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package proxy
+
+import (
+ "context"
+ "net"
+ "strings"
+)
+
+// A PerHost directs connections to a default Dialer unless the host name
+// requested matches one of a number of exceptions.
+type PerHost struct {
+ def, bypass Dialer
+
+ bypassNetworks []*net.IPNet
+ bypassIPs []net.IP
+ bypassZones []string
+ bypassHosts []string
+}
+
+// NewPerHost returns a PerHost Dialer that directs connections to either
+// defaultDialer or bypass, depending on whether the connection matches one of
+// the configured rules.
+func NewPerHost(defaultDialer, bypass Dialer) *PerHost {
+ return &PerHost{
+ def: defaultDialer,
+ bypass: bypass,
+ }
+}
+
+// Dial connects to the address addr on the given network through either
+// defaultDialer or bypass.
+func (p *PerHost) Dial(network, addr string) (c net.Conn, err error) {
+ host, _, err := net.SplitHostPort(addr)
+ if err != nil {
+ return nil, err
+ }
+
+ return p.dialerForRequest(host).Dial(network, addr)
+}
+
+// DialContext connects to the address addr on the given network through either
+// defaultDialer or bypass.
+func (p *PerHost) DialContext(ctx context.Context, network, addr string) (c net.Conn, err error) {
+ host, _, err := net.SplitHostPort(addr)
+ if err != nil {
+ return nil, err
+ }
+ d := p.dialerForRequest(host)
+ if x, ok := d.(ContextDialer); ok {
+ return x.DialContext(ctx, network, addr)
+ }
+ return dialContext(ctx, d, network, addr)
+}
+
+func (p *PerHost) dialerForRequest(host string) Dialer {
+ if ip := net.ParseIP(host); ip != nil {
+ for _, net := range p.bypassNetworks {
+ if net.Contains(ip) {
+ return p.bypass
+ }
+ }
+ for _, bypassIP := range p.bypassIPs {
+ if bypassIP.Equal(ip) {
+ return p.bypass
+ }
+ }
+ return p.def
+ }
+
+ for _, zone := range p.bypassZones {
+ if strings.HasSuffix(host, zone) {
+ return p.bypass
+ }
+ if host == zone[1:] {
+ // For a zone ".example.com", we match "example.com"
+ // too.
+ return p.bypass
+ }
+ }
+ for _, bypassHost := range p.bypassHosts {
+ if bypassHost == host {
+ return p.bypass
+ }
+ }
+ return p.def
+}
+
+// AddFromString parses a string that contains comma-separated values
+// specifying hosts that should use the bypass proxy. Each value is either an
+// IP address, a CIDR range, a zone (*.example.com) or a host name
+// (localhost). A best effort is made to parse the string and errors are
+// ignored.
+func (p *PerHost) AddFromString(s string) {
+ hosts := strings.Split(s, ",")
+ for _, host := range hosts {
+ host = strings.TrimSpace(host)
+ if len(host) == 0 {
+ continue
+ }
+ if strings.Contains(host, "/") {
+ // We assume that it's a CIDR address like 127.0.0.0/8
+ if _, net, err := net.ParseCIDR(host); err == nil {
+ p.AddNetwork(net)
+ }
+ continue
+ }
+ if ip := net.ParseIP(host); ip != nil {
+ p.AddIP(ip)
+ continue
+ }
+ if strings.HasPrefix(host, "*.") {
+ p.AddZone(host[1:])
+ continue
+ }
+ p.AddHost(host)
+ }
+}
+
+// AddIP specifies an IP address that will use the bypass proxy. Note that
+// this will only take effect if a literal IP address is dialed. A connection
+// to a named host will never match an IP.
+func (p *PerHost) AddIP(ip net.IP) {
+ p.bypassIPs = append(p.bypassIPs, ip)
+}
+
+// AddNetwork specifies an IP range that will use the bypass proxy. Note that
+// this will only take effect if a literal IP address is dialed. A connection
+// to a named host will never match.
+func (p *PerHost) AddNetwork(net *net.IPNet) {
+ p.bypassNetworks = append(p.bypassNetworks, net)
+}
+
+// AddZone specifies a DNS suffix that will use the bypass proxy. A zone of
+// "example.com" matches "example.com" and all of its subdomains.
+func (p *PerHost) AddZone(zone string) {
+ if strings.HasSuffix(zone, ".") {
+ zone = zone[:len(zone)-1]
+ }
+ if !strings.HasPrefix(zone, ".") {
+ zone = "." + zone
+ }
+ p.bypassZones = append(p.bypassZones, zone)
+}
+
+// AddHost specifies a host name that will use the bypass proxy.
+func (p *PerHost) AddHost(host string) {
+ if strings.HasSuffix(host, ".") {
+ host = host[:len(host)-1]
+ }
+ p.bypassHosts = append(p.bypassHosts, host)
+}
diff --git a/vendor/golang.org/x/net/proxy/proxy.go b/vendor/golang.org/x/net/proxy/proxy.go
new file mode 100644
index 0000000..9ff4b9a
--- /dev/null
+++ b/vendor/golang.org/x/net/proxy/proxy.go
@@ -0,0 +1,149 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package proxy provides support for a variety of protocols to proxy network
+// data.
+package proxy // import "golang.org/x/net/proxy"
+
+import (
+ "errors"
+ "net"
+ "net/url"
+ "os"
+ "sync"
+)
+
+// A Dialer is a means to establish a connection.
+// Custom dialers should also implement ContextDialer.
+type Dialer interface {
+ // Dial connects to the given address via the proxy.
+ Dial(network, addr string) (c net.Conn, err error)
+}
+
+// Auth contains authentication parameters that specific Dialers may require.
+type Auth struct {
+ User, Password string
+}
+
+// FromEnvironment returns the dialer specified by the proxy-related
+// variables in the environment and makes underlying connections
+// directly.
+func FromEnvironment() Dialer {
+ return FromEnvironmentUsing(Direct)
+}
+
+// FromEnvironmentUsing returns the dialer specify by the proxy-related
+// variables in the environment and makes underlying connections
+// using the provided forwarding Dialer (for instance, a *net.Dialer
+// with desired configuration).
+func FromEnvironmentUsing(forward Dialer) Dialer {
+ allProxy := allProxyEnv.Get()
+ if len(allProxy) == 0 {
+ return forward
+ }
+
+ proxyURL, err := url.Parse(allProxy)
+ if err != nil {
+ return forward
+ }
+ proxy, err := FromURL(proxyURL, forward)
+ if err != nil {
+ return forward
+ }
+
+ noProxy := noProxyEnv.Get()
+ if len(noProxy) == 0 {
+ return proxy
+ }
+
+ perHost := NewPerHost(proxy, forward)
+ perHost.AddFromString(noProxy)
+ return perHost
+}
+
+// proxySchemes is a map from URL schemes to a function that creates a Dialer
+// from a URL with such a scheme.
+var proxySchemes map[string]func(*url.URL, Dialer) (Dialer, error)
+
+// RegisterDialerType takes a URL scheme and a function to generate Dialers from
+// a URL with that scheme and a forwarding Dialer. Registered schemes are used
+// by FromURL.
+func RegisterDialerType(scheme string, f func(*url.URL, Dialer) (Dialer, error)) {
+ if proxySchemes == nil {
+ proxySchemes = make(map[string]func(*url.URL, Dialer) (Dialer, error))
+ }
+ proxySchemes[scheme] = f
+}
+
+// FromURL returns a Dialer given a URL specification and an underlying
+// Dialer for it to make network requests.
+func FromURL(u *url.URL, forward Dialer) (Dialer, error) {
+ var auth *Auth
+ if u.User != nil {
+ auth = new(Auth)
+ auth.User = u.User.Username()
+ if p, ok := u.User.Password(); ok {
+ auth.Password = p
+ }
+ }
+
+ switch u.Scheme {
+ case "socks5", "socks5h":
+ addr := u.Hostname()
+ port := u.Port()
+ if port == "" {
+ port = "1080"
+ }
+ return SOCKS5("tcp", net.JoinHostPort(addr, port), auth, forward)
+ }
+
+ // If the scheme doesn't match any of the built-in schemes, see if it
+ // was registered by another package.
+ if proxySchemes != nil {
+ if f, ok := proxySchemes[u.Scheme]; ok {
+ return f(u, forward)
+ }
+ }
+
+ return nil, errors.New("proxy: unknown scheme: " + u.Scheme)
+}
+
+var (
+ allProxyEnv = &envOnce{
+ names: []string{"ALL_PROXY", "all_proxy"},
+ }
+ noProxyEnv = &envOnce{
+ names: []string{"NO_PROXY", "no_proxy"},
+ }
+)
+
+// envOnce looks up an environment variable (optionally by multiple
+// names) once. It mitigates expensive lookups on some platforms
+// (e.g. Windows).
+// (Borrowed from net/http/transport.go)
+type envOnce struct {
+ names []string
+ once sync.Once
+ val string
+}
+
+func (e *envOnce) Get() string {
+ e.once.Do(e.init)
+ return e.val
+}
+
+func (e *envOnce) init() {
+ for _, n := range e.names {
+ e.val = os.Getenv(n)
+ if e.val != "" {
+ return
+ }
+ }
+}
+
+// reset is used by tests
+func (e *envOnce) reset() {
+ e.once = sync.Once{}
+ e.val = ""
+}
diff --git a/vendor/golang.org/x/net/proxy/socks5.go b/vendor/golang.org/x/net/proxy/socks5.go
new file mode 100644
index 0000000..c91651f
--- /dev/null
+++ b/vendor/golang.org/x/net/proxy/socks5.go
@@ -0,0 +1,42 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package proxy
+
+import (
+ "context"
+ "net"
+
+ "golang.org/x/net/internal/socks"
+)
+
+// SOCKS5 returns a Dialer that makes SOCKSv5 connections to the given
+// address with an optional username and password.
+// See RFC 1928 and RFC 1929.
+func SOCKS5(network, address string, auth *Auth, forward Dialer) (Dialer, error) {
+ d := socks.NewDialer(network, address)
+ if forward != nil {
+ if f, ok := forward.(ContextDialer); ok {
+ d.ProxyDial = func(ctx context.Context, network string, address string) (net.Conn, error) {
+ return f.DialContext(ctx, network, address)
+ }
+ } else {
+ d.ProxyDial = func(ctx context.Context, network string, address string) (net.Conn, error) {
+ return dialContext(ctx, forward, network, address)
+ }
+ }
+ }
+ if auth != nil {
+ up := socks.UsernamePassword{
+ Username: auth.User,
+ Password: auth.Password,
+ }
+ d.AuthMethods = []socks.AuthMethod{
+ socks.AuthMethodNotRequired,
+ socks.AuthMethodUsernamePassword,
+ }
+ d.Authenticate = up.Authenticate
+ }
+ return d, nil
+}
diff --git a/vendor/golang.org/x/sys/LICENSE b/vendor/golang.org/x/sys/LICENSE
new file mode 100644
index 0000000..2a7cf70
--- /dev/null
+++ b/vendor/golang.org/x/sys/LICENSE
@@ -0,0 +1,27 @@
+Copyright 2009 The Go Authors.
+
+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 LLC 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.
diff --git a/vendor/golang.org/x/sys/PATENTS b/vendor/golang.org/x/sys/PATENTS
new file mode 100644
index 0000000..7330990
--- /dev/null
+++ b/vendor/golang.org/x/sys/PATENTS
@@ -0,0 +1,22 @@
+Additional IP Rights Grant (Patents)
+
+"This implementation" means the copyrightable works distributed by
+Google as part of the Go project.
+
+Google 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,
+transfer and otherwise run, modify and propagate the contents of this
+implementation of Go, where such license applies only to those patent
+claims, both currently owned or controlled by Google and acquired in
+the future, licensable by Google that are necessarily infringed by this
+implementation of Go. This grant does not include claims that would be
+infringed only as a consequence of further modification of this
+implementation. If you or your agent or exclusive licensee institute or
+order or agree to the institution of patent litigation against any
+entity (including a cross-claim or counterclaim in a lawsuit) alleging
+that this implementation of Go or any code incorporated within this
+implementation of Go constitutes direct or contributory patent
+infringement, or inducement of patent infringement, then any patent
+rights granted to you under this License for this implementation of Go
+shall terminate as of the date such litigation is filed.
diff --git a/vendor/golang.org/x/sys/unix/.gitignore b/vendor/golang.org/x/sys/unix/.gitignore
new file mode 100644
index 0000000..e3e0fc6
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/.gitignore
@@ -0,0 +1,2 @@
+_obj/
+unix.test
diff --git a/vendor/golang.org/x/sys/unix/README.md b/vendor/golang.org/x/sys/unix/README.md
new file mode 100644
index 0000000..7d3c060
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/README.md
@@ -0,0 +1,184 @@
+# Building `sys/unix`
+
+The sys/unix package provides access to the raw system call interface of the
+underlying operating system. See: https://godoc.org/golang.org/x/sys/unix
+
+Porting Go to a new architecture/OS combination or adding syscalls, types, or
+constants to an existing architecture/OS pair requires some manual effort;
+however, there are tools that automate much of the process.
+
+## Build Systems
+
+There are currently two ways we generate the necessary files. We are currently
+migrating the build system to use containers so the builds are reproducible.
+This is being done on an OS-by-OS basis. Please update this documentation as
+components of the build system change.
+
+### Old Build System (currently for `GOOS != "linux"`)
+
+The old build system generates the Go files based on the C header files
+present on your system. This means that files
+for a given GOOS/GOARCH pair must be generated on a system with that OS and
+architecture. This also means that the generated code can differ from system
+to system, based on differences in the header files.
+
+To avoid this, if you are using the old build system, only generate the Go
+files on an installation with unmodified header files. It is also important to
+keep track of which version of the OS the files were generated from (ex.
+Darwin 14 vs Darwin 15). This makes it easier to track the progress of changes
+and have each OS upgrade correspond to a single change.
+
+To build the files for your current OS and architecture, make sure GOOS and
+GOARCH are set correctly and run `mkall.sh`. This will generate the files for
+your specific system. Running `mkall.sh -n` shows the commands that will be run.
+
+Requirements: bash, go
+
+### New Build System (currently for `GOOS == "linux"`)
+
+The new build system uses a Docker container to generate the go files directly
+from source checkouts of the kernel and various system libraries. This means
+that on any platform that supports Docker, all the files using the new build
+system can be generated at once, and generated files will not change based on
+what the person running the scripts has installed on their computer.
+
+The OS specific files for the new build system are located in the `${GOOS}`
+directory, and the build is coordinated by the `${GOOS}/mkall.go` program. When
+the kernel or system library updates, modify the Dockerfile at
+`${GOOS}/Dockerfile` to checkout the new release of the source.
+
+To build all the files under the new build system, you must be on an amd64/Linux
+system and have your GOOS and GOARCH set accordingly. Running `mkall.sh` will
+then generate all of the files for all of the GOOS/GOARCH pairs in the new build
+system. Running `mkall.sh -n` shows the commands that will be run.
+
+Requirements: bash, go, docker
+
+## Component files
+
+This section describes the various files used in the code generation process.
+It also contains instructions on how to modify these files to add a new
+architecture/OS or to add additional syscalls, types, or constants. Note that
+if you are using the new build system, the scripts/programs cannot be called normally.
+They must be called from within the docker container.
+
+### asm files
+
+The hand-written assembly file at `asm_${GOOS}_${GOARCH}.s` implements system
+call dispatch. There are three entry points:
+```
+ func Syscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr)
+ func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr)
+ func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr)
+```
+The first and second are the standard ones; they differ only in how many
+arguments can be passed to the kernel. The third is for low-level use by the
+ForkExec wrapper. Unlike the first two, it does not call into the scheduler to
+let it know that a system call is running.
+
+When porting Go to a new architecture/OS, this file must be implemented for
+each GOOS/GOARCH pair.
+
+### mksysnum
+
+Mksysnum is a Go program located at `${GOOS}/mksysnum.go` (or `mksysnum_${GOOS}.go`
+for the old system). This program takes in a list of header files containing the
+syscall number declarations and parses them to produce the corresponding list of
+Go numeric constants. See `zsysnum_${GOOS}_${GOARCH}.go` for the generated
+constants.
+
+Adding new syscall numbers is mostly done by running the build on a sufficiently
+new installation of the target OS (or updating the source checkouts for the
+new build system). However, depending on the OS, you may need to update the
+parsing in mksysnum.
+
+### mksyscall.go
+
+The `syscall.go`, `syscall_${GOOS}.go`, `syscall_${GOOS}_${GOARCH}.go` are
+hand-written Go files which implement system calls (for unix, the specific OS,
+or the specific OS/Architecture pair respectively) that need special handling
+and list `//sys` comments giving prototypes for ones that can be generated.
+
+The mksyscall.go program takes the `//sys` and `//sysnb` comments and converts
+them into syscalls. This requires the name of the prototype in the comment to
+match a syscall number in the `zsysnum_${GOOS}_${GOARCH}.go` file. The function
+prototype can be exported (capitalized) or not.
+
+Adding a new syscall often just requires adding a new `//sys` function prototype
+with the desired arguments and a capitalized name so it is exported. However, if
+you want the interface to the syscall to be different, often one will make an
+unexported `//sys` prototype, and then write a custom wrapper in
+`syscall_${GOOS}.go`.
+
+### types files
+
+For each OS, there is a hand-written Go file at `${GOOS}/types.go` (or
+`types_${GOOS}.go` on the old system). This file includes standard C headers and
+creates Go type aliases to the corresponding C types. The file is then fed
+through godef to get the Go compatible definitions. Finally, the generated code
+is fed though mkpost.go to format the code correctly and remove any hidden or
+private identifiers. This cleaned-up code is written to
+`ztypes_${GOOS}_${GOARCH}.go`.
+
+The hardest part about preparing this file is figuring out which headers to
+include and which symbols need to be `#define`d to get the actual data
+structures that pass through to the kernel system calls. Some C libraries
+preset alternate versions for binary compatibility and translate them on the
+way in and out of system calls, but there is almost always a `#define` that can
+get the real ones.
+See `types_darwin.go` and `linux/types.go` for examples.
+
+To add a new type, add in the necessary include statement at the top of the
+file (if it is not already there) and add in a type alias line. Note that if
+your type is significantly different on different architectures, you may need
+some `#if/#elif` macros in your include statements.
+
+### mkerrors.sh
+
+This script is used to generate the system's various constants. This doesn't
+just include the error numbers and error strings, but also the signal numbers
+and a wide variety of miscellaneous constants. The constants come from the list
+of include files in the `includes_${uname}` variable. A regex then picks out
+the desired `#define` statements, and generates the corresponding Go constants.
+The error numbers and strings are generated from `#include `, and the
+signal numbers and strings are generated from `#include `. All of
+these constants are written to `zerrors_${GOOS}_${GOARCH}.go` via a C program,
+`_errors.c`, which prints out all the constants.
+
+To add a constant, add the header that includes it to the appropriate variable.
+Then, edit the regex (if necessary) to match the desired constant. Avoid making
+the regex too broad to avoid matching unintended constants.
+
+### internal/mkmerge
+
+This program is used to extract duplicate const, func, and type declarations
+from the generated architecture-specific files listed below, and merge these
+into a common file for each OS.
+
+The merge is performed in the following steps:
+1. Construct the set of common code that is idential in all architecture-specific files.
+2. Write this common code to the merged file.
+3. Remove the common code from all architecture-specific files.
+
+
+## Generated files
+
+### `zerrors_${GOOS}_${GOARCH}.go`
+
+A file containing all of the system's generated error numbers, error strings,
+signal numbers, and constants. Generated by `mkerrors.sh` (see above).
+
+### `zsyscall_${GOOS}_${GOARCH}.go`
+
+A file containing all the generated syscalls for a specific GOOS and GOARCH.
+Generated by `mksyscall.go` (see above).
+
+### `zsysnum_${GOOS}_${GOARCH}.go`
+
+A list of numeric constants for all the syscall number of the specific GOOS
+and GOARCH. Generated by mksysnum (see above).
+
+### `ztypes_${GOOS}_${GOARCH}.go`
+
+A file containing Go types for passing into (or returning from) syscalls.
+Generated by godefs and the types file (see above).
diff --git a/vendor/golang.org/x/sys/unix/affinity_linux.go b/vendor/golang.org/x/sys/unix/affinity_linux.go
new file mode 100644
index 0000000..6e5c81a
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/affinity_linux.go
@@ -0,0 +1,86 @@
+// Copyright 2018 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.
+
+// CPU affinity functions
+
+package unix
+
+import (
+ "math/bits"
+ "unsafe"
+)
+
+const cpuSetSize = _CPU_SETSIZE / _NCPUBITS
+
+// CPUSet represents a CPU affinity mask.
+type CPUSet [cpuSetSize]cpuMask
+
+func schedAffinity(trap uintptr, pid int, set *CPUSet) error {
+ _, _, e := RawSyscall(trap, uintptr(pid), uintptr(unsafe.Sizeof(*set)), uintptr(unsafe.Pointer(set)))
+ if e != 0 {
+ return errnoErr(e)
+ }
+ return nil
+}
+
+// SchedGetaffinity gets the CPU affinity mask of the thread specified by pid.
+// If pid is 0 the calling thread is used.
+func SchedGetaffinity(pid int, set *CPUSet) error {
+ return schedAffinity(SYS_SCHED_GETAFFINITY, pid, set)
+}
+
+// SchedSetaffinity sets the CPU affinity mask of the thread specified by pid.
+// If pid is 0 the calling thread is used.
+func SchedSetaffinity(pid int, set *CPUSet) error {
+ return schedAffinity(SYS_SCHED_SETAFFINITY, pid, set)
+}
+
+// Zero clears the set s, so that it contains no CPUs.
+func (s *CPUSet) Zero() {
+ for i := range s {
+ s[i] = 0
+ }
+}
+
+func cpuBitsIndex(cpu int) int {
+ return cpu / _NCPUBITS
+}
+
+func cpuBitsMask(cpu int) cpuMask {
+ return cpuMask(1 << (uint(cpu) % _NCPUBITS))
+}
+
+// Set adds cpu to the set s.
+func (s *CPUSet) Set(cpu int) {
+ i := cpuBitsIndex(cpu)
+ if i < len(s) {
+ s[i] |= cpuBitsMask(cpu)
+ }
+}
+
+// Clear removes cpu from the set s.
+func (s *CPUSet) Clear(cpu int) {
+ i := cpuBitsIndex(cpu)
+ if i < len(s) {
+ s[i] &^= cpuBitsMask(cpu)
+ }
+}
+
+// IsSet reports whether cpu is in the set s.
+func (s *CPUSet) IsSet(cpu int) bool {
+ i := cpuBitsIndex(cpu)
+ if i < len(s) {
+ return s[i]&cpuBitsMask(cpu) != 0
+ }
+ return false
+}
+
+// Count returns the number of CPUs in the set s.
+func (s *CPUSet) Count() int {
+ c := 0
+ for _, b := range s {
+ c += bits.OnesCount64(uint64(b))
+ }
+ return c
+}
diff --git a/vendor/golang.org/x/sys/unix/aliases.go b/vendor/golang.org/x/sys/unix/aliases.go
new file mode 100644
index 0000000..b0e4198
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/aliases.go
@@ -0,0 +1,13 @@
+// Copyright 2018 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.
+
+//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos
+
+package unix
+
+import "syscall"
+
+type Signal = syscall.Signal
+type Errno = syscall.Errno
+type SysProcAttr = syscall.SysProcAttr
diff --git a/vendor/golang.org/x/sys/unix/asm_aix_ppc64.s b/vendor/golang.org/x/sys/unix/asm_aix_ppc64.s
new file mode 100644
index 0000000..269e173
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/asm_aix_ppc64.s
@@ -0,0 +1,17 @@
+// Copyright 2018 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.
+
+//go:build gc
+
+#include "textflag.h"
+
+//
+// System calls for ppc64, AIX are implemented in runtime/syscall_aix.go
+//
+
+TEXT ·syscall6(SB),NOSPLIT,$0-88
+ JMP syscall·syscall6(SB)
+
+TEXT ·rawSyscall6(SB),NOSPLIT,$0-88
+ JMP syscall·rawSyscall6(SB)
diff --git a/vendor/golang.org/x/sys/unix/asm_bsd_386.s b/vendor/golang.org/x/sys/unix/asm_bsd_386.s
new file mode 100644
index 0000000..a4fcef0
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/asm_bsd_386.s
@@ -0,0 +1,27 @@
+// Copyright 2021 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.
+
+//go:build (freebsd || netbsd || openbsd) && gc
+
+#include "textflag.h"
+
+// System call support for 386 BSD
+
+// Just jump to package syscall's implementation for all these functions.
+// The runtime may know about them.
+
+TEXT ·Syscall(SB),NOSPLIT,$0-28
+ JMP syscall·Syscall(SB)
+
+TEXT ·Syscall6(SB),NOSPLIT,$0-40
+ JMP syscall·Syscall6(SB)
+
+TEXT ·Syscall9(SB),NOSPLIT,$0-52
+ JMP syscall·Syscall9(SB)
+
+TEXT ·RawSyscall(SB),NOSPLIT,$0-28
+ JMP syscall·RawSyscall(SB)
+
+TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
+ JMP syscall·RawSyscall6(SB)
diff --git a/vendor/golang.org/x/sys/unix/asm_bsd_amd64.s b/vendor/golang.org/x/sys/unix/asm_bsd_amd64.s
new file mode 100644
index 0000000..1e63615
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/asm_bsd_amd64.s
@@ -0,0 +1,27 @@
+// Copyright 2021 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.
+
+//go:build (darwin || dragonfly || freebsd || netbsd || openbsd) && gc
+
+#include "textflag.h"
+
+// System call support for AMD64 BSD
+
+// Just jump to package syscall's implementation for all these functions.
+// The runtime may know about them.
+
+TEXT ·Syscall(SB),NOSPLIT,$0-56
+ JMP syscall·Syscall(SB)
+
+TEXT ·Syscall6(SB),NOSPLIT,$0-80
+ JMP syscall·Syscall6(SB)
+
+TEXT ·Syscall9(SB),NOSPLIT,$0-104
+ JMP syscall·Syscall9(SB)
+
+TEXT ·RawSyscall(SB),NOSPLIT,$0-56
+ JMP syscall·RawSyscall(SB)
+
+TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
+ JMP syscall·RawSyscall6(SB)
diff --git a/vendor/golang.org/x/sys/unix/asm_bsd_arm.s b/vendor/golang.org/x/sys/unix/asm_bsd_arm.s
new file mode 100644
index 0000000..6496c31
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/asm_bsd_arm.s
@@ -0,0 +1,27 @@
+// Copyright 2021 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.
+
+//go:build (freebsd || netbsd || openbsd) && gc
+
+#include "textflag.h"
+
+// System call support for ARM BSD
+
+// Just jump to package syscall's implementation for all these functions.
+// The runtime may know about them.
+
+TEXT ·Syscall(SB),NOSPLIT,$0-28
+ B syscall·Syscall(SB)
+
+TEXT ·Syscall6(SB),NOSPLIT,$0-40
+ B syscall·Syscall6(SB)
+
+TEXT ·Syscall9(SB),NOSPLIT,$0-52
+ B syscall·Syscall9(SB)
+
+TEXT ·RawSyscall(SB),NOSPLIT,$0-28
+ B syscall·RawSyscall(SB)
+
+TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
+ B syscall·RawSyscall6(SB)
diff --git a/vendor/golang.org/x/sys/unix/asm_bsd_arm64.s b/vendor/golang.org/x/sys/unix/asm_bsd_arm64.s
new file mode 100644
index 0000000..4fd1f54
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/asm_bsd_arm64.s
@@ -0,0 +1,27 @@
+// Copyright 2021 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.
+
+//go:build (darwin || freebsd || netbsd || openbsd) && gc
+
+#include "textflag.h"
+
+// System call support for ARM64 BSD
+
+// Just jump to package syscall's implementation for all these functions.
+// The runtime may know about them.
+
+TEXT ·Syscall(SB),NOSPLIT,$0-56
+ JMP syscall·Syscall(SB)
+
+TEXT ·Syscall6(SB),NOSPLIT,$0-80
+ JMP syscall·Syscall6(SB)
+
+TEXT ·Syscall9(SB),NOSPLIT,$0-104
+ JMP syscall·Syscall9(SB)
+
+TEXT ·RawSyscall(SB),NOSPLIT,$0-56
+ JMP syscall·RawSyscall(SB)
+
+TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
+ JMP syscall·RawSyscall6(SB)
diff --git a/vendor/golang.org/x/sys/unix/asm_bsd_ppc64.s b/vendor/golang.org/x/sys/unix/asm_bsd_ppc64.s
new file mode 100644
index 0000000..42f7eb9
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/asm_bsd_ppc64.s
@@ -0,0 +1,29 @@
+// Copyright 2022 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.
+
+//go:build (darwin || freebsd || netbsd || openbsd) && gc
+
+#include "textflag.h"
+
+//
+// System call support for ppc64, BSD
+//
+
+// Just jump to package syscall's implementation for all these functions.
+// The runtime may know about them.
+
+TEXT ·Syscall(SB),NOSPLIT,$0-56
+ JMP syscall·Syscall(SB)
+
+TEXT ·Syscall6(SB),NOSPLIT,$0-80
+ JMP syscall·Syscall6(SB)
+
+TEXT ·Syscall9(SB),NOSPLIT,$0-104
+ JMP syscall·Syscall9(SB)
+
+TEXT ·RawSyscall(SB),NOSPLIT,$0-56
+ JMP syscall·RawSyscall(SB)
+
+TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
+ JMP syscall·RawSyscall6(SB)
diff --git a/vendor/golang.org/x/sys/unix/asm_bsd_riscv64.s b/vendor/golang.org/x/sys/unix/asm_bsd_riscv64.s
new file mode 100644
index 0000000..f890266
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/asm_bsd_riscv64.s
@@ -0,0 +1,27 @@
+// Copyright 2021 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.
+
+//go:build (darwin || freebsd || netbsd || openbsd) && gc
+
+#include "textflag.h"
+
+// System call support for RISCV64 BSD
+
+// Just jump to package syscall's implementation for all these functions.
+// The runtime may know about them.
+
+TEXT ·Syscall(SB),NOSPLIT,$0-56
+ JMP syscall·Syscall(SB)
+
+TEXT ·Syscall6(SB),NOSPLIT,$0-80
+ JMP syscall·Syscall6(SB)
+
+TEXT ·Syscall9(SB),NOSPLIT,$0-104
+ JMP syscall·Syscall9(SB)
+
+TEXT ·RawSyscall(SB),NOSPLIT,$0-56
+ JMP syscall·RawSyscall(SB)
+
+TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
+ JMP syscall·RawSyscall6(SB)
diff --git a/vendor/golang.org/x/sys/unix/asm_linux_386.s b/vendor/golang.org/x/sys/unix/asm_linux_386.s
new file mode 100644
index 0000000..3b47348
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/asm_linux_386.s
@@ -0,0 +1,65 @@
+// Copyright 2009 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.
+
+//go:build gc
+
+#include "textflag.h"
+
+//
+// System calls for 386, Linux
+//
+
+// See ../runtime/sys_linux_386.s for the reason why we always use int 0x80
+// instead of the glibc-specific "CALL 0x10(GS)".
+#define INVOKE_SYSCALL INT $0x80
+
+// Just jump to package syscall's implementation for all these functions.
+// The runtime may know about them.
+
+TEXT ·Syscall(SB),NOSPLIT,$0-28
+ JMP syscall·Syscall(SB)
+
+TEXT ·Syscall6(SB),NOSPLIT,$0-40
+ JMP syscall·Syscall6(SB)
+
+TEXT ·SyscallNoError(SB),NOSPLIT,$0-24
+ CALL runtime·entersyscall(SB)
+ MOVL trap+0(FP), AX // syscall entry
+ MOVL a1+4(FP), BX
+ MOVL a2+8(FP), CX
+ MOVL a3+12(FP), DX
+ MOVL $0, SI
+ MOVL $0, DI
+ INVOKE_SYSCALL
+ MOVL AX, r1+16(FP)
+ MOVL DX, r2+20(FP)
+ CALL runtime·exitsyscall(SB)
+ RET
+
+TEXT ·RawSyscall(SB),NOSPLIT,$0-28
+ JMP syscall·RawSyscall(SB)
+
+TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
+ JMP syscall·RawSyscall6(SB)
+
+TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-24
+ MOVL trap+0(FP), AX // syscall entry
+ MOVL a1+4(FP), BX
+ MOVL a2+8(FP), CX
+ MOVL a3+12(FP), DX
+ MOVL $0, SI
+ MOVL $0, DI
+ INVOKE_SYSCALL
+ MOVL AX, r1+16(FP)
+ MOVL DX, r2+20(FP)
+ RET
+
+TEXT ·socketcall(SB),NOSPLIT,$0-36
+ JMP syscall·socketcall(SB)
+
+TEXT ·rawsocketcall(SB),NOSPLIT,$0-36
+ JMP syscall·rawsocketcall(SB)
+
+TEXT ·seek(SB),NOSPLIT,$0-28
+ JMP syscall·seek(SB)
diff --git a/vendor/golang.org/x/sys/unix/asm_linux_amd64.s b/vendor/golang.org/x/sys/unix/asm_linux_amd64.s
new file mode 100644
index 0000000..67e29f3
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/asm_linux_amd64.s
@@ -0,0 +1,57 @@
+// Copyright 2009 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.
+
+//go:build gc
+
+#include "textflag.h"
+
+//
+// System calls for AMD64, Linux
+//
+
+// Just jump to package syscall's implementation for all these functions.
+// The runtime may know about them.
+
+TEXT ·Syscall(SB),NOSPLIT,$0-56
+ JMP syscall·Syscall(SB)
+
+TEXT ·Syscall6(SB),NOSPLIT,$0-80
+ JMP syscall·Syscall6(SB)
+
+TEXT ·SyscallNoError(SB),NOSPLIT,$0-48
+ CALL runtime·entersyscall(SB)
+ MOVQ a1+8(FP), DI
+ MOVQ a2+16(FP), SI
+ MOVQ a3+24(FP), DX
+ MOVQ $0, R10
+ MOVQ $0, R8
+ MOVQ $0, R9
+ MOVQ trap+0(FP), AX // syscall entry
+ SYSCALL
+ MOVQ AX, r1+32(FP)
+ MOVQ DX, r2+40(FP)
+ CALL runtime·exitsyscall(SB)
+ RET
+
+TEXT ·RawSyscall(SB),NOSPLIT,$0-56
+ JMP syscall·RawSyscall(SB)
+
+TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
+ JMP syscall·RawSyscall6(SB)
+
+TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-48
+ MOVQ a1+8(FP), DI
+ MOVQ a2+16(FP), SI
+ MOVQ a3+24(FP), DX
+ MOVQ $0, R10
+ MOVQ $0, R8
+ MOVQ $0, R9
+ MOVQ trap+0(FP), AX // syscall entry
+ SYSCALL
+ MOVQ AX, r1+32(FP)
+ MOVQ DX, r2+40(FP)
+ RET
+
+TEXT ·gettimeofday(SB),NOSPLIT,$0-16
+ JMP syscall·gettimeofday(SB)
diff --git a/vendor/golang.org/x/sys/unix/asm_linux_arm.s b/vendor/golang.org/x/sys/unix/asm_linux_arm.s
new file mode 100644
index 0000000..d6ae269
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/asm_linux_arm.s
@@ -0,0 +1,56 @@
+// Copyright 2009 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.
+
+//go:build gc
+
+#include "textflag.h"
+
+//
+// System calls for arm, Linux
+//
+
+// Just jump to package syscall's implementation for all these functions.
+// The runtime may know about them.
+
+TEXT ·Syscall(SB),NOSPLIT,$0-28
+ B syscall·Syscall(SB)
+
+TEXT ·Syscall6(SB),NOSPLIT,$0-40
+ B syscall·Syscall6(SB)
+
+TEXT ·SyscallNoError(SB),NOSPLIT,$0-24
+ BL runtime·entersyscall(SB)
+ MOVW trap+0(FP), R7
+ MOVW a1+4(FP), R0
+ MOVW a2+8(FP), R1
+ MOVW a3+12(FP), R2
+ MOVW $0, R3
+ MOVW $0, R4
+ MOVW $0, R5
+ SWI $0
+ MOVW R0, r1+16(FP)
+ MOVW $0, R0
+ MOVW R0, r2+20(FP)
+ BL runtime·exitsyscall(SB)
+ RET
+
+TEXT ·RawSyscall(SB),NOSPLIT,$0-28
+ B syscall·RawSyscall(SB)
+
+TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
+ B syscall·RawSyscall6(SB)
+
+TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-24
+ MOVW trap+0(FP), R7 // syscall entry
+ MOVW a1+4(FP), R0
+ MOVW a2+8(FP), R1
+ MOVW a3+12(FP), R2
+ SWI $0
+ MOVW R0, r1+16(FP)
+ MOVW $0, R0
+ MOVW R0, r2+20(FP)
+ RET
+
+TEXT ·seek(SB),NOSPLIT,$0-28
+ B syscall·seek(SB)
diff --git a/vendor/golang.org/x/sys/unix/asm_linux_arm64.s b/vendor/golang.org/x/sys/unix/asm_linux_arm64.s
new file mode 100644
index 0000000..01e5e25
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/asm_linux_arm64.s
@@ -0,0 +1,50 @@
+// Copyright 2015 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.
+
+//go:build linux && arm64 && gc
+
+#include "textflag.h"
+
+// Just jump to package syscall's implementation for all these functions.
+// The runtime may know about them.
+
+TEXT ·Syscall(SB),NOSPLIT,$0-56
+ B syscall·Syscall(SB)
+
+TEXT ·Syscall6(SB),NOSPLIT,$0-80
+ B syscall·Syscall6(SB)
+
+TEXT ·SyscallNoError(SB),NOSPLIT,$0-48
+ BL runtime·entersyscall(SB)
+ MOVD a1+8(FP), R0
+ MOVD a2+16(FP), R1
+ MOVD a3+24(FP), R2
+ MOVD $0, R3
+ MOVD $0, R4
+ MOVD $0, R5
+ MOVD trap+0(FP), R8 // syscall entry
+ SVC
+ MOVD R0, r1+32(FP) // r1
+ MOVD R1, r2+40(FP) // r2
+ BL runtime·exitsyscall(SB)
+ RET
+
+TEXT ·RawSyscall(SB),NOSPLIT,$0-56
+ B syscall·RawSyscall(SB)
+
+TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
+ B syscall·RawSyscall6(SB)
+
+TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-48
+ MOVD a1+8(FP), R0
+ MOVD a2+16(FP), R1
+ MOVD a3+24(FP), R2
+ MOVD $0, R3
+ MOVD $0, R4
+ MOVD $0, R5
+ MOVD trap+0(FP), R8 // syscall entry
+ SVC
+ MOVD R0, r1+32(FP)
+ MOVD R1, r2+40(FP)
+ RET
diff --git a/vendor/golang.org/x/sys/unix/asm_linux_loong64.s b/vendor/golang.org/x/sys/unix/asm_linux_loong64.s
new file mode 100644
index 0000000..2abf12f
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/asm_linux_loong64.s
@@ -0,0 +1,51 @@
+// Copyright 2022 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.
+
+//go:build linux && loong64 && gc
+
+#include "textflag.h"
+
+
+// Just jump to package syscall's implementation for all these functions.
+// The runtime may know about them.
+
+TEXT ·Syscall(SB),NOSPLIT,$0-56
+ JMP syscall·Syscall(SB)
+
+TEXT ·Syscall6(SB),NOSPLIT,$0-80
+ JMP syscall·Syscall6(SB)
+
+TEXT ·SyscallNoError(SB),NOSPLIT,$0-48
+ JAL runtime·entersyscall(SB)
+ MOVV a1+8(FP), R4
+ MOVV a2+16(FP), R5
+ MOVV a3+24(FP), R6
+ MOVV R0, R7
+ MOVV R0, R8
+ MOVV R0, R9
+ MOVV trap+0(FP), R11 // syscall entry
+ SYSCALL
+ MOVV R4, r1+32(FP)
+ MOVV R0, r2+40(FP) // r2 is not used. Always set to 0
+ JAL runtime·exitsyscall(SB)
+ RET
+
+TEXT ·RawSyscall(SB),NOSPLIT,$0-56
+ JMP syscall·RawSyscall(SB)
+
+TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
+ JMP syscall·RawSyscall6(SB)
+
+TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-48
+ MOVV a1+8(FP), R4
+ MOVV a2+16(FP), R5
+ MOVV a3+24(FP), R6
+ MOVV R0, R7
+ MOVV R0, R8
+ MOVV R0, R9
+ MOVV trap+0(FP), R11 // syscall entry
+ SYSCALL
+ MOVV R4, r1+32(FP)
+ MOVV R0, r2+40(FP) // r2 is not used. Always set to 0
+ RET
diff --git a/vendor/golang.org/x/sys/unix/asm_linux_mips64x.s b/vendor/golang.org/x/sys/unix/asm_linux_mips64x.s
new file mode 100644
index 0000000..f84bae7
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/asm_linux_mips64x.s
@@ -0,0 +1,54 @@
+// Copyright 2015 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.
+
+//go:build linux && (mips64 || mips64le) && gc
+
+#include "textflag.h"
+
+//
+// System calls for mips64, Linux
+//
+
+// Just jump to package syscall's implementation for all these functions.
+// The runtime may know about them.
+
+TEXT ·Syscall(SB),NOSPLIT,$0-56
+ JMP syscall·Syscall(SB)
+
+TEXT ·Syscall6(SB),NOSPLIT,$0-80
+ JMP syscall·Syscall6(SB)
+
+TEXT ·SyscallNoError(SB),NOSPLIT,$0-48
+ JAL runtime·entersyscall(SB)
+ MOVV a1+8(FP), R4
+ MOVV a2+16(FP), R5
+ MOVV a3+24(FP), R6
+ MOVV R0, R7
+ MOVV R0, R8
+ MOVV R0, R9
+ MOVV trap+0(FP), R2 // syscall entry
+ SYSCALL
+ MOVV R2, r1+32(FP)
+ MOVV R3, r2+40(FP)
+ JAL runtime·exitsyscall(SB)
+ RET
+
+TEXT ·RawSyscall(SB),NOSPLIT,$0-56
+ JMP syscall·RawSyscall(SB)
+
+TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
+ JMP syscall·RawSyscall6(SB)
+
+TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-48
+ MOVV a1+8(FP), R4
+ MOVV a2+16(FP), R5
+ MOVV a3+24(FP), R6
+ MOVV R0, R7
+ MOVV R0, R8
+ MOVV R0, R9
+ MOVV trap+0(FP), R2 // syscall entry
+ SYSCALL
+ MOVV R2, r1+32(FP)
+ MOVV R3, r2+40(FP)
+ RET
diff --git a/vendor/golang.org/x/sys/unix/asm_linux_mipsx.s b/vendor/golang.org/x/sys/unix/asm_linux_mipsx.s
new file mode 100644
index 0000000..f08f628
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/asm_linux_mipsx.s
@@ -0,0 +1,52 @@
+// Copyright 2016 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.
+
+//go:build linux && (mips || mipsle) && gc
+
+#include "textflag.h"
+
+//
+// System calls for mips, Linux
+//
+
+// Just jump to package syscall's implementation for all these functions.
+// The runtime may know about them.
+
+TEXT ·Syscall(SB),NOSPLIT,$0-28
+ JMP syscall·Syscall(SB)
+
+TEXT ·Syscall6(SB),NOSPLIT,$0-40
+ JMP syscall·Syscall6(SB)
+
+TEXT ·Syscall9(SB),NOSPLIT,$0-52
+ JMP syscall·Syscall9(SB)
+
+TEXT ·SyscallNoError(SB),NOSPLIT,$0-24
+ JAL runtime·entersyscall(SB)
+ MOVW a1+4(FP), R4
+ MOVW a2+8(FP), R5
+ MOVW a3+12(FP), R6
+ MOVW R0, R7
+ MOVW trap+0(FP), R2 // syscall entry
+ SYSCALL
+ MOVW R2, r1+16(FP) // r1
+ MOVW R3, r2+20(FP) // r2
+ JAL runtime·exitsyscall(SB)
+ RET
+
+TEXT ·RawSyscall(SB),NOSPLIT,$0-28
+ JMP syscall·RawSyscall(SB)
+
+TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
+ JMP syscall·RawSyscall6(SB)
+
+TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-24
+ MOVW a1+4(FP), R4
+ MOVW a2+8(FP), R5
+ MOVW a3+12(FP), R6
+ MOVW trap+0(FP), R2 // syscall entry
+ SYSCALL
+ MOVW R2, r1+16(FP)
+ MOVW R3, r2+20(FP)
+ RET
diff --git a/vendor/golang.org/x/sys/unix/asm_linux_ppc64x.s b/vendor/golang.org/x/sys/unix/asm_linux_ppc64x.s
new file mode 100644
index 0000000..bdfc024
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/asm_linux_ppc64x.s
@@ -0,0 +1,42 @@
+// Copyright 2014 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.
+
+//go:build linux && (ppc64 || ppc64le) && gc
+
+#include "textflag.h"
+
+//
+// System calls for ppc64, Linux
+//
+
+// Just jump to package syscall's implementation for all these functions.
+// The runtime may know about them.
+
+TEXT ·SyscallNoError(SB),NOSPLIT,$0-48
+ BL runtime·entersyscall(SB)
+ MOVD a1+8(FP), R3
+ MOVD a2+16(FP), R4
+ MOVD a3+24(FP), R5
+ MOVD R0, R6
+ MOVD R0, R7
+ MOVD R0, R8
+ MOVD trap+0(FP), R9 // syscall entry
+ SYSCALL R9
+ MOVD R3, r1+32(FP)
+ MOVD R4, r2+40(FP)
+ BL runtime·exitsyscall(SB)
+ RET
+
+TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-48
+ MOVD a1+8(FP), R3
+ MOVD a2+16(FP), R4
+ MOVD a3+24(FP), R5
+ MOVD R0, R6
+ MOVD R0, R7
+ MOVD R0, R8
+ MOVD trap+0(FP), R9 // syscall entry
+ SYSCALL R9
+ MOVD R3, r1+32(FP)
+ MOVD R4, r2+40(FP)
+ RET
diff --git a/vendor/golang.org/x/sys/unix/asm_linux_riscv64.s b/vendor/golang.org/x/sys/unix/asm_linux_riscv64.s
new file mode 100644
index 0000000..2e8c996
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/asm_linux_riscv64.s
@@ -0,0 +1,47 @@
+// Copyright 2019 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.
+
+//go:build riscv64 && gc
+
+#include "textflag.h"
+
+//
+// System calls for linux/riscv64.
+//
+// Where available, just jump to package syscall's implementation of
+// these functions.
+
+TEXT ·Syscall(SB),NOSPLIT,$0-56
+ JMP syscall·Syscall(SB)
+
+TEXT ·Syscall6(SB),NOSPLIT,$0-80
+ JMP syscall·Syscall6(SB)
+
+TEXT ·SyscallNoError(SB),NOSPLIT,$0-48
+ CALL runtime·entersyscall(SB)
+ MOV a1+8(FP), A0
+ MOV a2+16(FP), A1
+ MOV a3+24(FP), A2
+ MOV trap+0(FP), A7 // syscall entry
+ ECALL
+ MOV A0, r1+32(FP) // r1
+ MOV A1, r2+40(FP) // r2
+ CALL runtime·exitsyscall(SB)
+ RET
+
+TEXT ·RawSyscall(SB),NOSPLIT,$0-56
+ JMP syscall·RawSyscall(SB)
+
+TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
+ JMP syscall·RawSyscall6(SB)
+
+TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-48
+ MOV a1+8(FP), A0
+ MOV a2+16(FP), A1
+ MOV a3+24(FP), A2
+ MOV trap+0(FP), A7 // syscall entry
+ ECALL
+ MOV A0, r1+32(FP)
+ MOV A1, r2+40(FP)
+ RET
diff --git a/vendor/golang.org/x/sys/unix/asm_linux_s390x.s b/vendor/golang.org/x/sys/unix/asm_linux_s390x.s
new file mode 100644
index 0000000..2c394b1
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/asm_linux_s390x.s
@@ -0,0 +1,54 @@
+// Copyright 2016 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.
+
+//go:build linux && s390x && gc
+
+#include "textflag.h"
+
+//
+// System calls for s390x, Linux
+//
+
+// Just jump to package syscall's implementation for all these functions.
+// The runtime may know about them.
+
+TEXT ·Syscall(SB),NOSPLIT,$0-56
+ BR syscall·Syscall(SB)
+
+TEXT ·Syscall6(SB),NOSPLIT,$0-80
+ BR syscall·Syscall6(SB)
+
+TEXT ·SyscallNoError(SB),NOSPLIT,$0-48
+ BL runtime·entersyscall(SB)
+ MOVD a1+8(FP), R2
+ MOVD a2+16(FP), R3
+ MOVD a3+24(FP), R4
+ MOVD $0, R5
+ MOVD $0, R6
+ MOVD $0, R7
+ MOVD trap+0(FP), R1 // syscall entry
+ SYSCALL
+ MOVD R2, r1+32(FP)
+ MOVD R3, r2+40(FP)
+ BL runtime·exitsyscall(SB)
+ RET
+
+TEXT ·RawSyscall(SB),NOSPLIT,$0-56
+ BR syscall·RawSyscall(SB)
+
+TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
+ BR syscall·RawSyscall6(SB)
+
+TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-48
+ MOVD a1+8(FP), R2
+ MOVD a2+16(FP), R3
+ MOVD a3+24(FP), R4
+ MOVD $0, R5
+ MOVD $0, R6
+ MOVD $0, R7
+ MOVD trap+0(FP), R1 // syscall entry
+ SYSCALL
+ MOVD R2, r1+32(FP)
+ MOVD R3, r2+40(FP)
+ RET
diff --git a/vendor/golang.org/x/sys/unix/asm_openbsd_mips64.s b/vendor/golang.org/x/sys/unix/asm_openbsd_mips64.s
new file mode 100644
index 0000000..fab586a
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/asm_openbsd_mips64.s
@@ -0,0 +1,29 @@
+// Copyright 2019 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.
+
+//go:build gc
+
+#include "textflag.h"
+
+//
+// System call support for mips64, OpenBSD
+//
+
+// Just jump to package syscall's implementation for all these functions.
+// The runtime may know about them.
+
+TEXT ·Syscall(SB),NOSPLIT,$0-56
+ JMP syscall·Syscall(SB)
+
+TEXT ·Syscall6(SB),NOSPLIT,$0-80
+ JMP syscall·Syscall6(SB)
+
+TEXT ·Syscall9(SB),NOSPLIT,$0-104
+ JMP syscall·Syscall9(SB)
+
+TEXT ·RawSyscall(SB),NOSPLIT,$0-56
+ JMP syscall·RawSyscall(SB)
+
+TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
+ JMP syscall·RawSyscall6(SB)
diff --git a/vendor/golang.org/x/sys/unix/asm_solaris_amd64.s b/vendor/golang.org/x/sys/unix/asm_solaris_amd64.s
new file mode 100644
index 0000000..f949ec5
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/asm_solaris_amd64.s
@@ -0,0 +1,17 @@
+// Copyright 2014 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.
+
+//go:build gc
+
+#include "textflag.h"
+
+//
+// System calls for amd64, Solaris are implemented in runtime/syscall_solaris.go
+//
+
+TEXT ·sysvicall6(SB),NOSPLIT,$0-88
+ JMP syscall·sysvicall6(SB)
+
+TEXT ·rawSysvicall6(SB),NOSPLIT,$0-88
+ JMP syscall·rawSysvicall6(SB)
diff --git a/vendor/golang.org/x/sys/unix/asm_zos_s390x.s b/vendor/golang.org/x/sys/unix/asm_zos_s390x.s
new file mode 100644
index 0000000..813dfad
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/asm_zos_s390x.s
@@ -0,0 +1,382 @@
+// Copyright 2020 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.
+
+//go:build zos && s390x && gc
+
+#include "textflag.h"
+
+#define PSALAA 1208(R0)
+#define GTAB64(x) 80(x)
+#define LCA64(x) 88(x)
+#define SAVSTACK_ASYNC(x) 336(x) // in the LCA
+#define CAA(x) 8(x)
+#define CEECAATHDID(x) 976(x) // in the CAA
+#define EDCHPXV(x) 1016(x) // in the CAA
+#define GOCB(x) 1104(x) // in the CAA
+
+// SS_*, where x=SAVSTACK_ASYNC
+#define SS_LE(x) 0(x)
+#define SS_GO(x) 8(x)
+#define SS_ERRNO(x) 16(x)
+#define SS_ERRNOJR(x) 20(x)
+
+// Function Descriptor Offsets
+#define __errno 0x156*16
+#define __err2ad 0x16C*16
+
+// Call Instructions
+#define LE_CALL BYTE $0x0D; BYTE $0x76 // BL R7, R6
+#define SVC_LOAD BYTE $0x0A; BYTE $0x08 // SVC 08 LOAD
+#define SVC_DELETE BYTE $0x0A; BYTE $0x09 // SVC 09 DELETE
+
+DATA zosLibVec<>(SB)/8, $0
+GLOBL zosLibVec<>(SB), NOPTR, $8
+
+TEXT ·initZosLibVec(SB), NOSPLIT|NOFRAME, $0-0
+ MOVW PSALAA, R8
+ MOVD LCA64(R8), R8
+ MOVD CAA(R8), R8
+ MOVD EDCHPXV(R8), R8
+ MOVD R8, zosLibVec<>(SB)
+ RET
+
+TEXT ·GetZosLibVec(SB), NOSPLIT|NOFRAME, $0-0
+ MOVD zosLibVec<>(SB), R8
+ MOVD R8, ret+0(FP)
+ RET
+
+TEXT ·clearErrno(SB), NOSPLIT, $0-0
+ BL addrerrno<>(SB)
+ MOVD $0, 0(R3)
+ RET
+
+// Returns the address of errno in R3.
+TEXT addrerrno<>(SB), NOSPLIT|NOFRAME, $0-0
+ // Get library control area (LCA).
+ MOVW PSALAA, R8
+ MOVD LCA64(R8), R8
+
+ // Get __errno FuncDesc.
+ MOVD CAA(R8), R9
+ MOVD EDCHPXV(R9), R9
+ ADD $(__errno), R9
+ LMG 0(R9), R5, R6
+
+ // Switch to saved LE stack.
+ MOVD SAVSTACK_ASYNC(R8), R9
+ MOVD 0(R9), R4
+ MOVD $0, 0(R9)
+
+ // Call __errno function.
+ LE_CALL
+ NOPH
+
+ // Switch back to Go stack.
+ XOR R0, R0 // Restore R0 to $0.
+ MOVD R4, 0(R9) // Save stack pointer.
+ RET
+
+// func svcCall(fnptr unsafe.Pointer, argv *unsafe.Pointer, dsa *uint64)
+TEXT ·svcCall(SB), NOSPLIT, $0
+ BL runtime·save_g(SB) // Save g and stack pointer
+ MOVW PSALAA, R8
+ MOVD LCA64(R8), R8
+ MOVD SAVSTACK_ASYNC(R8), R9
+ MOVD R15, 0(R9)
+
+ MOVD argv+8(FP), R1 // Move function arguments into registers
+ MOVD dsa+16(FP), g
+ MOVD fnptr+0(FP), R15
+
+ BYTE $0x0D // Branch to function
+ BYTE $0xEF
+
+ BL runtime·load_g(SB) // Restore g and stack pointer
+ MOVW PSALAA, R8
+ MOVD LCA64(R8), R8
+ MOVD SAVSTACK_ASYNC(R8), R9
+ MOVD 0(R9), R15
+
+ RET
+
+// func svcLoad(name *byte) unsafe.Pointer
+TEXT ·svcLoad(SB), NOSPLIT, $0
+ MOVD R15, R2 // Save go stack pointer
+ MOVD name+0(FP), R0 // Move SVC args into registers
+ MOVD $0x80000000, R1
+ MOVD $0, R15
+ SVC_LOAD
+ MOVW R15, R3 // Save return code from SVC
+ MOVD R2, R15 // Restore go stack pointer
+ CMP R3, $0 // Check SVC return code
+ BNE error
+
+ MOVD $-2, R3 // Reset last bit of entry point to zero
+ AND R0, R3
+ MOVD R3, ret+8(FP) // Return entry point returned by SVC
+ CMP R0, R3 // Check if last bit of entry point was set
+ BNE done
+
+ MOVD R15, R2 // Save go stack pointer
+ MOVD $0, R15 // Move SVC args into registers (entry point still in r0 from SVC 08)
+ SVC_DELETE
+ MOVD R2, R15 // Restore go stack pointer
+
+error:
+ MOVD $0, ret+8(FP) // Return 0 on failure
+
+done:
+ XOR R0, R0 // Reset r0 to 0
+ RET
+
+// func svcUnload(name *byte, fnptr unsafe.Pointer) int64
+TEXT ·svcUnload(SB), NOSPLIT, $0
+ MOVD R15, R2 // Save go stack pointer
+ MOVD name+0(FP), R0 // Move SVC args into registers
+ MOVD fnptr+8(FP), R15
+ SVC_DELETE
+ XOR R0, R0 // Reset r0 to 0
+ MOVD R15, R1 // Save SVC return code
+ MOVD R2, R15 // Restore go stack pointer
+ MOVD R1, ret+16(FP) // Return SVC return code
+ RET
+
+// func gettid() uint64
+TEXT ·gettid(SB), NOSPLIT, $0
+ // Get library control area (LCA).
+ MOVW PSALAA, R8
+ MOVD LCA64(R8), R8
+
+ // Get CEECAATHDID
+ MOVD CAA(R8), R9
+ MOVD CEECAATHDID(R9), R9
+ MOVD R9, ret+0(FP)
+
+ RET
+
+//
+// Call LE function, if the return is -1
+// errno and errno2 is retrieved
+//
+TEXT ·CallLeFuncWithErr(SB), NOSPLIT, $0
+ MOVW PSALAA, R8
+ MOVD LCA64(R8), R8
+ MOVD CAA(R8), R9
+ MOVD g, GOCB(R9)
+
+ // Restore LE stack.
+ MOVD SAVSTACK_ASYNC(R8), R9 // R9-> LE stack frame saving address
+ MOVD 0(R9), R4 // R4-> restore previously saved stack frame pointer
+
+ MOVD parms_base+8(FP), R7 // R7 -> argument array
+ MOVD parms_len+16(FP), R8 // R8 number of arguments
+
+ // arg 1 ---> R1
+ CMP R8, $0
+ BEQ docall
+ SUB $1, R8
+ MOVD 0(R7), R1
+
+ // arg 2 ---> R2
+ CMP R8, $0
+ BEQ docall
+ SUB $1, R8
+ ADD $8, R7
+ MOVD 0(R7), R2
+
+ // arg 3 --> R3
+ CMP R8, $0
+ BEQ docall
+ SUB $1, R8
+ ADD $8, R7
+ MOVD 0(R7), R3
+
+ CMP R8, $0
+ BEQ docall
+ MOVD $2176+16, R6 // starting LE stack address-8 to store 4th argument
+
+repeat:
+ ADD $8, R7
+ MOVD 0(R7), R0 // advance arg pointer by 8 byte
+ ADD $8, R6 // advance LE argument address by 8 byte
+ MOVD R0, (R4)(R6*1) // copy argument from go-slice to le-frame
+ SUB $1, R8
+ CMP R8, $0
+ BNE repeat
+
+docall:
+ MOVD funcdesc+0(FP), R8 // R8-> function descriptor
+ LMG 0(R8), R5, R6
+ MOVD $0, 0(R9) // R9 address of SAVSTACK_ASYNC
+ LE_CALL // balr R7, R6 (return #1)
+ NOPH
+ MOVD R3, ret+32(FP)
+ CMP R3, $-1 // compare result to -1
+ BNE done
+
+ // retrieve errno and errno2
+ MOVD zosLibVec<>(SB), R8
+ ADD $(__errno), R8
+ LMG 0(R8), R5, R6
+ LE_CALL // balr R7, R6 __errno (return #3)
+ NOPH
+ MOVWZ 0(R3), R3
+ MOVD R3, err+48(FP)
+ MOVD zosLibVec<>(SB), R8
+ ADD $(__err2ad), R8
+ LMG 0(R8), R5, R6
+ LE_CALL // balr R7, R6 __err2ad (return #2)
+ NOPH
+ MOVW (R3), R2 // retrieve errno2
+ MOVD R2, errno2+40(FP) // store in return area
+
+done:
+ MOVD R4, 0(R9) // Save stack pointer.
+ RET
+
+//
+// Call LE function, if the return is 0
+// errno and errno2 is retrieved
+//
+TEXT ·CallLeFuncWithPtrReturn(SB), NOSPLIT, $0
+ MOVW PSALAA, R8
+ MOVD LCA64(R8), R8
+ MOVD CAA(R8), R9
+ MOVD g, GOCB(R9)
+
+ // Restore LE stack.
+ MOVD SAVSTACK_ASYNC(R8), R9 // R9-> LE stack frame saving address
+ MOVD 0(R9), R4 // R4-> restore previously saved stack frame pointer
+
+ MOVD parms_base+8(FP), R7 // R7 -> argument array
+ MOVD parms_len+16(FP), R8 // R8 number of arguments
+
+ // arg 1 ---> R1
+ CMP R8, $0
+ BEQ docall
+ SUB $1, R8
+ MOVD 0(R7), R1
+
+ // arg 2 ---> R2
+ CMP R8, $0
+ BEQ docall
+ SUB $1, R8
+ ADD $8, R7
+ MOVD 0(R7), R2
+
+ // arg 3 --> R3
+ CMP R8, $0
+ BEQ docall
+ SUB $1, R8
+ ADD $8, R7
+ MOVD 0(R7), R3
+
+ CMP R8, $0
+ BEQ docall
+ MOVD $2176+16, R6 // starting LE stack address-8 to store 4th argument
+
+repeat:
+ ADD $8, R7
+ MOVD 0(R7), R0 // advance arg pointer by 8 byte
+ ADD $8, R6 // advance LE argument address by 8 byte
+ MOVD R0, (R4)(R6*1) // copy argument from go-slice to le-frame
+ SUB $1, R8
+ CMP R8, $0
+ BNE repeat
+
+docall:
+ MOVD funcdesc+0(FP), R8 // R8-> function descriptor
+ LMG 0(R8), R5, R6
+ MOVD $0, 0(R9) // R9 address of SAVSTACK_ASYNC
+ LE_CALL // balr R7, R6 (return #1)
+ NOPH
+ MOVD R3, ret+32(FP)
+ CMP R3, $0 // compare result to 0
+ BNE done
+
+ // retrieve errno and errno2
+ MOVD zosLibVec<>(SB), R8
+ ADD $(__errno), R8
+ LMG 0(R8), R5, R6
+ LE_CALL // balr R7, R6 __errno (return #3)
+ NOPH
+ MOVWZ 0(R3), R3
+ MOVD R3, err+48(FP)
+ MOVD zosLibVec<>(SB), R8
+ ADD $(__err2ad), R8
+ LMG 0(R8), R5, R6
+ LE_CALL // balr R7, R6 __err2ad (return #2)
+ NOPH
+ MOVW (R3), R2 // retrieve errno2
+ MOVD R2, errno2+40(FP) // store in return area
+ XOR R2, R2
+ MOVWZ R2, (R3) // clear errno2
+
+done:
+ MOVD R4, 0(R9) // Save stack pointer.
+ RET
+
+//
+// function to test if a pointer can be safely dereferenced (content read)
+// return 0 for succces
+//
+TEXT ·ptrtest(SB), NOSPLIT, $0-16
+ MOVD arg+0(FP), R10 // test pointer in R10
+
+ // set up R2 to point to CEECAADMC
+ BYTE $0xE3; BYTE $0x20; BYTE $0x04; BYTE $0xB8; BYTE $0x00; BYTE $0x17 // llgt 2,1208
+ BYTE $0xB9; BYTE $0x17; BYTE $0x00; BYTE $0x22 // llgtr 2,2
+ BYTE $0xA5; BYTE $0x26; BYTE $0x7F; BYTE $0xFF // nilh 2,32767
+ BYTE $0xE3; BYTE $0x22; BYTE $0x00; BYTE $0x58; BYTE $0x00; BYTE $0x04 // lg 2,88(2)
+ BYTE $0xE3; BYTE $0x22; BYTE $0x00; BYTE $0x08; BYTE $0x00; BYTE $0x04 // lg 2,8(2)
+ BYTE $0x41; BYTE $0x22; BYTE $0x03; BYTE $0x68 // la 2,872(2)
+
+ // set up R5 to point to the "shunt" path which set 1 to R3 (failure)
+ BYTE $0xB9; BYTE $0x82; BYTE $0x00; BYTE $0x33 // xgr 3,3
+ BYTE $0xA7; BYTE $0x55; BYTE $0x00; BYTE $0x04 // bras 5,lbl1
+ BYTE $0xA7; BYTE $0x39; BYTE $0x00; BYTE $0x01 // lghi 3,1
+
+ // if r3 is not zero (failed) then branch to finish
+ BYTE $0xB9; BYTE $0x02; BYTE $0x00; BYTE $0x33 // lbl1 ltgr 3,3
+ BYTE $0xA7; BYTE $0x74; BYTE $0x00; BYTE $0x08 // brc b'0111',lbl2
+
+ // stomic store shunt address in R5 into CEECAADMC
+ BYTE $0xE3; BYTE $0x52; BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x24 // stg 5,0(2)
+
+ // now try reading from the test pointer in R10, if it fails it branches to the "lghi" instruction above
+ BYTE $0xE3; BYTE $0x9A; BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x04 // lg 9,0(10)
+
+ // finish here, restore 0 into CEECAADMC
+ BYTE $0xB9; BYTE $0x82; BYTE $0x00; BYTE $0x99 // lbl2 xgr 9,9
+ BYTE $0xE3; BYTE $0x92; BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x24 // stg 9,0(2)
+ MOVD R3, ret+8(FP) // result in R3
+ RET
+
+//
+// function to test if a untptr can be loaded from a pointer
+// return 1: the 8-byte content
+// 2: 0 for success, 1 for failure
+//
+// func safeload(ptr uintptr) ( value uintptr, error uintptr)
+TEXT ·safeload(SB), NOSPLIT, $0-24
+ MOVD ptr+0(FP), R10 // test pointer in R10
+ MOVD $0x0, R6
+ BYTE $0xE3; BYTE $0x20; BYTE $0x04; BYTE $0xB8; BYTE $0x00; BYTE $0x17 // llgt 2,1208
+ BYTE $0xB9; BYTE $0x17; BYTE $0x00; BYTE $0x22 // llgtr 2,2
+ BYTE $0xA5; BYTE $0x26; BYTE $0x7F; BYTE $0xFF // nilh 2,32767
+ BYTE $0xE3; BYTE $0x22; BYTE $0x00; BYTE $0x58; BYTE $0x00; BYTE $0x04 // lg 2,88(2)
+ BYTE $0xE3; BYTE $0x22; BYTE $0x00; BYTE $0x08; BYTE $0x00; BYTE $0x04 // lg 2,8(2)
+ BYTE $0x41; BYTE $0x22; BYTE $0x03; BYTE $0x68 // la 2,872(2)
+ BYTE $0xB9; BYTE $0x82; BYTE $0x00; BYTE $0x33 // xgr 3,3
+ BYTE $0xA7; BYTE $0x55; BYTE $0x00; BYTE $0x04 // bras 5,lbl1
+ BYTE $0xA7; BYTE $0x39; BYTE $0x00; BYTE $0x01 // lghi 3,1
+ BYTE $0xB9; BYTE $0x02; BYTE $0x00; BYTE $0x33 // lbl1 ltgr 3,3
+ BYTE $0xA7; BYTE $0x74; BYTE $0x00; BYTE $0x08 // brc b'0111',lbl2
+ BYTE $0xE3; BYTE $0x52; BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x24 // stg 5,0(2)
+ BYTE $0xE3; BYTE $0x6A; BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x04 // lg 6,0(10)
+ BYTE $0xB9; BYTE $0x82; BYTE $0x00; BYTE $0x99 // lbl2 xgr 9,9
+ BYTE $0xE3; BYTE $0x92; BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x24 // stg 9,0(2)
+ MOVD R6, value+8(FP) // result in R6
+ MOVD R3, error+16(FP) // error in R3
+ RET
diff --git a/vendor/golang.org/x/sys/unix/bluetooth_linux.go b/vendor/golang.org/x/sys/unix/bluetooth_linux.go
new file mode 100644
index 0000000..a178a61
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/bluetooth_linux.go
@@ -0,0 +1,36 @@
+// Copyright 2016 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.
+
+// Bluetooth sockets and messages
+
+package unix
+
+// Bluetooth Protocols
+const (
+ BTPROTO_L2CAP = 0
+ BTPROTO_HCI = 1
+ BTPROTO_SCO = 2
+ BTPROTO_RFCOMM = 3
+ BTPROTO_BNEP = 4
+ BTPROTO_CMTP = 5
+ BTPROTO_HIDP = 6
+ BTPROTO_AVDTP = 7
+)
+
+const (
+ HCI_CHANNEL_RAW = 0
+ HCI_CHANNEL_USER = 1
+ HCI_CHANNEL_MONITOR = 2
+ HCI_CHANNEL_CONTROL = 3
+ HCI_CHANNEL_LOGGING = 4
+)
+
+// Socketoption Level
+const (
+ SOL_BLUETOOTH = 0x112
+ SOL_HCI = 0x0
+ SOL_L2CAP = 0x6
+ SOL_RFCOMM = 0x12
+ SOL_SCO = 0x11
+)
diff --git a/vendor/golang.org/x/sys/unix/bpxsvc_zos.go b/vendor/golang.org/x/sys/unix/bpxsvc_zos.go
new file mode 100644
index 0000000..39d647d
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/bpxsvc_zos.go
@@ -0,0 +1,657 @@
+// Copyright 2024 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.
+
+//go:build zos
+
+package unix
+
+import (
+ "bytes"
+ "fmt"
+ "unsafe"
+)
+
+//go:noescape
+func bpxcall(plist []unsafe.Pointer, bpx_offset int64)
+
+//go:noescape
+func A2e([]byte)
+
+//go:noescape
+func E2a([]byte)
+
+const (
+ BPX4STA = 192 // stat
+ BPX4FST = 104 // fstat
+ BPX4LST = 132 // lstat
+ BPX4OPN = 156 // open
+ BPX4CLO = 72 // close
+ BPX4CHR = 500 // chattr
+ BPX4FCR = 504 // fchattr
+ BPX4LCR = 1180 // lchattr
+ BPX4CTW = 492 // cond_timed_wait
+ BPX4GTH = 1056 // __getthent
+ BPX4PTQ = 412 // pthread_quiesc
+ BPX4PTR = 320 // ptrace
+)
+
+const (
+ //options
+ //byte1
+ BPX_OPNFHIGH = 0x80
+ //byte2
+ BPX_OPNFEXEC = 0x80
+ //byte3
+ BPX_O_NOLARGEFILE = 0x08
+ BPX_O_LARGEFILE = 0x04
+ BPX_O_ASYNCSIG = 0x02
+ BPX_O_SYNC = 0x01
+ //byte4
+ BPX_O_CREXCL = 0xc0
+ BPX_O_CREAT = 0x80
+ BPX_O_EXCL = 0x40
+ BPX_O_NOCTTY = 0x20
+ BPX_O_TRUNC = 0x10
+ BPX_O_APPEND = 0x08
+ BPX_O_NONBLOCK = 0x04
+ BPX_FNDELAY = 0x04
+ BPX_O_RDWR = 0x03
+ BPX_O_RDONLY = 0x02
+ BPX_O_WRONLY = 0x01
+ BPX_O_ACCMODE = 0x03
+ BPX_O_GETFL = 0x0f
+
+ //mode
+ // byte1 (file type)
+ BPX_FT_DIR = 1
+ BPX_FT_CHARSPEC = 2
+ BPX_FT_REGFILE = 3
+ BPX_FT_FIFO = 4
+ BPX_FT_SYMLINK = 5
+ BPX_FT_SOCKET = 6
+ //byte3
+ BPX_S_ISUID = 0x08
+ BPX_S_ISGID = 0x04
+ BPX_S_ISVTX = 0x02
+ BPX_S_IRWXU1 = 0x01
+ BPX_S_IRUSR = 0x01
+ //byte4
+ BPX_S_IRWXU2 = 0xc0
+ BPX_S_IWUSR = 0x80
+ BPX_S_IXUSR = 0x40
+ BPX_S_IRWXG = 0x38
+ BPX_S_IRGRP = 0x20
+ BPX_S_IWGRP = 0x10
+ BPX_S_IXGRP = 0x08
+ BPX_S_IRWXOX = 0x07
+ BPX_S_IROTH = 0x04
+ BPX_S_IWOTH = 0x02
+ BPX_S_IXOTH = 0x01
+
+ CW_INTRPT = 1
+ CW_CONDVAR = 32
+ CW_TIMEOUT = 64
+
+ PGTHA_NEXT = 2
+ PGTHA_CURRENT = 1
+ PGTHA_FIRST = 0
+ PGTHA_LAST = 3
+ PGTHA_PROCESS = 0x80
+ PGTHA_CONTTY = 0x40
+ PGTHA_PATH = 0x20
+ PGTHA_COMMAND = 0x10
+ PGTHA_FILEDATA = 0x08
+ PGTHA_THREAD = 0x04
+ PGTHA_PTAG = 0x02
+ PGTHA_COMMANDLONG = 0x01
+ PGTHA_THREADFAST = 0x80
+ PGTHA_FILEPATH = 0x40
+ PGTHA_THDSIGMASK = 0x20
+ // thread quiece mode
+ QUIESCE_TERM int32 = 1
+ QUIESCE_FORCE int32 = 2
+ QUIESCE_QUERY int32 = 3
+ QUIESCE_FREEZE int32 = 4
+ QUIESCE_UNFREEZE int32 = 5
+ FREEZE_THIS_THREAD int32 = 6
+ FREEZE_EXIT int32 = 8
+ QUIESCE_SRB int32 = 9
+)
+
+type Pgtha struct {
+ Pid uint32 // 0
+ Tid0 uint32 // 4
+ Tid1 uint32
+ Accesspid byte // C
+ Accesstid byte // D
+ Accessasid uint16 // E
+ Loginname [8]byte // 10
+ Flag1 byte // 18
+ Flag1b2 byte // 19
+}
+
+type Bpxystat_t struct { // DSECT BPXYSTAT
+ St_id [4]uint8 // 0
+ St_length uint16 // 0x4
+ St_version uint16 // 0x6
+ St_mode uint32 // 0x8
+ St_ino uint32 // 0xc
+ St_dev uint32 // 0x10
+ St_nlink uint32 // 0x14
+ St_uid uint32 // 0x18
+ St_gid uint32 // 0x1c
+ St_size uint64 // 0x20
+ St_atime uint32 // 0x28
+ St_mtime uint32 // 0x2c
+ St_ctime uint32 // 0x30
+ St_rdev uint32 // 0x34
+ St_auditoraudit uint32 // 0x38
+ St_useraudit uint32 // 0x3c
+ St_blksize uint32 // 0x40
+ St_createtime uint32 // 0x44
+ St_auditid [4]uint32 // 0x48
+ St_res01 uint32 // 0x58
+ Ft_ccsid uint16 // 0x5c
+ Ft_flags uint16 // 0x5e
+ St_res01a [2]uint32 // 0x60
+ St_res02 uint32 // 0x68
+ St_blocks uint32 // 0x6c
+ St_opaque [3]uint8 // 0x70
+ St_visible uint8 // 0x73
+ St_reftime uint32 // 0x74
+ St_fid uint64 // 0x78
+ St_filefmt uint8 // 0x80
+ St_fspflag2 uint8 // 0x81
+ St_res03 [2]uint8 // 0x82
+ St_ctimemsec uint32 // 0x84
+ St_seclabel [8]uint8 // 0x88
+ St_res04 [4]uint8 // 0x90
+ // end of version 1
+ _ uint32 // 0x94
+ St_atime64 uint64 // 0x98
+ St_mtime64 uint64 // 0xa0
+ St_ctime64 uint64 // 0xa8
+ St_createtime64 uint64 // 0xb0
+ St_reftime64 uint64 // 0xb8
+ _ uint64 // 0xc0
+ St_res05 [16]uint8 // 0xc8
+ // end of version 2
+}
+
+type BpxFilestatus struct {
+ Oflag1 byte
+ Oflag2 byte
+ Oflag3 byte
+ Oflag4 byte
+}
+
+type BpxMode struct {
+ Ftype byte
+ Mode1 byte
+ Mode2 byte
+ Mode3 byte
+}
+
+// Thr attribute structure for extended attributes
+type Bpxyatt_t struct { // DSECT BPXYATT
+ Att_id [4]uint8
+ Att_version uint16
+ Att_res01 [2]uint8
+ Att_setflags1 uint8
+ Att_setflags2 uint8
+ Att_setflags3 uint8
+ Att_setflags4 uint8
+ Att_mode uint32
+ Att_uid uint32
+ Att_gid uint32
+ Att_opaquemask [3]uint8
+ Att_visblmaskres uint8
+ Att_opaque [3]uint8
+ Att_visibleres uint8
+ Att_size_h uint32
+ Att_size_l uint32
+ Att_atime uint32
+ Att_mtime uint32
+ Att_auditoraudit uint32
+ Att_useraudit uint32
+ Att_ctime uint32
+ Att_reftime uint32
+ // end of version 1
+ Att_filefmt uint8
+ Att_res02 [3]uint8
+ Att_filetag uint32
+ Att_res03 [8]uint8
+ // end of version 2
+ Att_atime64 uint64
+ Att_mtime64 uint64
+ Att_ctime64 uint64
+ Att_reftime64 uint64
+ Att_seclabel [8]uint8
+ Att_ver3res02 [8]uint8
+ // end of version 3
+}
+
+func BpxOpen(name string, options *BpxFilestatus, mode *BpxMode) (rv int32, rc int32, rn int32) {
+ if len(name) < 1024 {
+ var namebuf [1024]byte
+ sz := int32(copy(namebuf[:], name))
+ A2e(namebuf[:sz])
+ var parms [7]unsafe.Pointer
+ parms[0] = unsafe.Pointer(&sz)
+ parms[1] = unsafe.Pointer(&namebuf[0])
+ parms[2] = unsafe.Pointer(options)
+ parms[3] = unsafe.Pointer(mode)
+ parms[4] = unsafe.Pointer(&rv)
+ parms[5] = unsafe.Pointer(&rc)
+ parms[6] = unsafe.Pointer(&rn)
+ bpxcall(parms[:], BPX4OPN)
+ return rv, rc, rn
+ }
+ return -1, -1, -1
+}
+
+func BpxClose(fd int32) (rv int32, rc int32, rn int32) {
+ var parms [4]unsafe.Pointer
+ parms[0] = unsafe.Pointer(&fd)
+ parms[1] = unsafe.Pointer(&rv)
+ parms[2] = unsafe.Pointer(&rc)
+ parms[3] = unsafe.Pointer(&rn)
+ bpxcall(parms[:], BPX4CLO)
+ return rv, rc, rn
+}
+
+func BpxFileFStat(fd int32, st *Bpxystat_t) (rv int32, rc int32, rn int32) {
+ st.St_id = [4]uint8{0xe2, 0xe3, 0xc1, 0xe3}
+ st.St_version = 2
+ stat_sz := uint32(unsafe.Sizeof(*st))
+ var parms [6]unsafe.Pointer
+ parms[0] = unsafe.Pointer(&fd)
+ parms[1] = unsafe.Pointer(&stat_sz)
+ parms[2] = unsafe.Pointer(st)
+ parms[3] = unsafe.Pointer(&rv)
+ parms[4] = unsafe.Pointer(&rc)
+ parms[5] = unsafe.Pointer(&rn)
+ bpxcall(parms[:], BPX4FST)
+ return rv, rc, rn
+}
+
+func BpxFileStat(name string, st *Bpxystat_t) (rv int32, rc int32, rn int32) {
+ if len(name) < 1024 {
+ var namebuf [1024]byte
+ sz := int32(copy(namebuf[:], name))
+ A2e(namebuf[:sz])
+ st.St_id = [4]uint8{0xe2, 0xe3, 0xc1, 0xe3}
+ st.St_version = 2
+ stat_sz := uint32(unsafe.Sizeof(*st))
+ var parms [7]unsafe.Pointer
+ parms[0] = unsafe.Pointer(&sz)
+ parms[1] = unsafe.Pointer(&namebuf[0])
+ parms[2] = unsafe.Pointer(&stat_sz)
+ parms[3] = unsafe.Pointer(st)
+ parms[4] = unsafe.Pointer(&rv)
+ parms[5] = unsafe.Pointer(&rc)
+ parms[6] = unsafe.Pointer(&rn)
+ bpxcall(parms[:], BPX4STA)
+ return rv, rc, rn
+ }
+ return -1, -1, -1
+}
+
+func BpxFileLStat(name string, st *Bpxystat_t) (rv int32, rc int32, rn int32) {
+ if len(name) < 1024 {
+ var namebuf [1024]byte
+ sz := int32(copy(namebuf[:], name))
+ A2e(namebuf[:sz])
+ st.St_id = [4]uint8{0xe2, 0xe3, 0xc1, 0xe3}
+ st.St_version = 2
+ stat_sz := uint32(unsafe.Sizeof(*st))
+ var parms [7]unsafe.Pointer
+ parms[0] = unsafe.Pointer(&sz)
+ parms[1] = unsafe.Pointer(&namebuf[0])
+ parms[2] = unsafe.Pointer(&stat_sz)
+ parms[3] = unsafe.Pointer(st)
+ parms[4] = unsafe.Pointer(&rv)
+ parms[5] = unsafe.Pointer(&rc)
+ parms[6] = unsafe.Pointer(&rn)
+ bpxcall(parms[:], BPX4LST)
+ return rv, rc, rn
+ }
+ return -1, -1, -1
+}
+
+func BpxChattr(path string, attr *Bpxyatt_t) (rv int32, rc int32, rn int32) {
+ if len(path) >= 1024 {
+ return -1, -1, -1
+ }
+ var namebuf [1024]byte
+ sz := int32(copy(namebuf[:], path))
+ A2e(namebuf[:sz])
+ attr_sz := uint32(unsafe.Sizeof(*attr))
+ var parms [7]unsafe.Pointer
+ parms[0] = unsafe.Pointer(&sz)
+ parms[1] = unsafe.Pointer(&namebuf[0])
+ parms[2] = unsafe.Pointer(&attr_sz)
+ parms[3] = unsafe.Pointer(attr)
+ parms[4] = unsafe.Pointer(&rv)
+ parms[5] = unsafe.Pointer(&rc)
+ parms[6] = unsafe.Pointer(&rn)
+ bpxcall(parms[:], BPX4CHR)
+ return rv, rc, rn
+}
+
+func BpxLchattr(path string, attr *Bpxyatt_t) (rv int32, rc int32, rn int32) {
+ if len(path) >= 1024 {
+ return -1, -1, -1
+ }
+ var namebuf [1024]byte
+ sz := int32(copy(namebuf[:], path))
+ A2e(namebuf[:sz])
+ attr_sz := uint32(unsafe.Sizeof(*attr))
+ var parms [7]unsafe.Pointer
+ parms[0] = unsafe.Pointer(&sz)
+ parms[1] = unsafe.Pointer(&namebuf[0])
+ parms[2] = unsafe.Pointer(&attr_sz)
+ parms[3] = unsafe.Pointer(attr)
+ parms[4] = unsafe.Pointer(&rv)
+ parms[5] = unsafe.Pointer(&rc)
+ parms[6] = unsafe.Pointer(&rn)
+ bpxcall(parms[:], BPX4LCR)
+ return rv, rc, rn
+}
+
+func BpxFchattr(fd int32, attr *Bpxyatt_t) (rv int32, rc int32, rn int32) {
+ attr_sz := uint32(unsafe.Sizeof(*attr))
+ var parms [6]unsafe.Pointer
+ parms[0] = unsafe.Pointer(&fd)
+ parms[1] = unsafe.Pointer(&attr_sz)
+ parms[2] = unsafe.Pointer(attr)
+ parms[3] = unsafe.Pointer(&rv)
+ parms[4] = unsafe.Pointer(&rc)
+ parms[5] = unsafe.Pointer(&rn)
+ bpxcall(parms[:], BPX4FCR)
+ return rv, rc, rn
+}
+
+func BpxCondTimedWait(sec uint32, nsec uint32, events uint32, secrem *uint32, nsecrem *uint32) (rv int32, rc int32, rn int32) {
+ var parms [8]unsafe.Pointer
+ parms[0] = unsafe.Pointer(&sec)
+ parms[1] = unsafe.Pointer(&nsec)
+ parms[2] = unsafe.Pointer(&events)
+ parms[3] = unsafe.Pointer(secrem)
+ parms[4] = unsafe.Pointer(nsecrem)
+ parms[5] = unsafe.Pointer(&rv)
+ parms[6] = unsafe.Pointer(&rc)
+ parms[7] = unsafe.Pointer(&rn)
+ bpxcall(parms[:], BPX4CTW)
+ return rv, rc, rn
+}
+func BpxGetthent(in *Pgtha, outlen *uint32, out unsafe.Pointer) (rv int32, rc int32, rn int32) {
+ var parms [7]unsafe.Pointer
+ inlen := uint32(26) // nothing else will work. Go says Pgtha is 28-byte because of alignment, but Pgtha is "packed" and must be 26-byte
+ parms[0] = unsafe.Pointer(&inlen)
+ parms[1] = unsafe.Pointer(&in)
+ parms[2] = unsafe.Pointer(outlen)
+ parms[3] = unsafe.Pointer(&out)
+ parms[4] = unsafe.Pointer(&rv)
+ parms[5] = unsafe.Pointer(&rc)
+ parms[6] = unsafe.Pointer(&rn)
+ bpxcall(parms[:], BPX4GTH)
+ return rv, rc, rn
+}
+func ZosJobname() (jobname string, err error) {
+ var pgtha Pgtha
+ pgtha.Pid = uint32(Getpid())
+ pgtha.Accesspid = PGTHA_CURRENT
+ pgtha.Flag1 = PGTHA_PROCESS
+ var out [256]byte
+ var outlen uint32
+ outlen = 256
+ rv, rc, rn := BpxGetthent(&pgtha, &outlen, unsafe.Pointer(&out[0]))
+ if rv == 0 {
+ gthc := []byte{0x87, 0xa3, 0x88, 0x83} // 'gthc' in ebcdic
+ ix := bytes.Index(out[:], gthc)
+ if ix == -1 {
+ err = fmt.Errorf("BPX4GTH: gthc return data not found")
+ return
+ }
+ jn := out[ix+80 : ix+88] // we didn't declare Pgthc, but jobname is 8-byte at offset 80
+ E2a(jn)
+ jobname = string(bytes.TrimRight(jn, " "))
+
+ } else {
+ err = fmt.Errorf("BPX4GTH: rc=%d errno=%d reason=code=0x%x", rv, rc, rn)
+ }
+ return
+}
+func Bpx4ptq(code int32, data string) (rv int32, rc int32, rn int32) {
+ var userdata [8]byte
+ var parms [5]unsafe.Pointer
+ copy(userdata[:], data+" ")
+ A2e(userdata[:])
+ parms[0] = unsafe.Pointer(&code)
+ parms[1] = unsafe.Pointer(&userdata[0])
+ parms[2] = unsafe.Pointer(&rv)
+ parms[3] = unsafe.Pointer(&rc)
+ parms[4] = unsafe.Pointer(&rn)
+ bpxcall(parms[:], BPX4PTQ)
+ return rv, rc, rn
+}
+
+const (
+ PT_TRACE_ME = 0 // Debug this process
+ PT_READ_I = 1 // Read a full word
+ PT_READ_D = 2 // Read a full word
+ PT_READ_U = 3 // Read control info
+ PT_WRITE_I = 4 //Write a full word
+ PT_WRITE_D = 5 //Write a full word
+ PT_CONTINUE = 7 //Continue the process
+ PT_KILL = 8 //Terminate the process
+ PT_READ_GPR = 11 // Read GPR, CR, PSW
+ PT_READ_FPR = 12 // Read FPR
+ PT_READ_VR = 13 // Read VR
+ PT_WRITE_GPR = 14 // Write GPR, CR, PSW
+ PT_WRITE_FPR = 15 // Write FPR
+ PT_WRITE_VR = 16 // Write VR
+ PT_READ_BLOCK = 17 // Read storage
+ PT_WRITE_BLOCK = 19 // Write storage
+ PT_READ_GPRH = 20 // Read GPRH
+ PT_WRITE_GPRH = 21 // Write GPRH
+ PT_REGHSET = 22 // Read all GPRHs
+ PT_ATTACH = 30 // Attach to a process
+ PT_DETACH = 31 // Detach from a process
+ PT_REGSET = 32 // Read all GPRs
+ PT_REATTACH = 33 // Reattach to a process
+ PT_LDINFO = 34 // Read loader info
+ PT_MULTI = 35 // Multi process mode
+ PT_LD64INFO = 36 // RMODE64 Info Area
+ PT_BLOCKREQ = 40 // Block request
+ PT_THREAD_INFO = 60 // Read thread info
+ PT_THREAD_MODIFY = 61
+ PT_THREAD_READ_FOCUS = 62
+ PT_THREAD_WRITE_FOCUS = 63
+ PT_THREAD_HOLD = 64
+ PT_THREAD_SIGNAL = 65
+ PT_EXPLAIN = 66
+ PT_EVENTS = 67
+ PT_THREAD_INFO_EXTENDED = 68
+ PT_REATTACH2 = 71
+ PT_CAPTURE = 72
+ PT_UNCAPTURE = 73
+ PT_GET_THREAD_TCB = 74
+ PT_GET_ALET = 75
+ PT_SWAPIN = 76
+ PT_EXTENDED_EVENT = 98
+ PT_RECOVER = 99 // Debug a program check
+ PT_GPR0 = 0 // General purpose register 0
+ PT_GPR1 = 1 // General purpose register 1
+ PT_GPR2 = 2 // General purpose register 2
+ PT_GPR3 = 3 // General purpose register 3
+ PT_GPR4 = 4 // General purpose register 4
+ PT_GPR5 = 5 // General purpose register 5
+ PT_GPR6 = 6 // General purpose register 6
+ PT_GPR7 = 7 // General purpose register 7
+ PT_GPR8 = 8 // General purpose register 8
+ PT_GPR9 = 9 // General purpose register 9
+ PT_GPR10 = 10 // General purpose register 10
+ PT_GPR11 = 11 // General purpose register 11
+ PT_GPR12 = 12 // General purpose register 12
+ PT_GPR13 = 13 // General purpose register 13
+ PT_GPR14 = 14 // General purpose register 14
+ PT_GPR15 = 15 // General purpose register 15
+ PT_FPR0 = 16 // Floating point register 0
+ PT_FPR1 = 17 // Floating point register 1
+ PT_FPR2 = 18 // Floating point register 2
+ PT_FPR3 = 19 // Floating point register 3
+ PT_FPR4 = 20 // Floating point register 4
+ PT_FPR5 = 21 // Floating point register 5
+ PT_FPR6 = 22 // Floating point register 6
+ PT_FPR7 = 23 // Floating point register 7
+ PT_FPR8 = 24 // Floating point register 8
+ PT_FPR9 = 25 // Floating point register 9
+ PT_FPR10 = 26 // Floating point register 10
+ PT_FPR11 = 27 // Floating point register 11
+ PT_FPR12 = 28 // Floating point register 12
+ PT_FPR13 = 29 // Floating point register 13
+ PT_FPR14 = 30 // Floating point register 14
+ PT_FPR15 = 31 // Floating point register 15
+ PT_FPC = 32 // Floating point control register
+ PT_PSW = 40 // PSW
+ PT_PSW0 = 40 // Left half of the PSW
+ PT_PSW1 = 41 // Right half of the PSW
+ PT_CR0 = 42 // Control register 0
+ PT_CR1 = 43 // Control register 1
+ PT_CR2 = 44 // Control register 2
+ PT_CR3 = 45 // Control register 3
+ PT_CR4 = 46 // Control register 4
+ PT_CR5 = 47 // Control register 5
+ PT_CR6 = 48 // Control register 6
+ PT_CR7 = 49 // Control register 7
+ PT_CR8 = 50 // Control register 8
+ PT_CR9 = 51 // Control register 9
+ PT_CR10 = 52 // Control register 10
+ PT_CR11 = 53 // Control register 11
+ PT_CR12 = 54 // Control register 12
+ PT_CR13 = 55 // Control register 13
+ PT_CR14 = 56 // Control register 14
+ PT_CR15 = 57 // Control register 15
+ PT_GPRH0 = 58 // GP High register 0
+ PT_GPRH1 = 59 // GP High register 1
+ PT_GPRH2 = 60 // GP High register 2
+ PT_GPRH3 = 61 // GP High register 3
+ PT_GPRH4 = 62 // GP High register 4
+ PT_GPRH5 = 63 // GP High register 5
+ PT_GPRH6 = 64 // GP High register 6
+ PT_GPRH7 = 65 // GP High register 7
+ PT_GPRH8 = 66 // GP High register 8
+ PT_GPRH9 = 67 // GP High register 9
+ PT_GPRH10 = 68 // GP High register 10
+ PT_GPRH11 = 69 // GP High register 11
+ PT_GPRH12 = 70 // GP High register 12
+ PT_GPRH13 = 71 // GP High register 13
+ PT_GPRH14 = 72 // GP High register 14
+ PT_GPRH15 = 73 // GP High register 15
+ PT_VR0 = 74 // Vector register 0
+ PT_VR1 = 75 // Vector register 1
+ PT_VR2 = 76 // Vector register 2
+ PT_VR3 = 77 // Vector register 3
+ PT_VR4 = 78 // Vector register 4
+ PT_VR5 = 79 // Vector register 5
+ PT_VR6 = 80 // Vector register 6
+ PT_VR7 = 81 // Vector register 7
+ PT_VR8 = 82 // Vector register 8
+ PT_VR9 = 83 // Vector register 9
+ PT_VR10 = 84 // Vector register 10
+ PT_VR11 = 85 // Vector register 11
+ PT_VR12 = 86 // Vector register 12
+ PT_VR13 = 87 // Vector register 13
+ PT_VR14 = 88 // Vector register 14
+ PT_VR15 = 89 // Vector register 15
+ PT_VR16 = 90 // Vector register 16
+ PT_VR17 = 91 // Vector register 17
+ PT_VR18 = 92 // Vector register 18
+ PT_VR19 = 93 // Vector register 19
+ PT_VR20 = 94 // Vector register 20
+ PT_VR21 = 95 // Vector register 21
+ PT_VR22 = 96 // Vector register 22
+ PT_VR23 = 97 // Vector register 23
+ PT_VR24 = 98 // Vector register 24
+ PT_VR25 = 99 // Vector register 25
+ PT_VR26 = 100 // Vector register 26
+ PT_VR27 = 101 // Vector register 27
+ PT_VR28 = 102 // Vector register 28
+ PT_VR29 = 103 // Vector register 29
+ PT_VR30 = 104 // Vector register 30
+ PT_VR31 = 105 // Vector register 31
+ PT_PSWG = 106 // PSWG
+ PT_PSWG0 = 106 // Bytes 0-3
+ PT_PSWG1 = 107 // Bytes 4-7
+ PT_PSWG2 = 108 // Bytes 8-11 (IA high word)
+ PT_PSWG3 = 109 // Bytes 12-15 (IA low word)
+)
+
+func Bpx4ptr(request int32, pid int32, addr unsafe.Pointer, data unsafe.Pointer, buffer unsafe.Pointer) (rv int32, rc int32, rn int32) {
+ var parms [8]unsafe.Pointer
+ parms[0] = unsafe.Pointer(&request)
+ parms[1] = unsafe.Pointer(&pid)
+ parms[2] = unsafe.Pointer(&addr)
+ parms[3] = unsafe.Pointer(&data)
+ parms[4] = unsafe.Pointer(&buffer)
+ parms[5] = unsafe.Pointer(&rv)
+ parms[6] = unsafe.Pointer(&rc)
+ parms[7] = unsafe.Pointer(&rn)
+ bpxcall(parms[:], BPX4PTR)
+ return rv, rc, rn
+}
+
+func copyU8(val uint8, dest []uint8) int {
+ if len(dest) < 1 {
+ return 0
+ }
+ dest[0] = val
+ return 1
+}
+
+func copyU8Arr(src, dest []uint8) int {
+ if len(dest) < len(src) {
+ return 0
+ }
+ for i, v := range src {
+ dest[i] = v
+ }
+ return len(src)
+}
+
+func copyU16(val uint16, dest []uint16) int {
+ if len(dest) < 1 {
+ return 0
+ }
+ dest[0] = val
+ return 1
+}
+
+func copyU32(val uint32, dest []uint32) int {
+ if len(dest) < 1 {
+ return 0
+ }
+ dest[0] = val
+ return 1
+}
+
+func copyU32Arr(src, dest []uint32) int {
+ if len(dest) < len(src) {
+ return 0
+ }
+ for i, v := range src {
+ dest[i] = v
+ }
+ return len(src)
+}
+
+func copyU64(val uint64, dest []uint64) int {
+ if len(dest) < 1 {
+ return 0
+ }
+ dest[0] = val
+ return 1
+}
diff --git a/vendor/golang.org/x/sys/unix/bpxsvc_zos.s b/vendor/golang.org/x/sys/unix/bpxsvc_zos.s
new file mode 100644
index 0000000..4bd4a17
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/bpxsvc_zos.s
@@ -0,0 +1,192 @@
+// Copyright 2024 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.
+
+#include "go_asm.h"
+#include "textflag.h"
+
+// function to call USS assembly language services
+//
+// doc: https://www.ibm.com/support/knowledgecenter/en/SSLTBW_3.1.0/com.ibm.zos.v3r1.bpxb100/bit64env.htm
+//
+// arg1 unsafe.Pointer array that ressembles an OS PLIST
+//
+// arg2 function offset as in
+// doc: https://www.ibm.com/support/knowledgecenter/en/SSLTBW_3.1.0/com.ibm.zos.v3r1.bpxb100/bpx2cr_List_of_offsets.htm
+//
+// func bpxcall(plist []unsafe.Pointer, bpx_offset int64)
+
+TEXT ·bpxcall(SB), NOSPLIT|NOFRAME, $0
+ MOVD plist_base+0(FP), R1 // r1 points to plist
+ MOVD bpx_offset+24(FP), R2 // r2 offset to BPX vector table
+ MOVD R14, R7 // save r14
+ MOVD R15, R8 // save r15
+ MOVWZ 16(R0), R9
+ MOVWZ 544(R9), R9
+ MOVWZ 24(R9), R9 // call vector in r9
+ ADD R2, R9 // add offset to vector table
+ MOVWZ (R9), R9 // r9 points to entry point
+ BYTE $0x0D // BL R14,R9 --> basr r14,r9
+ BYTE $0xE9 // clobbers 0,1,14,15
+ MOVD R8, R15 // restore 15
+ JMP R7 // return via saved return address
+
+// func A2e(arr [] byte)
+// code page conversion from 819 to 1047
+TEXT ·A2e(SB), NOSPLIT|NOFRAME, $0
+ MOVD arg_base+0(FP), R2 // pointer to arry of characters
+ MOVD arg_len+8(FP), R3 // count
+ XOR R0, R0
+ XOR R1, R1
+ BYTE $0xA7; BYTE $0x15; BYTE $0x00; BYTE $0x82 // BRAS 1,(2+(256/2))
+
+ // ASCII -> EBCDIC conversion table:
+ BYTE $0x00; BYTE $0x01; BYTE $0x02; BYTE $0x03
+ BYTE $0x37; BYTE $0x2d; BYTE $0x2e; BYTE $0x2f
+ BYTE $0x16; BYTE $0x05; BYTE $0x15; BYTE $0x0b
+ BYTE $0x0c; BYTE $0x0d; BYTE $0x0e; BYTE $0x0f
+ BYTE $0x10; BYTE $0x11; BYTE $0x12; BYTE $0x13
+ BYTE $0x3c; BYTE $0x3d; BYTE $0x32; BYTE $0x26
+ BYTE $0x18; BYTE $0x19; BYTE $0x3f; BYTE $0x27
+ BYTE $0x1c; BYTE $0x1d; BYTE $0x1e; BYTE $0x1f
+ BYTE $0x40; BYTE $0x5a; BYTE $0x7f; BYTE $0x7b
+ BYTE $0x5b; BYTE $0x6c; BYTE $0x50; BYTE $0x7d
+ BYTE $0x4d; BYTE $0x5d; BYTE $0x5c; BYTE $0x4e
+ BYTE $0x6b; BYTE $0x60; BYTE $0x4b; BYTE $0x61
+ BYTE $0xf0; BYTE $0xf1; BYTE $0xf2; BYTE $0xf3
+ BYTE $0xf4; BYTE $0xf5; BYTE $0xf6; BYTE $0xf7
+ BYTE $0xf8; BYTE $0xf9; BYTE $0x7a; BYTE $0x5e
+ BYTE $0x4c; BYTE $0x7e; BYTE $0x6e; BYTE $0x6f
+ BYTE $0x7c; BYTE $0xc1; BYTE $0xc2; BYTE $0xc3
+ BYTE $0xc4; BYTE $0xc5; BYTE $0xc6; BYTE $0xc7
+ BYTE $0xc8; BYTE $0xc9; BYTE $0xd1; BYTE $0xd2
+ BYTE $0xd3; BYTE $0xd4; BYTE $0xd5; BYTE $0xd6
+ BYTE $0xd7; BYTE $0xd8; BYTE $0xd9; BYTE $0xe2
+ BYTE $0xe3; BYTE $0xe4; BYTE $0xe5; BYTE $0xe6
+ BYTE $0xe7; BYTE $0xe8; BYTE $0xe9; BYTE $0xad
+ BYTE $0xe0; BYTE $0xbd; BYTE $0x5f; BYTE $0x6d
+ BYTE $0x79; BYTE $0x81; BYTE $0x82; BYTE $0x83
+ BYTE $0x84; BYTE $0x85; BYTE $0x86; BYTE $0x87
+ BYTE $0x88; BYTE $0x89; BYTE $0x91; BYTE $0x92
+ BYTE $0x93; BYTE $0x94; BYTE $0x95; BYTE $0x96
+ BYTE $0x97; BYTE $0x98; BYTE $0x99; BYTE $0xa2
+ BYTE $0xa3; BYTE $0xa4; BYTE $0xa5; BYTE $0xa6
+ BYTE $0xa7; BYTE $0xa8; BYTE $0xa9; BYTE $0xc0
+ BYTE $0x4f; BYTE $0xd0; BYTE $0xa1; BYTE $0x07
+ BYTE $0x20; BYTE $0x21; BYTE $0x22; BYTE $0x23
+ BYTE $0x24; BYTE $0x25; BYTE $0x06; BYTE $0x17
+ BYTE $0x28; BYTE $0x29; BYTE $0x2a; BYTE $0x2b
+ BYTE $0x2c; BYTE $0x09; BYTE $0x0a; BYTE $0x1b
+ BYTE $0x30; BYTE $0x31; BYTE $0x1a; BYTE $0x33
+ BYTE $0x34; BYTE $0x35; BYTE $0x36; BYTE $0x08
+ BYTE $0x38; BYTE $0x39; BYTE $0x3a; BYTE $0x3b
+ BYTE $0x04; BYTE $0x14; BYTE $0x3e; BYTE $0xff
+ BYTE $0x41; BYTE $0xaa; BYTE $0x4a; BYTE $0xb1
+ BYTE $0x9f; BYTE $0xb2; BYTE $0x6a; BYTE $0xb5
+ BYTE $0xbb; BYTE $0xb4; BYTE $0x9a; BYTE $0x8a
+ BYTE $0xb0; BYTE $0xca; BYTE $0xaf; BYTE $0xbc
+ BYTE $0x90; BYTE $0x8f; BYTE $0xea; BYTE $0xfa
+ BYTE $0xbe; BYTE $0xa0; BYTE $0xb6; BYTE $0xb3
+ BYTE $0x9d; BYTE $0xda; BYTE $0x9b; BYTE $0x8b
+ BYTE $0xb7; BYTE $0xb8; BYTE $0xb9; BYTE $0xab
+ BYTE $0x64; BYTE $0x65; BYTE $0x62; BYTE $0x66
+ BYTE $0x63; BYTE $0x67; BYTE $0x9e; BYTE $0x68
+ BYTE $0x74; BYTE $0x71; BYTE $0x72; BYTE $0x73
+ BYTE $0x78; BYTE $0x75; BYTE $0x76; BYTE $0x77
+ BYTE $0xac; BYTE $0x69; BYTE $0xed; BYTE $0xee
+ BYTE $0xeb; BYTE $0xef; BYTE $0xec; BYTE $0xbf
+ BYTE $0x80; BYTE $0xfd; BYTE $0xfe; BYTE $0xfb
+ BYTE $0xfc; BYTE $0xba; BYTE $0xae; BYTE $0x59
+ BYTE $0x44; BYTE $0x45; BYTE $0x42; BYTE $0x46
+ BYTE $0x43; BYTE $0x47; BYTE $0x9c; BYTE $0x48
+ BYTE $0x54; BYTE $0x51; BYTE $0x52; BYTE $0x53
+ BYTE $0x58; BYTE $0x55; BYTE $0x56; BYTE $0x57
+ BYTE $0x8c; BYTE $0x49; BYTE $0xcd; BYTE $0xce
+ BYTE $0xcb; BYTE $0xcf; BYTE $0xcc; BYTE $0xe1
+ BYTE $0x70; BYTE $0xdd; BYTE $0xde; BYTE $0xdb
+ BYTE $0xdc; BYTE $0x8d; BYTE $0x8e; BYTE $0xdf
+
+retry:
+ WORD $0xB9931022 // TROO 2,2,b'0001'
+ BVS retry
+ RET
+
+// func e2a(arr [] byte)
+// code page conversion from 1047 to 819
+TEXT ·E2a(SB), NOSPLIT|NOFRAME, $0
+ MOVD arg_base+0(FP), R2 // pointer to arry of characters
+ MOVD arg_len+8(FP), R3 // count
+ XOR R0, R0
+ XOR R1, R1
+ BYTE $0xA7; BYTE $0x15; BYTE $0x00; BYTE $0x82 // BRAS 1,(2+(256/2))
+
+ // EBCDIC -> ASCII conversion table:
+ BYTE $0x00; BYTE $0x01; BYTE $0x02; BYTE $0x03
+ BYTE $0x9c; BYTE $0x09; BYTE $0x86; BYTE $0x7f
+ BYTE $0x97; BYTE $0x8d; BYTE $0x8e; BYTE $0x0b
+ BYTE $0x0c; BYTE $0x0d; BYTE $0x0e; BYTE $0x0f
+ BYTE $0x10; BYTE $0x11; BYTE $0x12; BYTE $0x13
+ BYTE $0x9d; BYTE $0x0a; BYTE $0x08; BYTE $0x87
+ BYTE $0x18; BYTE $0x19; BYTE $0x92; BYTE $0x8f
+ BYTE $0x1c; BYTE $0x1d; BYTE $0x1e; BYTE $0x1f
+ BYTE $0x80; BYTE $0x81; BYTE $0x82; BYTE $0x83
+ BYTE $0x84; BYTE $0x85; BYTE $0x17; BYTE $0x1b
+ BYTE $0x88; BYTE $0x89; BYTE $0x8a; BYTE $0x8b
+ BYTE $0x8c; BYTE $0x05; BYTE $0x06; BYTE $0x07
+ BYTE $0x90; BYTE $0x91; BYTE $0x16; BYTE $0x93
+ BYTE $0x94; BYTE $0x95; BYTE $0x96; BYTE $0x04
+ BYTE $0x98; BYTE $0x99; BYTE $0x9a; BYTE $0x9b
+ BYTE $0x14; BYTE $0x15; BYTE $0x9e; BYTE $0x1a
+ BYTE $0x20; BYTE $0xa0; BYTE $0xe2; BYTE $0xe4
+ BYTE $0xe0; BYTE $0xe1; BYTE $0xe3; BYTE $0xe5
+ BYTE $0xe7; BYTE $0xf1; BYTE $0xa2; BYTE $0x2e
+ BYTE $0x3c; BYTE $0x28; BYTE $0x2b; BYTE $0x7c
+ BYTE $0x26; BYTE $0xe9; BYTE $0xea; BYTE $0xeb
+ BYTE $0xe8; BYTE $0xed; BYTE $0xee; BYTE $0xef
+ BYTE $0xec; BYTE $0xdf; BYTE $0x21; BYTE $0x24
+ BYTE $0x2a; BYTE $0x29; BYTE $0x3b; BYTE $0x5e
+ BYTE $0x2d; BYTE $0x2f; BYTE $0xc2; BYTE $0xc4
+ BYTE $0xc0; BYTE $0xc1; BYTE $0xc3; BYTE $0xc5
+ BYTE $0xc7; BYTE $0xd1; BYTE $0xa6; BYTE $0x2c
+ BYTE $0x25; BYTE $0x5f; BYTE $0x3e; BYTE $0x3f
+ BYTE $0xf8; BYTE $0xc9; BYTE $0xca; BYTE $0xcb
+ BYTE $0xc8; BYTE $0xcd; BYTE $0xce; BYTE $0xcf
+ BYTE $0xcc; BYTE $0x60; BYTE $0x3a; BYTE $0x23
+ BYTE $0x40; BYTE $0x27; BYTE $0x3d; BYTE $0x22
+ BYTE $0xd8; BYTE $0x61; BYTE $0x62; BYTE $0x63
+ BYTE $0x64; BYTE $0x65; BYTE $0x66; BYTE $0x67
+ BYTE $0x68; BYTE $0x69; BYTE $0xab; BYTE $0xbb
+ BYTE $0xf0; BYTE $0xfd; BYTE $0xfe; BYTE $0xb1
+ BYTE $0xb0; BYTE $0x6a; BYTE $0x6b; BYTE $0x6c
+ BYTE $0x6d; BYTE $0x6e; BYTE $0x6f; BYTE $0x70
+ BYTE $0x71; BYTE $0x72; BYTE $0xaa; BYTE $0xba
+ BYTE $0xe6; BYTE $0xb8; BYTE $0xc6; BYTE $0xa4
+ BYTE $0xb5; BYTE $0x7e; BYTE $0x73; BYTE $0x74
+ BYTE $0x75; BYTE $0x76; BYTE $0x77; BYTE $0x78
+ BYTE $0x79; BYTE $0x7a; BYTE $0xa1; BYTE $0xbf
+ BYTE $0xd0; BYTE $0x5b; BYTE $0xde; BYTE $0xae
+ BYTE $0xac; BYTE $0xa3; BYTE $0xa5; BYTE $0xb7
+ BYTE $0xa9; BYTE $0xa7; BYTE $0xb6; BYTE $0xbc
+ BYTE $0xbd; BYTE $0xbe; BYTE $0xdd; BYTE $0xa8
+ BYTE $0xaf; BYTE $0x5d; BYTE $0xb4; BYTE $0xd7
+ BYTE $0x7b; BYTE $0x41; BYTE $0x42; BYTE $0x43
+ BYTE $0x44; BYTE $0x45; BYTE $0x46; BYTE $0x47
+ BYTE $0x48; BYTE $0x49; BYTE $0xad; BYTE $0xf4
+ BYTE $0xf6; BYTE $0xf2; BYTE $0xf3; BYTE $0xf5
+ BYTE $0x7d; BYTE $0x4a; BYTE $0x4b; BYTE $0x4c
+ BYTE $0x4d; BYTE $0x4e; BYTE $0x4f; BYTE $0x50
+ BYTE $0x51; BYTE $0x52; BYTE $0xb9; BYTE $0xfb
+ BYTE $0xfc; BYTE $0xf9; BYTE $0xfa; BYTE $0xff
+ BYTE $0x5c; BYTE $0xf7; BYTE $0x53; BYTE $0x54
+ BYTE $0x55; BYTE $0x56; BYTE $0x57; BYTE $0x58
+ BYTE $0x59; BYTE $0x5a; BYTE $0xb2; BYTE $0xd4
+ BYTE $0xd6; BYTE $0xd2; BYTE $0xd3; BYTE $0xd5
+ BYTE $0x30; BYTE $0x31; BYTE $0x32; BYTE $0x33
+ BYTE $0x34; BYTE $0x35; BYTE $0x36; BYTE $0x37
+ BYTE $0x38; BYTE $0x39; BYTE $0xb3; BYTE $0xdb
+ BYTE $0xdc; BYTE $0xd9; BYTE $0xda; BYTE $0x9f
+
+retry:
+ WORD $0xB9931022 // TROO 2,2,b'0001'
+ BVS retry
+ RET
diff --git a/vendor/golang.org/x/sys/unix/cap_freebsd.go b/vendor/golang.org/x/sys/unix/cap_freebsd.go
new file mode 100644
index 0000000..a086578
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/cap_freebsd.go
@@ -0,0 +1,195 @@
+// Copyright 2017 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.
+
+//go:build freebsd
+
+package unix
+
+import (
+ "errors"
+ "fmt"
+)
+
+// Go implementation of C mostly found in /usr/src/sys/kern/subr_capability.c
+
+const (
+ // This is the version of CapRights this package understands. See C implementation for parallels.
+ capRightsGoVersion = CAP_RIGHTS_VERSION_00
+ capArSizeMin = CAP_RIGHTS_VERSION_00 + 2
+ capArSizeMax = capRightsGoVersion + 2
+)
+
+var (
+ bit2idx = []int{
+ -1, 0, 1, -1, 2, -1, -1, -1, 3, -1, -1, -1, -1, -1, -1, -1,
+ 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ }
+)
+
+func capidxbit(right uint64) int {
+ return int((right >> 57) & 0x1f)
+}
+
+func rightToIndex(right uint64) (int, error) {
+ idx := capidxbit(right)
+ if idx < 0 || idx >= len(bit2idx) {
+ return -2, fmt.Errorf("index for right 0x%x out of range", right)
+ }
+ return bit2idx[idx], nil
+}
+
+func caprver(right uint64) int {
+ return int(right >> 62)
+}
+
+func capver(rights *CapRights) int {
+ return caprver(rights.Rights[0])
+}
+
+func caparsize(rights *CapRights) int {
+ return capver(rights) + 2
+}
+
+// CapRightsSet sets the permissions in setrights in rights.
+func CapRightsSet(rights *CapRights, setrights []uint64) error {
+ // This is essentially a copy of cap_rights_vset()
+ if capver(rights) != CAP_RIGHTS_VERSION_00 {
+ return fmt.Errorf("bad rights version %d", capver(rights))
+ }
+
+ n := caparsize(rights)
+ if n < capArSizeMin || n > capArSizeMax {
+ return errors.New("bad rights size")
+ }
+
+ for _, right := range setrights {
+ if caprver(right) != CAP_RIGHTS_VERSION_00 {
+ return errors.New("bad right version")
+ }
+ i, err := rightToIndex(right)
+ if err != nil {
+ return err
+ }
+ if i >= n {
+ return errors.New("index overflow")
+ }
+ if capidxbit(rights.Rights[i]) != capidxbit(right) {
+ return errors.New("index mismatch")
+ }
+ rights.Rights[i] |= right
+ if capidxbit(rights.Rights[i]) != capidxbit(right) {
+ return errors.New("index mismatch (after assign)")
+ }
+ }
+
+ return nil
+}
+
+// CapRightsClear clears the permissions in clearrights from rights.
+func CapRightsClear(rights *CapRights, clearrights []uint64) error {
+ // This is essentially a copy of cap_rights_vclear()
+ if capver(rights) != CAP_RIGHTS_VERSION_00 {
+ return fmt.Errorf("bad rights version %d", capver(rights))
+ }
+
+ n := caparsize(rights)
+ if n < capArSizeMin || n > capArSizeMax {
+ return errors.New("bad rights size")
+ }
+
+ for _, right := range clearrights {
+ if caprver(right) != CAP_RIGHTS_VERSION_00 {
+ return errors.New("bad right version")
+ }
+ i, err := rightToIndex(right)
+ if err != nil {
+ return err
+ }
+ if i >= n {
+ return errors.New("index overflow")
+ }
+ if capidxbit(rights.Rights[i]) != capidxbit(right) {
+ return errors.New("index mismatch")
+ }
+ rights.Rights[i] &= ^(right & 0x01FFFFFFFFFFFFFF)
+ if capidxbit(rights.Rights[i]) != capidxbit(right) {
+ return errors.New("index mismatch (after assign)")
+ }
+ }
+
+ return nil
+}
+
+// CapRightsIsSet checks whether all the permissions in setrights are present in rights.
+func CapRightsIsSet(rights *CapRights, setrights []uint64) (bool, error) {
+ // This is essentially a copy of cap_rights_is_vset()
+ if capver(rights) != CAP_RIGHTS_VERSION_00 {
+ return false, fmt.Errorf("bad rights version %d", capver(rights))
+ }
+
+ n := caparsize(rights)
+ if n < capArSizeMin || n > capArSizeMax {
+ return false, errors.New("bad rights size")
+ }
+
+ for _, right := range setrights {
+ if caprver(right) != CAP_RIGHTS_VERSION_00 {
+ return false, errors.New("bad right version")
+ }
+ i, err := rightToIndex(right)
+ if err != nil {
+ return false, err
+ }
+ if i >= n {
+ return false, errors.New("index overflow")
+ }
+ if capidxbit(rights.Rights[i]) != capidxbit(right) {
+ return false, errors.New("index mismatch")
+ }
+ if (rights.Rights[i] & right) != right {
+ return false, nil
+ }
+ }
+
+ return true, nil
+}
+
+func capright(idx uint64, bit uint64) uint64 {
+ return ((1 << (57 + idx)) | bit)
+}
+
+// CapRightsInit returns a pointer to an initialised CapRights structure filled with rights.
+// See man cap_rights_init(3) and rights(4).
+func CapRightsInit(rights []uint64) (*CapRights, error) {
+ var r CapRights
+ r.Rights[0] = (capRightsGoVersion << 62) | capright(0, 0)
+ r.Rights[1] = capright(1, 0)
+
+ err := CapRightsSet(&r, rights)
+ if err != nil {
+ return nil, err
+ }
+ return &r, nil
+}
+
+// CapRightsLimit reduces the operations permitted on fd to at most those contained in rights.
+// The capability rights on fd can never be increased by CapRightsLimit.
+// See man cap_rights_limit(2) and rights(4).
+func CapRightsLimit(fd uintptr, rights *CapRights) error {
+ return capRightsLimit(int(fd), rights)
+}
+
+// CapRightsGet returns a CapRights structure containing the operations permitted on fd.
+// See man cap_rights_get(3) and rights(4).
+func CapRightsGet(fd uintptr) (*CapRights, error) {
+ r, err := CapRightsInit(nil)
+ if err != nil {
+ return nil, err
+ }
+ err = capRightsGet(capRightsGoVersion, int(fd), r)
+ if err != nil {
+ return nil, err
+ }
+ return r, nil
+}
diff --git a/vendor/golang.org/x/sys/unix/constants.go b/vendor/golang.org/x/sys/unix/constants.go
new file mode 100644
index 0000000..6fb7cb7
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/constants.go
@@ -0,0 +1,13 @@
+// Copyright 2015 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.
+
+//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos
+
+package unix
+
+const (
+ R_OK = 0x4
+ W_OK = 0x2
+ X_OK = 0x1
+)
diff --git a/vendor/golang.org/x/sys/unix/dev_aix_ppc.go b/vendor/golang.org/x/sys/unix/dev_aix_ppc.go
new file mode 100644
index 0000000..d785134
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/dev_aix_ppc.go
@@ -0,0 +1,26 @@
+// Copyright 2018 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.
+
+//go:build aix && ppc
+
+// Functions to access/create device major and minor numbers matching the
+// encoding used by AIX.
+
+package unix
+
+// Major returns the major component of a Linux device number.
+func Major(dev uint64) uint32 {
+ return uint32((dev >> 16) & 0xffff)
+}
+
+// Minor returns the minor component of a Linux device number.
+func Minor(dev uint64) uint32 {
+ return uint32(dev & 0xffff)
+}
+
+// Mkdev returns a Linux device number generated from the given major and minor
+// components.
+func Mkdev(major, minor uint32) uint64 {
+ return uint64(((major) << 16) | (minor))
+}
diff --git a/vendor/golang.org/x/sys/unix/dev_aix_ppc64.go b/vendor/golang.org/x/sys/unix/dev_aix_ppc64.go
new file mode 100644
index 0000000..623a5e6
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/dev_aix_ppc64.go
@@ -0,0 +1,28 @@
+// Copyright 2018 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.
+
+//go:build aix && ppc64
+
+// Functions to access/create device major and minor numbers matching the
+// encoding used AIX.
+
+package unix
+
+// Major returns the major component of a Linux device number.
+func Major(dev uint64) uint32 {
+ return uint32((dev & 0x3fffffff00000000) >> 32)
+}
+
+// Minor returns the minor component of a Linux device number.
+func Minor(dev uint64) uint32 {
+ return uint32((dev & 0x00000000ffffffff) >> 0)
+}
+
+// Mkdev returns a Linux device number generated from the given major and minor
+// components.
+func Mkdev(major, minor uint32) uint64 {
+ var DEVNO64 uint64
+ DEVNO64 = 0x8000000000000000
+ return ((uint64(major) << 32) | (uint64(minor) & 0x00000000FFFFFFFF) | DEVNO64)
+}
diff --git a/vendor/golang.org/x/sys/unix/dev_darwin.go b/vendor/golang.org/x/sys/unix/dev_darwin.go
new file mode 100644
index 0000000..8d1dc0f
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/dev_darwin.go
@@ -0,0 +1,24 @@
+// Copyright 2017 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.
+
+// Functions to access/create device major and minor numbers matching the
+// encoding used in Darwin's sys/types.h header.
+
+package unix
+
+// Major returns the major component of a Darwin device number.
+func Major(dev uint64) uint32 {
+ return uint32((dev >> 24) & 0xff)
+}
+
+// Minor returns the minor component of a Darwin device number.
+func Minor(dev uint64) uint32 {
+ return uint32(dev & 0xffffff)
+}
+
+// Mkdev returns a Darwin device number generated from the given major and minor
+// components.
+func Mkdev(major, minor uint32) uint64 {
+ return (uint64(major) << 24) | uint64(minor)
+}
diff --git a/vendor/golang.org/x/sys/unix/dev_dragonfly.go b/vendor/golang.org/x/sys/unix/dev_dragonfly.go
new file mode 100644
index 0000000..8502f20
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/dev_dragonfly.go
@@ -0,0 +1,30 @@
+// Copyright 2017 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.
+
+// Functions to access/create device major and minor numbers matching the
+// encoding used in Dragonfly's sys/types.h header.
+//
+// The information below is extracted and adapted from sys/types.h:
+//
+// Minor gives a cookie instead of an index since in order to avoid changing the
+// meanings of bits 0-15 or wasting time and space shifting bits 16-31 for
+// devices that don't use them.
+
+package unix
+
+// Major returns the major component of a DragonFlyBSD device number.
+func Major(dev uint64) uint32 {
+ return uint32((dev >> 8) & 0xff)
+}
+
+// Minor returns the minor component of a DragonFlyBSD device number.
+func Minor(dev uint64) uint32 {
+ return uint32(dev & 0xffff00ff)
+}
+
+// Mkdev returns a DragonFlyBSD device number generated from the given major and
+// minor components.
+func Mkdev(major, minor uint32) uint64 {
+ return (uint64(major) << 8) | uint64(minor)
+}
diff --git a/vendor/golang.org/x/sys/unix/dev_freebsd.go b/vendor/golang.org/x/sys/unix/dev_freebsd.go
new file mode 100644
index 0000000..eba3b4b
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/dev_freebsd.go
@@ -0,0 +1,30 @@
+// Copyright 2017 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.
+
+// Functions to access/create device major and minor numbers matching the
+// encoding used in FreeBSD's sys/types.h header.
+//
+// The information below is extracted and adapted from sys/types.h:
+//
+// Minor gives a cookie instead of an index since in order to avoid changing the
+// meanings of bits 0-15 or wasting time and space shifting bits 16-31 for
+// devices that don't use them.
+
+package unix
+
+// Major returns the major component of a FreeBSD device number.
+func Major(dev uint64) uint32 {
+ return uint32((dev >> 8) & 0xff)
+}
+
+// Minor returns the minor component of a FreeBSD device number.
+func Minor(dev uint64) uint32 {
+ return uint32(dev & 0xffff00ff)
+}
+
+// Mkdev returns a FreeBSD device number generated from the given major and
+// minor components.
+func Mkdev(major, minor uint32) uint64 {
+ return (uint64(major) << 8) | uint64(minor)
+}
diff --git a/vendor/golang.org/x/sys/unix/dev_linux.go b/vendor/golang.org/x/sys/unix/dev_linux.go
new file mode 100644
index 0000000..d165d6f
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/dev_linux.go
@@ -0,0 +1,42 @@
+// Copyright 2017 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.
+
+// Functions to access/create device major and minor numbers matching the
+// encoding used by the Linux kernel and glibc.
+//
+// The information below is extracted and adapted from bits/sysmacros.h in the
+// glibc sources:
+//
+// dev_t in glibc is 64-bit, with 32-bit major and minor numbers. glibc's
+// default encoding is MMMM Mmmm mmmM MMmm, where M is a hex digit of the major
+// number and m is a hex digit of the minor number. This is backward compatible
+// with legacy systems where dev_t is 16 bits wide, encoded as MMmm. It is also
+// backward compatible with the Linux kernel, which for some architectures uses
+// 32-bit dev_t, encoded as mmmM MMmm.
+
+package unix
+
+// Major returns the major component of a Linux device number.
+func Major(dev uint64) uint32 {
+ major := uint32((dev & 0x00000000000fff00) >> 8)
+ major |= uint32((dev & 0xfffff00000000000) >> 32)
+ return major
+}
+
+// Minor returns the minor component of a Linux device number.
+func Minor(dev uint64) uint32 {
+ minor := uint32((dev & 0x00000000000000ff) >> 0)
+ minor |= uint32((dev & 0x00000ffffff00000) >> 12)
+ return minor
+}
+
+// Mkdev returns a Linux device number generated from the given major and minor
+// components.
+func Mkdev(major, minor uint32) uint64 {
+ dev := (uint64(major) & 0x00000fff) << 8
+ dev |= (uint64(major) & 0xfffff000) << 32
+ dev |= (uint64(minor) & 0x000000ff) << 0
+ dev |= (uint64(minor) & 0xffffff00) << 12
+ return dev
+}
diff --git a/vendor/golang.org/x/sys/unix/dev_netbsd.go b/vendor/golang.org/x/sys/unix/dev_netbsd.go
new file mode 100644
index 0000000..b4a203d
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/dev_netbsd.go
@@ -0,0 +1,29 @@
+// Copyright 2017 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.
+
+// Functions to access/create device major and minor numbers matching the
+// encoding used in NetBSD's sys/types.h header.
+
+package unix
+
+// Major returns the major component of a NetBSD device number.
+func Major(dev uint64) uint32 {
+ return uint32((dev & 0x000fff00) >> 8)
+}
+
+// Minor returns the minor component of a NetBSD device number.
+func Minor(dev uint64) uint32 {
+ minor := uint32((dev & 0x000000ff) >> 0)
+ minor |= uint32((dev & 0xfff00000) >> 12)
+ return minor
+}
+
+// Mkdev returns a NetBSD device number generated from the given major and minor
+// components.
+func Mkdev(major, minor uint32) uint64 {
+ dev := (uint64(major) << 8) & 0x000fff00
+ dev |= (uint64(minor) << 12) & 0xfff00000
+ dev |= (uint64(minor) << 0) & 0x000000ff
+ return dev
+}
diff --git a/vendor/golang.org/x/sys/unix/dev_openbsd.go b/vendor/golang.org/x/sys/unix/dev_openbsd.go
new file mode 100644
index 0000000..f3430c4
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/dev_openbsd.go
@@ -0,0 +1,29 @@
+// Copyright 2017 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.
+
+// Functions to access/create device major and minor numbers matching the
+// encoding used in OpenBSD's sys/types.h header.
+
+package unix
+
+// Major returns the major component of an OpenBSD device number.
+func Major(dev uint64) uint32 {
+ return uint32((dev & 0x0000ff00) >> 8)
+}
+
+// Minor returns the minor component of an OpenBSD device number.
+func Minor(dev uint64) uint32 {
+ minor := uint32((dev & 0x000000ff) >> 0)
+ minor |= uint32((dev & 0xffff0000) >> 8)
+ return minor
+}
+
+// Mkdev returns an OpenBSD device number generated from the given major and minor
+// components.
+func Mkdev(major, minor uint32) uint64 {
+ dev := (uint64(major) << 8) & 0x0000ff00
+ dev |= (uint64(minor) << 8) & 0xffff0000
+ dev |= (uint64(minor) << 0) & 0x000000ff
+ return dev
+}
diff --git a/vendor/golang.org/x/sys/unix/dev_zos.go b/vendor/golang.org/x/sys/unix/dev_zos.go
new file mode 100644
index 0000000..bb6a64f
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/dev_zos.go
@@ -0,0 +1,28 @@
+// Copyright 2020 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.
+
+//go:build zos && s390x
+
+// Functions to access/create device major and minor numbers matching the
+// encoding used by z/OS.
+//
+// The information below is extracted and adapted from macros.
+
+package unix
+
+// Major returns the major component of a z/OS device number.
+func Major(dev uint64) uint32 {
+ return uint32((dev >> 16) & 0x0000FFFF)
+}
+
+// Minor returns the minor component of a z/OS device number.
+func Minor(dev uint64) uint32 {
+ return uint32(dev & 0x0000FFFF)
+}
+
+// Mkdev returns a z/OS device number generated from the given major and minor
+// components.
+func Mkdev(major, minor uint32) uint64 {
+ return (uint64(major) << 16) | uint64(minor)
+}
diff --git a/vendor/golang.org/x/sys/unix/dirent.go b/vendor/golang.org/x/sys/unix/dirent.go
new file mode 100644
index 0000000..1ebf117
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/dirent.go
@@ -0,0 +1,102 @@
+// Copyright 2009 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.
+
+//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos
+
+package unix
+
+import "unsafe"
+
+// readInt returns the size-bytes unsigned integer in native byte order at offset off.
+func readInt(b []byte, off, size uintptr) (u uint64, ok bool) {
+ if len(b) < int(off+size) {
+ return 0, false
+ }
+ if isBigEndian {
+ return readIntBE(b[off:], size), true
+ }
+ return readIntLE(b[off:], size), true
+}
+
+func readIntBE(b []byte, size uintptr) uint64 {
+ switch size {
+ case 1:
+ return uint64(b[0])
+ case 2:
+ _ = b[1] // bounds check hint to compiler; see golang.org/issue/14808
+ return uint64(b[1]) | uint64(b[0])<<8
+ case 4:
+ _ = b[3] // bounds check hint to compiler; see golang.org/issue/14808
+ return uint64(b[3]) | uint64(b[2])<<8 | uint64(b[1])<<16 | uint64(b[0])<<24
+ case 8:
+ _ = b[7] // bounds check hint to compiler; see golang.org/issue/14808
+ return uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 |
+ uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56
+ default:
+ panic("syscall: readInt with unsupported size")
+ }
+}
+
+func readIntLE(b []byte, size uintptr) uint64 {
+ switch size {
+ case 1:
+ return uint64(b[0])
+ case 2:
+ _ = b[1] // bounds check hint to compiler; see golang.org/issue/14808
+ return uint64(b[0]) | uint64(b[1])<<8
+ case 4:
+ _ = b[3] // bounds check hint to compiler; see golang.org/issue/14808
+ return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24
+ case 8:
+ _ = b[7] // bounds check hint to compiler; see golang.org/issue/14808
+ return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 |
+ uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56
+ default:
+ panic("syscall: readInt with unsupported size")
+ }
+}
+
+// ParseDirent parses up to max directory entries in buf,
+// appending the names to names. It returns the number of
+// bytes consumed from buf, the number of entries added
+// to names, and the new names slice.
+func ParseDirent(buf []byte, max int, names []string) (consumed int, count int, newnames []string) {
+ origlen := len(buf)
+ count = 0
+ for max != 0 && len(buf) > 0 {
+ reclen, ok := direntReclen(buf)
+ if !ok || reclen > uint64(len(buf)) {
+ return origlen, count, names
+ }
+ rec := buf[:reclen]
+ buf = buf[reclen:]
+ ino, ok := direntIno(rec)
+ if !ok {
+ break
+ }
+ if ino == 0 { // File absent in directory.
+ continue
+ }
+ const namoff = uint64(unsafe.Offsetof(Dirent{}.Name))
+ namlen, ok := direntNamlen(rec)
+ if !ok || namoff+namlen > uint64(len(rec)) {
+ break
+ }
+ name := rec[namoff : namoff+namlen]
+ for i, c := range name {
+ if c == 0 {
+ name = name[:i]
+ break
+ }
+ }
+ // Check for useless names before allocating a string.
+ if string(name) == "." || string(name) == ".." {
+ continue
+ }
+ max--
+ count++
+ names = append(names, string(name))
+ }
+ return origlen - len(buf), count, names
+}
diff --git a/vendor/golang.org/x/sys/unix/endian_big.go b/vendor/golang.org/x/sys/unix/endian_big.go
new file mode 100644
index 0000000..1095fd3
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/endian_big.go
@@ -0,0 +1,9 @@
+// Copyright 2016 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.
+//
+//go:build armbe || arm64be || m68k || mips || mips64 || mips64p32 || ppc || ppc64 || s390 || s390x || shbe || sparc || sparc64
+
+package unix
+
+const isBigEndian = true
diff --git a/vendor/golang.org/x/sys/unix/endian_little.go b/vendor/golang.org/x/sys/unix/endian_little.go
new file mode 100644
index 0000000..b9f0e27
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/endian_little.go
@@ -0,0 +1,9 @@
+// Copyright 2016 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.
+//
+//go:build 386 || amd64 || amd64p32 || alpha || arm || arm64 || loong64 || mipsle || mips64le || mips64p32le || nios2 || ppc64le || riscv || riscv64 || sh
+
+package unix
+
+const isBigEndian = false
diff --git a/vendor/golang.org/x/sys/unix/env_unix.go b/vendor/golang.org/x/sys/unix/env_unix.go
new file mode 100644
index 0000000..a96da71
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/env_unix.go
@@ -0,0 +1,31 @@
+// 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.
+
+//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos
+
+// Unix environment variables.
+
+package unix
+
+import "syscall"
+
+func Getenv(key string) (value string, found bool) {
+ return syscall.Getenv(key)
+}
+
+func Setenv(key, value string) error {
+ return syscall.Setenv(key, value)
+}
+
+func Clearenv() {
+ syscall.Clearenv()
+}
+
+func Environ() []string {
+ return syscall.Environ()
+}
+
+func Unsetenv(key string) error {
+ return syscall.Unsetenv(key)
+}
diff --git a/vendor/golang.org/x/sys/unix/fcntl.go b/vendor/golang.org/x/sys/unix/fcntl.go
new file mode 100644
index 0000000..6200876
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/fcntl.go
@@ -0,0 +1,36 @@
+// Copyright 2014 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.
+
+//go:build dragonfly || freebsd || linux || netbsd
+
+package unix
+
+import "unsafe"
+
+// fcntl64Syscall is usually SYS_FCNTL, but is overridden on 32-bit Linux
+// systems by fcntl_linux_32bit.go to be SYS_FCNTL64.
+var fcntl64Syscall uintptr = SYS_FCNTL
+
+func fcntl(fd int, cmd, arg int) (int, error) {
+ valptr, _, errno := Syscall(fcntl64Syscall, uintptr(fd), uintptr(cmd), uintptr(arg))
+ var err error
+ if errno != 0 {
+ err = errno
+ }
+ return int(valptr), err
+}
+
+// FcntlInt performs a fcntl syscall on fd with the provided command and argument.
+func FcntlInt(fd uintptr, cmd, arg int) (int, error) {
+ return fcntl(int(fd), cmd, arg)
+}
+
+// FcntlFlock performs a fcntl syscall for the F_GETLK, F_SETLK or F_SETLKW command.
+func FcntlFlock(fd uintptr, cmd int, lk *Flock_t) error {
+ _, _, errno := Syscall(fcntl64Syscall, fd, uintptr(cmd), uintptr(unsafe.Pointer(lk)))
+ if errno == 0 {
+ return nil
+ }
+ return errno
+}
diff --git a/vendor/golang.org/x/sys/unix/fcntl_darwin.go b/vendor/golang.org/x/sys/unix/fcntl_darwin.go
new file mode 100644
index 0000000..a9911c7
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/fcntl_darwin.go
@@ -0,0 +1,24 @@
+// Copyright 2019 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 unix
+
+import "unsafe"
+
+// FcntlInt performs a fcntl syscall on fd with the provided command and argument.
+func FcntlInt(fd uintptr, cmd, arg int) (int, error) {
+ return fcntl(int(fd), cmd, arg)
+}
+
+// FcntlFlock performs a fcntl syscall for the F_GETLK, F_SETLK or F_SETLKW command.
+func FcntlFlock(fd uintptr, cmd int, lk *Flock_t) error {
+ _, err := fcntl(int(fd), cmd, int(uintptr(unsafe.Pointer(lk))))
+ return err
+}
+
+// FcntlFstore performs a fcntl syscall for the F_PREALLOCATE command.
+func FcntlFstore(fd uintptr, cmd int, fstore *Fstore_t) error {
+ _, err := fcntl(int(fd), cmd, int(uintptr(unsafe.Pointer(fstore))))
+ return err
+}
diff --git a/vendor/golang.org/x/sys/unix/fcntl_linux_32bit.go b/vendor/golang.org/x/sys/unix/fcntl_linux_32bit.go
new file mode 100644
index 0000000..13b4acd
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/fcntl_linux_32bit.go
@@ -0,0 +1,13 @@
+// Copyright 2014 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.
+
+//go:build (linux && 386) || (linux && arm) || (linux && mips) || (linux && mipsle) || (linux && ppc)
+
+package unix
+
+func init() {
+ // On 32-bit Linux systems, the fcntl syscall that matches Go's
+ // Flock_t type is SYS_FCNTL64, not SYS_FCNTL.
+ fcntl64Syscall = SYS_FCNTL64
+}
diff --git a/vendor/golang.org/x/sys/unix/fdset.go b/vendor/golang.org/x/sys/unix/fdset.go
new file mode 100644
index 0000000..9e83d18
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/fdset.go
@@ -0,0 +1,29 @@
+// Copyright 2019 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.
+
+//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos
+
+package unix
+
+// Set adds fd to the set fds.
+func (fds *FdSet) Set(fd int) {
+ fds.Bits[fd/NFDBITS] |= (1 << (uintptr(fd) % NFDBITS))
+}
+
+// Clear removes fd from the set fds.
+func (fds *FdSet) Clear(fd int) {
+ fds.Bits[fd/NFDBITS] &^= (1 << (uintptr(fd) % NFDBITS))
+}
+
+// IsSet returns whether fd is in the set fds.
+func (fds *FdSet) IsSet(fd int) bool {
+ return fds.Bits[fd/NFDBITS]&(1<<(uintptr(fd)%NFDBITS)) != 0
+}
+
+// Zero clears the set fds.
+func (fds *FdSet) Zero() {
+ for i := range fds.Bits {
+ fds.Bits[i] = 0
+ }
+}
diff --git a/vendor/golang.org/x/sys/unix/gccgo.go b/vendor/golang.org/x/sys/unix/gccgo.go
new file mode 100644
index 0000000..aca5721
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/gccgo.go
@@ -0,0 +1,59 @@
+// Copyright 2015 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.
+
+//go:build gccgo && !aix && !hurd
+
+package unix
+
+import "syscall"
+
+// We can't use the gc-syntax .s files for gccgo. On the plus side
+// much of the functionality can be written directly in Go.
+
+func realSyscallNoError(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r uintptr)
+
+func realSyscall(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r, errno uintptr)
+
+func SyscallNoError(trap, a1, a2, a3 uintptr) (r1, r2 uintptr) {
+ syscall.Entersyscall()
+ r := realSyscallNoError(trap, a1, a2, a3, 0, 0, 0, 0, 0, 0)
+ syscall.Exitsyscall()
+ return r, 0
+}
+
+func Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno) {
+ syscall.Entersyscall()
+ r, errno := realSyscall(trap, a1, a2, a3, 0, 0, 0, 0, 0, 0)
+ syscall.Exitsyscall()
+ return r, 0, syscall.Errno(errno)
+}
+
+func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err syscall.Errno) {
+ syscall.Entersyscall()
+ r, errno := realSyscall(trap, a1, a2, a3, a4, a5, a6, 0, 0, 0)
+ syscall.Exitsyscall()
+ return r, 0, syscall.Errno(errno)
+}
+
+func Syscall9(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err syscall.Errno) {
+ syscall.Entersyscall()
+ r, errno := realSyscall(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9)
+ syscall.Exitsyscall()
+ return r, 0, syscall.Errno(errno)
+}
+
+func RawSyscallNoError(trap, a1, a2, a3 uintptr) (r1, r2 uintptr) {
+ r := realSyscallNoError(trap, a1, a2, a3, 0, 0, 0, 0, 0, 0)
+ return r, 0
+}
+
+func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno) {
+ r, errno := realSyscall(trap, a1, a2, a3, 0, 0, 0, 0, 0, 0)
+ return r, 0, syscall.Errno(errno)
+}
+
+func RawSyscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err syscall.Errno) {
+ r, errno := realSyscall(trap, a1, a2, a3, a4, a5, a6, 0, 0, 0)
+ return r, 0, syscall.Errno(errno)
+}
diff --git a/vendor/golang.org/x/sys/unix/gccgo_c.c b/vendor/golang.org/x/sys/unix/gccgo_c.c
new file mode 100644
index 0000000..d468b7b
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/gccgo_c.c
@@ -0,0 +1,44 @@
+// Copyright 2015 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.
+
+//go:build gccgo && !aix && !hurd
+
+#include
+#include
+#include
+
+#define _STRINGIFY2_(x) #x
+#define _STRINGIFY_(x) _STRINGIFY2_(x)
+#define GOSYM_PREFIX _STRINGIFY_(__USER_LABEL_PREFIX__)
+
+// Call syscall from C code because the gccgo support for calling from
+// Go to C does not support varargs functions.
+
+struct ret {
+ uintptr_t r;
+ uintptr_t err;
+};
+
+struct ret gccgoRealSyscall(uintptr_t trap, uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4, uintptr_t a5, uintptr_t a6, uintptr_t a7, uintptr_t a8, uintptr_t a9)
+ __asm__(GOSYM_PREFIX GOPKGPATH ".realSyscall");
+
+struct ret
+gccgoRealSyscall(uintptr_t trap, uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4, uintptr_t a5, uintptr_t a6, uintptr_t a7, uintptr_t a8, uintptr_t a9)
+{
+ struct ret r;
+
+ errno = 0;
+ r.r = syscall(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+ r.err = errno;
+ return r;
+}
+
+uintptr_t gccgoRealSyscallNoError(uintptr_t trap, uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4, uintptr_t a5, uintptr_t a6, uintptr_t a7, uintptr_t a8, uintptr_t a9)
+ __asm__(GOSYM_PREFIX GOPKGPATH ".realSyscallNoError");
+
+uintptr_t
+gccgoRealSyscallNoError(uintptr_t trap, uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4, uintptr_t a5, uintptr_t a6, uintptr_t a7, uintptr_t a8, uintptr_t a9)
+{
+ return syscall(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+}
diff --git a/vendor/golang.org/x/sys/unix/gccgo_linux_amd64.go b/vendor/golang.org/x/sys/unix/gccgo_linux_amd64.go
new file mode 100644
index 0000000..972d61b
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/gccgo_linux_amd64.go
@@ -0,0 +1,20 @@
+// Copyright 2015 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.
+
+//go:build gccgo && linux && amd64
+
+package unix
+
+import "syscall"
+
+//extern gettimeofday
+func realGettimeofday(*Timeval, *byte) int32
+
+func gettimeofday(tv *Timeval) (err syscall.Errno) {
+ r := realGettimeofday(tv, nil)
+ if r < 0 {
+ return syscall.GetErrno()
+ }
+ return 0
+}
diff --git a/vendor/golang.org/x/sys/unix/ifreq_linux.go b/vendor/golang.org/x/sys/unix/ifreq_linux.go
new file mode 100644
index 0000000..848840a
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/ifreq_linux.go
@@ -0,0 +1,141 @@
+// Copyright 2021 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.
+
+//go:build linux
+
+package unix
+
+import (
+ "unsafe"
+)
+
+// Helpers for dealing with ifreq since it contains a union and thus requires a
+// lot of unsafe.Pointer casts to use properly.
+
+// An Ifreq is a type-safe wrapper around the raw ifreq struct. An Ifreq
+// contains an interface name and a union of arbitrary data which can be
+// accessed using the Ifreq's methods. To create an Ifreq, use the NewIfreq
+// function.
+//
+// Use the Name method to access the stored interface name. The union data
+// fields can be get and set using the following methods:
+// - Uint16/SetUint16: flags
+// - Uint32/SetUint32: ifindex, metric, mtu
+type Ifreq struct{ raw ifreq }
+
+// NewIfreq creates an Ifreq with the input network interface name after
+// validating the name does not exceed IFNAMSIZ-1 (trailing NULL required)
+// bytes.
+func NewIfreq(name string) (*Ifreq, error) {
+ // Leave room for terminating NULL byte.
+ if len(name) >= IFNAMSIZ {
+ return nil, EINVAL
+ }
+
+ var ifr ifreq
+ copy(ifr.Ifrn[:], name)
+
+ return &Ifreq{raw: ifr}, nil
+}
+
+// TODO(mdlayher): get/set methods for hardware address sockaddr, char array, etc.
+
+// Name returns the interface name associated with the Ifreq.
+func (ifr *Ifreq) Name() string {
+ return ByteSliceToString(ifr.raw.Ifrn[:])
+}
+
+// According to netdevice(7), only AF_INET addresses are returned for numerous
+// sockaddr ioctls. For convenience, we expose these as Inet4Addr since the Port
+// field and other data is always empty.
+
+// Inet4Addr returns the Ifreq union data from an embedded sockaddr as a C
+// in_addr/Go []byte (4-byte IPv4 address) value. If the sockaddr family is not
+// AF_INET, an error is returned.
+func (ifr *Ifreq) Inet4Addr() ([]byte, error) {
+ raw := *(*RawSockaddrInet4)(unsafe.Pointer(&ifr.raw.Ifru[:SizeofSockaddrInet4][0]))
+ if raw.Family != AF_INET {
+ // Cannot safely interpret raw.Addr bytes as an IPv4 address.
+ return nil, EINVAL
+ }
+
+ return raw.Addr[:], nil
+}
+
+// SetInet4Addr sets a C in_addr/Go []byte (4-byte IPv4 address) value in an
+// embedded sockaddr within the Ifreq's union data. v must be 4 bytes in length
+// or an error will be returned.
+func (ifr *Ifreq) SetInet4Addr(v []byte) error {
+ if len(v) != 4 {
+ return EINVAL
+ }
+
+ var addr [4]byte
+ copy(addr[:], v)
+
+ ifr.clear()
+ *(*RawSockaddrInet4)(
+ unsafe.Pointer(&ifr.raw.Ifru[:SizeofSockaddrInet4][0]),
+ ) = RawSockaddrInet4{
+ // Always set IP family as ioctls would require it anyway.
+ Family: AF_INET,
+ Addr: addr,
+ }
+
+ return nil
+}
+
+// Uint16 returns the Ifreq union data as a C short/Go uint16 value.
+func (ifr *Ifreq) Uint16() uint16 {
+ return *(*uint16)(unsafe.Pointer(&ifr.raw.Ifru[:2][0]))
+}
+
+// SetUint16 sets a C short/Go uint16 value as the Ifreq's union data.
+func (ifr *Ifreq) SetUint16(v uint16) {
+ ifr.clear()
+ *(*uint16)(unsafe.Pointer(&ifr.raw.Ifru[:2][0])) = v
+}
+
+// Uint32 returns the Ifreq union data as a C int/Go uint32 value.
+func (ifr *Ifreq) Uint32() uint32 {
+ return *(*uint32)(unsafe.Pointer(&ifr.raw.Ifru[:4][0]))
+}
+
+// SetUint32 sets a C int/Go uint32 value as the Ifreq's union data.
+func (ifr *Ifreq) SetUint32(v uint32) {
+ ifr.clear()
+ *(*uint32)(unsafe.Pointer(&ifr.raw.Ifru[:4][0])) = v
+}
+
+// clear zeroes the ifreq's union field to prevent trailing garbage data from
+// being sent to the kernel if an ifreq is reused.
+func (ifr *Ifreq) clear() {
+ for i := range ifr.raw.Ifru {
+ ifr.raw.Ifru[i] = 0
+ }
+}
+
+// TODO(mdlayher): export as IfreqData? For now we can provide helpers such as
+// IoctlGetEthtoolDrvinfo which use these APIs under the hood.
+
+// An ifreqData is an Ifreq which carries pointer data. To produce an ifreqData,
+// use the Ifreq.withData method.
+type ifreqData struct {
+ name [IFNAMSIZ]byte
+ // A type separate from ifreq is required in order to comply with the
+ // unsafe.Pointer rules since the "pointer-ness" of data would not be
+ // preserved if it were cast into the byte array of a raw ifreq.
+ data unsafe.Pointer
+ // Pad to the same size as ifreq.
+ _ [len(ifreq{}.Ifru) - SizeofPtr]byte
+}
+
+// withData produces an ifreqData with the pointer p set for ioctls which require
+// arbitrary pointer data.
+func (ifr Ifreq) withData(p unsafe.Pointer) ifreqData {
+ return ifreqData{
+ name: ifr.raw.Ifrn,
+ data: p,
+ }
+}
diff --git a/vendor/golang.org/x/sys/unix/ioctl_linux.go b/vendor/golang.org/x/sys/unix/ioctl_linux.go
new file mode 100644
index 0000000..dbe680e
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/ioctl_linux.go
@@ -0,0 +1,238 @@
+// Copyright 2021 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 unix
+
+import "unsafe"
+
+// IoctlRetInt performs an ioctl operation specified by req on a device
+// associated with opened file descriptor fd, and returns a non-negative
+// integer that is returned by the ioctl syscall.
+func IoctlRetInt(fd int, req uint) (int, error) {
+ ret, _, err := Syscall(SYS_IOCTL, uintptr(fd), uintptr(req), 0)
+ if err != 0 {
+ return 0, err
+ }
+ return int(ret), nil
+}
+
+func IoctlGetUint32(fd int, req uint) (uint32, error) {
+ var value uint32
+ err := ioctlPtr(fd, req, unsafe.Pointer(&value))
+ return value, err
+}
+
+func IoctlGetRTCTime(fd int) (*RTCTime, error) {
+ var value RTCTime
+ err := ioctlPtr(fd, RTC_RD_TIME, unsafe.Pointer(&value))
+ return &value, err
+}
+
+func IoctlSetRTCTime(fd int, value *RTCTime) error {
+ return ioctlPtr(fd, RTC_SET_TIME, unsafe.Pointer(value))
+}
+
+func IoctlGetRTCWkAlrm(fd int) (*RTCWkAlrm, error) {
+ var value RTCWkAlrm
+ err := ioctlPtr(fd, RTC_WKALM_RD, unsafe.Pointer(&value))
+ return &value, err
+}
+
+func IoctlSetRTCWkAlrm(fd int, value *RTCWkAlrm) error {
+ return ioctlPtr(fd, RTC_WKALM_SET, unsafe.Pointer(value))
+}
+
+// IoctlGetEthtoolDrvinfo fetches ethtool driver information for the network
+// device specified by ifname.
+func IoctlGetEthtoolDrvinfo(fd int, ifname string) (*EthtoolDrvinfo, error) {
+ ifr, err := NewIfreq(ifname)
+ if err != nil {
+ return nil, err
+ }
+
+ value := EthtoolDrvinfo{Cmd: ETHTOOL_GDRVINFO}
+ ifrd := ifr.withData(unsafe.Pointer(&value))
+
+ err = ioctlIfreqData(fd, SIOCETHTOOL, &ifrd)
+ return &value, err
+}
+
+// IoctlGetWatchdogInfo fetches information about a watchdog device from the
+// Linux watchdog API. For more information, see:
+// https://www.kernel.org/doc/html/latest/watchdog/watchdog-api.html.
+func IoctlGetWatchdogInfo(fd int) (*WatchdogInfo, error) {
+ var value WatchdogInfo
+ err := ioctlPtr(fd, WDIOC_GETSUPPORT, unsafe.Pointer(&value))
+ return &value, err
+}
+
+// IoctlWatchdogKeepalive issues a keepalive ioctl to a watchdog device. For
+// more information, see:
+// https://www.kernel.org/doc/html/latest/watchdog/watchdog-api.html.
+func IoctlWatchdogKeepalive(fd int) error {
+ // arg is ignored and not a pointer, so ioctl is fine instead of ioctlPtr.
+ return ioctl(fd, WDIOC_KEEPALIVE, 0)
+}
+
+// IoctlFileCloneRange performs an FICLONERANGE ioctl operation to clone the
+// range of data conveyed in value to the file associated with the file
+// descriptor destFd. See the ioctl_ficlonerange(2) man page for details.
+func IoctlFileCloneRange(destFd int, value *FileCloneRange) error {
+ return ioctlPtr(destFd, FICLONERANGE, unsafe.Pointer(value))
+}
+
+// IoctlFileClone performs an FICLONE ioctl operation to clone the entire file
+// associated with the file description srcFd to the file associated with the
+// file descriptor destFd. See the ioctl_ficlone(2) man page for details.
+func IoctlFileClone(destFd, srcFd int) error {
+ return ioctl(destFd, FICLONE, uintptr(srcFd))
+}
+
+type FileDedupeRange struct {
+ Src_offset uint64
+ Src_length uint64
+ Reserved1 uint16
+ Reserved2 uint32
+ Info []FileDedupeRangeInfo
+}
+
+type FileDedupeRangeInfo struct {
+ Dest_fd int64
+ Dest_offset uint64
+ Bytes_deduped uint64
+ Status int32
+ Reserved uint32
+}
+
+// IoctlFileDedupeRange performs an FIDEDUPERANGE ioctl operation to share the
+// range of data conveyed in value from the file associated with the file
+// descriptor srcFd to the value.Info destinations. See the
+// ioctl_fideduperange(2) man page for details.
+func IoctlFileDedupeRange(srcFd int, value *FileDedupeRange) error {
+ buf := make([]byte, SizeofRawFileDedupeRange+
+ len(value.Info)*SizeofRawFileDedupeRangeInfo)
+ rawrange := (*RawFileDedupeRange)(unsafe.Pointer(&buf[0]))
+ rawrange.Src_offset = value.Src_offset
+ rawrange.Src_length = value.Src_length
+ rawrange.Dest_count = uint16(len(value.Info))
+ rawrange.Reserved1 = value.Reserved1
+ rawrange.Reserved2 = value.Reserved2
+
+ for i := range value.Info {
+ rawinfo := (*RawFileDedupeRangeInfo)(unsafe.Pointer(
+ uintptr(unsafe.Pointer(&buf[0])) + uintptr(SizeofRawFileDedupeRange) +
+ uintptr(i*SizeofRawFileDedupeRangeInfo)))
+ rawinfo.Dest_fd = value.Info[i].Dest_fd
+ rawinfo.Dest_offset = value.Info[i].Dest_offset
+ rawinfo.Bytes_deduped = value.Info[i].Bytes_deduped
+ rawinfo.Status = value.Info[i].Status
+ rawinfo.Reserved = value.Info[i].Reserved
+ }
+
+ err := ioctlPtr(srcFd, FIDEDUPERANGE, unsafe.Pointer(&buf[0]))
+
+ // Output
+ for i := range value.Info {
+ rawinfo := (*RawFileDedupeRangeInfo)(unsafe.Pointer(
+ uintptr(unsafe.Pointer(&buf[0])) + uintptr(SizeofRawFileDedupeRange) +
+ uintptr(i*SizeofRawFileDedupeRangeInfo)))
+ value.Info[i].Dest_fd = rawinfo.Dest_fd
+ value.Info[i].Dest_offset = rawinfo.Dest_offset
+ value.Info[i].Bytes_deduped = rawinfo.Bytes_deduped
+ value.Info[i].Status = rawinfo.Status
+ value.Info[i].Reserved = rawinfo.Reserved
+ }
+
+ return err
+}
+
+func IoctlHIDGetDesc(fd int, value *HIDRawReportDescriptor) error {
+ return ioctlPtr(fd, HIDIOCGRDESC, unsafe.Pointer(value))
+}
+
+func IoctlHIDGetRawInfo(fd int) (*HIDRawDevInfo, error) {
+ var value HIDRawDevInfo
+ err := ioctlPtr(fd, HIDIOCGRAWINFO, unsafe.Pointer(&value))
+ return &value, err
+}
+
+func IoctlHIDGetRawName(fd int) (string, error) {
+ var value [_HIDIOCGRAWNAME_LEN]byte
+ err := ioctlPtr(fd, _HIDIOCGRAWNAME, unsafe.Pointer(&value[0]))
+ return ByteSliceToString(value[:]), err
+}
+
+func IoctlHIDGetRawPhys(fd int) (string, error) {
+ var value [_HIDIOCGRAWPHYS_LEN]byte
+ err := ioctlPtr(fd, _HIDIOCGRAWPHYS, unsafe.Pointer(&value[0]))
+ return ByteSliceToString(value[:]), err
+}
+
+func IoctlHIDGetRawUniq(fd int) (string, error) {
+ var value [_HIDIOCGRAWUNIQ_LEN]byte
+ err := ioctlPtr(fd, _HIDIOCGRAWUNIQ, unsafe.Pointer(&value[0]))
+ return ByteSliceToString(value[:]), err
+}
+
+// IoctlIfreq performs an ioctl using an Ifreq structure for input and/or
+// output. See the netdevice(7) man page for details.
+func IoctlIfreq(fd int, req uint, value *Ifreq) error {
+ // It is possible we will add more fields to *Ifreq itself later to prevent
+ // misuse, so pass the raw *ifreq directly.
+ return ioctlPtr(fd, req, unsafe.Pointer(&value.raw))
+}
+
+// TODO(mdlayher): export if and when IfreqData is exported.
+
+// ioctlIfreqData performs an ioctl using an ifreqData structure for input
+// and/or output. See the netdevice(7) man page for details.
+func ioctlIfreqData(fd int, req uint, value *ifreqData) error {
+ // The memory layout of IfreqData (type-safe) and ifreq (not type-safe) are
+ // identical so pass *IfreqData directly.
+ return ioctlPtr(fd, req, unsafe.Pointer(value))
+}
+
+// IoctlKCMClone attaches a new file descriptor to a multiplexor by cloning an
+// existing KCM socket, returning a structure containing the file descriptor of
+// the new socket.
+func IoctlKCMClone(fd int) (*KCMClone, error) {
+ var info KCMClone
+ if err := ioctlPtr(fd, SIOCKCMCLONE, unsafe.Pointer(&info)); err != nil {
+ return nil, err
+ }
+
+ return &info, nil
+}
+
+// IoctlKCMAttach attaches a TCP socket and associated BPF program file
+// descriptor to a multiplexor.
+func IoctlKCMAttach(fd int, info KCMAttach) error {
+ return ioctlPtr(fd, SIOCKCMATTACH, unsafe.Pointer(&info))
+}
+
+// IoctlKCMUnattach unattaches a TCP socket file descriptor from a multiplexor.
+func IoctlKCMUnattach(fd int, info KCMUnattach) error {
+ return ioctlPtr(fd, SIOCKCMUNATTACH, unsafe.Pointer(&info))
+}
+
+// IoctlLoopGetStatus64 gets the status of the loop device associated with the
+// file descriptor fd using the LOOP_GET_STATUS64 operation.
+func IoctlLoopGetStatus64(fd int) (*LoopInfo64, error) {
+ var value LoopInfo64
+ if err := ioctlPtr(fd, LOOP_GET_STATUS64, unsafe.Pointer(&value)); err != nil {
+ return nil, err
+ }
+ return &value, nil
+}
+
+// IoctlLoopSetStatus64 sets the status of the loop device associated with the
+// file descriptor fd using the LOOP_SET_STATUS64 operation.
+func IoctlLoopSetStatus64(fd int, value *LoopInfo64) error {
+ return ioctlPtr(fd, LOOP_SET_STATUS64, unsafe.Pointer(value))
+}
+
+// IoctlLoopConfigure configures all loop device parameters in a single step
+func IoctlLoopConfigure(fd int, value *LoopConfig) error {
+ return ioctlPtr(fd, LOOP_CONFIGURE, unsafe.Pointer(value))
+}
diff --git a/vendor/golang.org/x/sys/unix/ioctl_signed.go b/vendor/golang.org/x/sys/unix/ioctl_signed.go
new file mode 100644
index 0000000..5b0759b
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/ioctl_signed.go
@@ -0,0 +1,69 @@
+// Copyright 2018 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.
+
+//go:build aix || solaris
+
+package unix
+
+import (
+ "unsafe"
+)
+
+// ioctl itself should not be exposed directly, but additional get/set
+// functions for specific types are permissible.
+
+// IoctlSetInt performs an ioctl operation which sets an integer value
+// on fd, using the specified request number.
+func IoctlSetInt(fd int, req int, value int) error {
+ return ioctl(fd, req, uintptr(value))
+}
+
+// IoctlSetPointerInt performs an ioctl operation which sets an
+// integer value on fd, using the specified request number. The ioctl
+// argument is called with a pointer to the integer value, rather than
+// passing the integer value directly.
+func IoctlSetPointerInt(fd int, req int, value int) error {
+ v := int32(value)
+ return ioctlPtr(fd, req, unsafe.Pointer(&v))
+}
+
+// IoctlSetWinsize performs an ioctl on fd with a *Winsize argument.
+//
+// To change fd's window size, the req argument should be TIOCSWINSZ.
+func IoctlSetWinsize(fd int, req int, value *Winsize) error {
+ // TODO: if we get the chance, remove the req parameter and
+ // hardcode TIOCSWINSZ.
+ return ioctlPtr(fd, req, unsafe.Pointer(value))
+}
+
+// IoctlSetTermios performs an ioctl on fd with a *Termios.
+//
+// The req value will usually be TCSETA or TIOCSETA.
+func IoctlSetTermios(fd int, req int, value *Termios) error {
+ // TODO: if we get the chance, remove the req parameter.
+ return ioctlPtr(fd, req, unsafe.Pointer(value))
+}
+
+// IoctlGetInt performs an ioctl operation which gets an integer value
+// from fd, using the specified request number.
+//
+// A few ioctl requests use the return value as an output parameter;
+// for those, IoctlRetInt should be used instead of this function.
+func IoctlGetInt(fd int, req int) (int, error) {
+ var value int
+ err := ioctlPtr(fd, req, unsafe.Pointer(&value))
+ return value, err
+}
+
+func IoctlGetWinsize(fd int, req int) (*Winsize, error) {
+ var value Winsize
+ err := ioctlPtr(fd, req, unsafe.Pointer(&value))
+ return &value, err
+}
+
+func IoctlGetTermios(fd int, req int) (*Termios, error) {
+ var value Termios
+ err := ioctlPtr(fd, req, unsafe.Pointer(&value))
+ return &value, err
+}
diff --git a/vendor/golang.org/x/sys/unix/ioctl_unsigned.go b/vendor/golang.org/x/sys/unix/ioctl_unsigned.go
new file mode 100644
index 0000000..20f470b
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/ioctl_unsigned.go
@@ -0,0 +1,69 @@
+// Copyright 2018 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.
+
+//go:build darwin || dragonfly || freebsd || hurd || linux || netbsd || openbsd
+
+package unix
+
+import (
+ "unsafe"
+)
+
+// ioctl itself should not be exposed directly, but additional get/set
+// functions for specific types are permissible.
+
+// IoctlSetInt performs an ioctl operation which sets an integer value
+// on fd, using the specified request number.
+func IoctlSetInt(fd int, req uint, value int) error {
+ return ioctl(fd, req, uintptr(value))
+}
+
+// IoctlSetPointerInt performs an ioctl operation which sets an
+// integer value on fd, using the specified request number. The ioctl
+// argument is called with a pointer to the integer value, rather than
+// passing the integer value directly.
+func IoctlSetPointerInt(fd int, req uint, value int) error {
+ v := int32(value)
+ return ioctlPtr(fd, req, unsafe.Pointer(&v))
+}
+
+// IoctlSetWinsize performs an ioctl on fd with a *Winsize argument.
+//
+// To change fd's window size, the req argument should be TIOCSWINSZ.
+func IoctlSetWinsize(fd int, req uint, value *Winsize) error {
+ // TODO: if we get the chance, remove the req parameter and
+ // hardcode TIOCSWINSZ.
+ return ioctlPtr(fd, req, unsafe.Pointer(value))
+}
+
+// IoctlSetTermios performs an ioctl on fd with a *Termios.
+//
+// The req value will usually be TCSETA or TIOCSETA.
+func IoctlSetTermios(fd int, req uint, value *Termios) error {
+ // TODO: if we get the chance, remove the req parameter.
+ return ioctlPtr(fd, req, unsafe.Pointer(value))
+}
+
+// IoctlGetInt performs an ioctl operation which gets an integer value
+// from fd, using the specified request number.
+//
+// A few ioctl requests use the return value as an output parameter;
+// for those, IoctlRetInt should be used instead of this function.
+func IoctlGetInt(fd int, req uint) (int, error) {
+ var value int
+ err := ioctlPtr(fd, req, unsafe.Pointer(&value))
+ return value, err
+}
+
+func IoctlGetWinsize(fd int, req uint) (*Winsize, error) {
+ var value Winsize
+ err := ioctlPtr(fd, req, unsafe.Pointer(&value))
+ return &value, err
+}
+
+func IoctlGetTermios(fd int, req uint) (*Termios, error) {
+ var value Termios
+ err := ioctlPtr(fd, req, unsafe.Pointer(&value))
+ return &value, err
+}
diff --git a/vendor/golang.org/x/sys/unix/ioctl_zos.go b/vendor/golang.org/x/sys/unix/ioctl_zos.go
new file mode 100644
index 0000000..c8b2a75
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/ioctl_zos.go
@@ -0,0 +1,71 @@
+// Copyright 2020 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.
+
+//go:build zos && s390x
+
+package unix
+
+import (
+ "runtime"
+ "unsafe"
+)
+
+// ioctl itself should not be exposed directly, but additional get/set
+// functions for specific types are permissible.
+
+// IoctlSetInt performs an ioctl operation which sets an integer value
+// on fd, using the specified request number.
+func IoctlSetInt(fd int, req int, value int) error {
+ return ioctl(fd, req, uintptr(value))
+}
+
+// IoctlSetWinsize performs an ioctl on fd with a *Winsize argument.
+//
+// To change fd's window size, the req argument should be TIOCSWINSZ.
+func IoctlSetWinsize(fd int, req int, value *Winsize) error {
+ // TODO: if we get the chance, remove the req parameter and
+ // hardcode TIOCSWINSZ.
+ return ioctlPtr(fd, req, unsafe.Pointer(value))
+}
+
+// IoctlSetTermios performs an ioctl on fd with a *Termios.
+//
+// The req value is expected to be TCSETS, TCSETSW, or TCSETSF
+func IoctlSetTermios(fd int, req int, value *Termios) error {
+ if (req != TCSETS) && (req != TCSETSW) && (req != TCSETSF) {
+ return ENOSYS
+ }
+ err := Tcsetattr(fd, int(req), value)
+ runtime.KeepAlive(value)
+ return err
+}
+
+// IoctlGetInt performs an ioctl operation which gets an integer value
+// from fd, using the specified request number.
+//
+// A few ioctl requests use the return value as an output parameter;
+// for those, IoctlRetInt should be used instead of this function.
+func IoctlGetInt(fd int, req int) (int, error) {
+ var value int
+ err := ioctlPtr(fd, req, unsafe.Pointer(&value))
+ return value, err
+}
+
+func IoctlGetWinsize(fd int, req int) (*Winsize, error) {
+ var value Winsize
+ err := ioctlPtr(fd, req, unsafe.Pointer(&value))
+ return &value, err
+}
+
+// IoctlGetTermios performs an ioctl on fd with a *Termios.
+//
+// The req value is expected to be TCGETS
+func IoctlGetTermios(fd int, req int) (*Termios, error) {
+ var value Termios
+ if req != TCGETS {
+ return &value, ENOSYS
+ }
+ err := Tcgetattr(fd, &value)
+ return &value, err
+}
diff --git a/vendor/golang.org/x/sys/unix/mkall.sh b/vendor/golang.org/x/sys/unix/mkall.sh
new file mode 100644
index 0000000..e6f31d3
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/mkall.sh
@@ -0,0 +1,249 @@
+#!/usr/bin/env bash
+# Copyright 2009 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.
+
+# This script runs or (given -n) prints suggested commands to generate files for
+# the Architecture/OS specified by the GOARCH and GOOS environment variables.
+# See README.md for more information about how the build system works.
+
+GOOSARCH="${GOOS}_${GOARCH}"
+
+# defaults
+mksyscall="go run mksyscall.go"
+mkerrors="./mkerrors.sh"
+zerrors="zerrors_$GOOSARCH.go"
+mksysctl=""
+zsysctl="zsysctl_$GOOSARCH.go"
+mksysnum=
+mktypes=
+mkasm=
+run="sh"
+cmd=""
+
+case "$1" in
+-syscalls)
+ for i in zsyscall*go
+ do
+ # Run the command line that appears in the first line
+ # of the generated file to regenerate it.
+ sed 1q $i | sed 's;^// ;;' | sh > _$i && gofmt < _$i > $i
+ rm _$i
+ done
+ exit 0
+ ;;
+-n)
+ run="cat"
+ cmd="echo"
+ shift
+esac
+
+case "$#" in
+0)
+ ;;
+*)
+ echo 'usage: mkall.sh [-n]' 1>&2
+ exit 2
+esac
+
+if [[ "$GOOS" = "linux" ]]; then
+ # Use the Docker-based build system
+ # Files generated through docker (use $cmd so you can Ctl-C the build or run)
+ $cmd docker build --tag generate:$GOOS $GOOS
+ $cmd docker run --interactive --tty --volume $(cd -- "$(dirname -- "$0")/.." && pwd):/build generate:$GOOS
+ exit
+fi
+
+GOOSARCH_in=syscall_$GOOSARCH.go
+case "$GOOSARCH" in
+_* | *_ | _)
+ echo 'undefined $GOOS_$GOARCH:' "$GOOSARCH" 1>&2
+ exit 1
+ ;;
+aix_ppc)
+ mkerrors="$mkerrors -maix32"
+ mksyscall="go run mksyscall_aix_ppc.go -aix"
+ mktypes="GOARCH=$GOARCH go tool cgo -godefs"
+ ;;
+aix_ppc64)
+ mkerrors="$mkerrors -maix64"
+ mksyscall="go run mksyscall_aix_ppc64.go -aix"
+ mktypes="GOARCH=$GOARCH go tool cgo -godefs"
+ ;;
+darwin_amd64)
+ mkerrors="$mkerrors -m64"
+ mktypes="GOARCH=$GOARCH go tool cgo -godefs"
+ mkasm="go run mkasm.go"
+ ;;
+darwin_arm64)
+ mkerrors="$mkerrors -m64"
+ mktypes="GOARCH=$GOARCH go tool cgo -godefs"
+ mkasm="go run mkasm.go"
+ ;;
+dragonfly_amd64)
+ mkerrors="$mkerrors -m64"
+ mksyscall="go run mksyscall.go -dragonfly"
+ mksysnum="go run mksysnum.go 'https://gitweb.dragonflybsd.org/dragonfly.git/blob_plain/HEAD:/sys/kern/syscalls.master'"
+ mktypes="GOARCH=$GOARCH go tool cgo -godefs"
+ ;;
+freebsd_386)
+ mkerrors="$mkerrors -m32"
+ mksyscall="go run mksyscall.go -l32"
+ mksysnum="go run mksysnum.go 'https://cgit.freebsd.org/src/plain/sys/kern/syscalls.master?h=stable/12'"
+ mktypes="GOARCH=$GOARCH go tool cgo -godefs"
+ ;;
+freebsd_amd64)
+ mkerrors="$mkerrors -m64"
+ mksysnum="go run mksysnum.go 'https://cgit.freebsd.org/src/plain/sys/kern/syscalls.master?h=stable/12'"
+ mktypes="GOARCH=$GOARCH go tool cgo -godefs"
+ ;;
+freebsd_arm)
+ mkerrors="$mkerrors"
+ mksyscall="go run mksyscall.go -l32 -arm"
+ mksysnum="go run mksysnum.go 'https://cgit.freebsd.org/src/plain/sys/kern/syscalls.master?h=stable/12'"
+ # Let the type of C char be signed for making the bare syscall
+ # API consistent across platforms.
+ mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char"
+ ;;
+freebsd_arm64)
+ mkerrors="$mkerrors -m64"
+ mksysnum="go run mksysnum.go 'https://cgit.freebsd.org/src/plain/sys/kern/syscalls.master?h=stable/12'"
+ mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char"
+ ;;
+freebsd_riscv64)
+ mkerrors="$mkerrors -m64"
+ mksysnum="go run mksysnum.go 'https://cgit.freebsd.org/src/plain/sys/kern/syscalls.master?h=stable/12'"
+ mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char"
+ ;;
+netbsd_386)
+ mkerrors="$mkerrors -m32"
+ mksyscall="go run mksyscall.go -l32 -netbsd"
+ mksysnum="go run mksysnum.go 'http://cvsweb.netbsd.org/bsdweb.cgi/~checkout~/src/sys/kern/syscalls.master'"
+ mktypes="GOARCH=$GOARCH go tool cgo -godefs"
+ ;;
+netbsd_amd64)
+ mkerrors="$mkerrors -m64"
+ mksyscall="go run mksyscall.go -netbsd"
+ mksysnum="go run mksysnum.go 'http://cvsweb.netbsd.org/bsdweb.cgi/~checkout~/src/sys/kern/syscalls.master'"
+ mktypes="GOARCH=$GOARCH go tool cgo -godefs"
+ ;;
+netbsd_arm)
+ mkerrors="$mkerrors"
+ mksyscall="go run mksyscall.go -l32 -netbsd -arm"
+ mksysnum="go run mksysnum.go 'http://cvsweb.netbsd.org/bsdweb.cgi/~checkout~/src/sys/kern/syscalls.master'"
+ # Let the type of C char be signed for making the bare syscall
+ # API consistent across platforms.
+ mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char"
+ ;;
+netbsd_arm64)
+ mkerrors="$mkerrors -m64"
+ mksyscall="go run mksyscall.go -netbsd"
+ mksysnum="go run mksysnum.go 'http://cvsweb.netbsd.org/bsdweb.cgi/~checkout~/src/sys/kern/syscalls.master'"
+ mktypes="GOARCH=$GOARCH go tool cgo -godefs"
+ ;;
+openbsd_386)
+ mkasm="go run mkasm.go"
+ mkerrors="$mkerrors -m32"
+ mksyscall="go run mksyscall.go -l32 -openbsd -libc"
+ mksysctl="go run mksysctl_openbsd.go"
+ mktypes="GOARCH=$GOARCH go tool cgo -godefs"
+ ;;
+openbsd_amd64)
+ mkasm="go run mkasm.go"
+ mkerrors="$mkerrors -m64"
+ mksyscall="go run mksyscall.go -openbsd -libc"
+ mksysctl="go run mksysctl_openbsd.go"
+ mktypes="GOARCH=$GOARCH go tool cgo -godefs"
+ ;;
+openbsd_arm)
+ mkasm="go run mkasm.go"
+ mkerrors="$mkerrors"
+ mksyscall="go run mksyscall.go -l32 -openbsd -arm -libc"
+ mksysctl="go run mksysctl_openbsd.go"
+ # Let the type of C char be signed for making the bare syscall
+ # API consistent across platforms.
+ mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char"
+ ;;
+openbsd_arm64)
+ mkasm="go run mkasm.go"
+ mkerrors="$mkerrors -m64"
+ mksyscall="go run mksyscall.go -openbsd -libc"
+ mksysctl="go run mksysctl_openbsd.go"
+ # Let the type of C char be signed for making the bare syscall
+ # API consistent across platforms.
+ mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char"
+ ;;
+openbsd_mips64)
+ mkasm="go run mkasm.go"
+ mkerrors="$mkerrors -m64"
+ mksyscall="go run mksyscall.go -openbsd -libc"
+ mksysctl="go run mksysctl_openbsd.go"
+ # Let the type of C char be signed for making the bare syscall
+ # API consistent across platforms.
+ mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char"
+ ;;
+openbsd_ppc64)
+ mkasm="go run mkasm.go"
+ mkerrors="$mkerrors -m64"
+ mksyscall="go run mksyscall.go -openbsd -libc"
+ mksysctl="go run mksysctl_openbsd.go"
+ # Let the type of C char be signed for making the bare syscall
+ # API consistent across platforms.
+ mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char"
+ ;;
+openbsd_riscv64)
+ mkasm="go run mkasm.go"
+ mkerrors="$mkerrors -m64"
+ mksyscall="go run mksyscall.go -openbsd -libc"
+ mksysctl="go run mksysctl_openbsd.go"
+ # Let the type of C char be signed for making the bare syscall
+ # API consistent across platforms.
+ mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char"
+ ;;
+solaris_amd64)
+ mksyscall="go run mksyscall_solaris.go"
+ mkerrors="$mkerrors -m64"
+ mksysnum=
+ mktypes="GOARCH=$GOARCH go tool cgo -godefs"
+ ;;
+illumos_amd64)
+ mksyscall="go run mksyscall_solaris.go"
+ mkerrors=
+ mksysnum=
+ mktypes="GOARCH=$GOARCH go tool cgo -godefs"
+ ;;
+*)
+ echo 'unrecognized $GOOS_$GOARCH: ' "$GOOSARCH" 1>&2
+ exit 1
+ ;;
+esac
+
+(
+ if [ -n "$mkerrors" ]; then echo "$mkerrors |gofmt >$zerrors"; fi
+ case "$GOOS" in
+ *)
+ syscall_goos="syscall_$GOOS.go"
+ case "$GOOS" in
+ darwin | dragonfly | freebsd | netbsd | openbsd)
+ syscall_goos="syscall_bsd.go $syscall_goos"
+ ;;
+ esac
+ if [ -n "$mksyscall" ]; then
+ if [ "$GOOSARCH" == "aix_ppc64" ]; then
+ # aix/ppc64 script generates files instead of writing to stdin.
+ echo "$mksyscall -tags $GOOS,$GOARCH $syscall_goos $GOOSARCH_in && gofmt -w zsyscall_$GOOSARCH.go && gofmt -w zsyscall_"$GOOSARCH"_gccgo.go && gofmt -w zsyscall_"$GOOSARCH"_gc.go " ;
+ elif [ "$GOOS" == "illumos" ]; then
+ # illumos code generation requires a --illumos switch
+ echo "$mksyscall -illumos -tags illumos,$GOARCH syscall_illumos.go |gofmt > zsyscall_illumos_$GOARCH.go";
+ # illumos implies solaris, so solaris code generation is also required
+ echo "$mksyscall -tags solaris,$GOARCH syscall_solaris.go syscall_solaris_$GOARCH.go |gofmt >zsyscall_solaris_$GOARCH.go";
+ else
+ echo "$mksyscall -tags $GOOS,$GOARCH $syscall_goos $GOOSARCH_in |gofmt >zsyscall_$GOOSARCH.go";
+ fi
+ fi
+ esac
+ if [ -n "$mksysctl" ]; then echo "$mksysctl |gofmt >$zsysctl"; fi
+ if [ -n "$mksysnum" ]; then echo "$mksysnum |gofmt >zsysnum_$GOOSARCH.go"; fi
+ if [ -n "$mktypes" ]; then echo "$mktypes types_$GOOS.go | go run mkpost.go > ztypes_$GOOSARCH.go"; fi
+ if [ -n "$mkasm" ]; then echo "$mkasm $GOOS $GOARCH"; fi
+) | $run
diff --git a/vendor/golang.org/x/sys/unix/mkerrors.sh b/vendor/golang.org/x/sys/unix/mkerrors.sh
new file mode 100644
index 0000000..e14b766
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/mkerrors.sh
@@ -0,0 +1,793 @@
+#!/usr/bin/env bash
+# Copyright 2009 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.
+
+# Generate Go code listing errors and other #defined constant
+# values (ENAMETOOLONG etc.), by asking the preprocessor
+# about the definitions.
+
+unset LANG
+export LC_ALL=C
+export LC_CTYPE=C
+
+if test -z "$GOARCH" -o -z "$GOOS"; then
+ echo 1>&2 "GOARCH or GOOS not defined in environment"
+ exit 1
+fi
+
+# Check that we are using the new build system if we should
+if [[ "$GOOS" = "linux" ]] && [[ "$GOLANG_SYS_BUILD" != "docker" ]]; then
+ echo 1>&2 "In the Docker based build system, mkerrors should not be called directly."
+ echo 1>&2 "See README.md"
+ exit 1
+fi
+
+if [[ "$GOOS" = "aix" ]]; then
+ CC=${CC:-gcc}
+else
+ CC=${CC:-cc}
+fi
+
+if [[ "$GOOS" = "solaris" ]]; then
+ # Assumes GNU versions of utilities in PATH.
+ export PATH=/usr/gnu/bin:$PATH
+fi
+
+uname=$(uname)
+
+includes_AIX='
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#define AF_LOCAL AF_UNIX
+'
+
+includes_Darwin='
+#define _DARWIN_C_SOURCE
+#define KERNEL 1
+#define _DARWIN_USE_64_BIT_INODE
+#define __APPLE_USE_RFC_3542
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+// for backwards compatibility because moved TIOCREMOTE to Kernel.framework after MacOSX12.0.sdk.
+#define TIOCREMOTE 0x80047469
+'
+
+includes_DragonFly='
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+'
+
+includes_FreeBSD='
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#if __FreeBSD__ >= 10
+#define IFT_CARP 0xf8 // IFT_CARP is deprecated in FreeBSD 10
+#undef SIOCAIFADDR
+#define SIOCAIFADDR _IOW(105, 26, struct oifaliasreq) // ifaliasreq contains if_data
+#undef SIOCSIFPHYADDR
+#define SIOCSIFPHYADDR _IOW(105, 70, struct oifaliasreq) // ifaliasreq contains if_data
+#endif
+'
+
+includes_Linux='
+#define _LARGEFILE_SOURCE
+#define _LARGEFILE64_SOURCE
+#ifndef __LP64__
+#define _FILE_OFFSET_BITS 64
+#endif
+#define _GNU_SOURCE
+
+// is broken on powerpc64, as it fails to include definitions of
+// these structures. We just include them copied from .
+#if defined(__powerpc__)
+struct sgttyb {
+ char sg_ispeed;
+ char sg_ospeed;
+ char sg_erase;
+ char sg_kill;
+ short sg_flags;
+};
+
+struct tchars {
+ char t_intrc;
+ char t_quitc;
+ char t_startc;
+ char t_stopc;
+ char t_eofc;
+ char t_brkc;
+};
+
+struct ltchars {
+ char t_suspc;
+ char t_dsuspc;
+ char t_rprntc;
+ char t_flushc;
+ char t_werasc;
+ char t_lnextc;
+};
+#endif
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+
+#if defined(__sparc__)
+// On sparc{,64}, the kernel defines struct termios2 itself which clashes with the
+// definition in glibc. As only the error constants are needed here, include the
+// generic termibits.h (which is included by termbits.h on sparc).
+#include
+#else
+#include
+#endif
+
+#ifndef PTRACE_GETREGS
+#define PTRACE_GETREGS 0xc
+#endif
+
+#ifndef PTRACE_SETREGS
+#define PTRACE_SETREGS 0xd
+#endif
+
+#ifdef SOL_BLUETOOTH
+// SPARC includes this in /usr/include/sparc64-linux-gnu/bits/socket.h
+// but it is already in bluetooth_linux.go
+#undef SOL_BLUETOOTH
+#endif
+
+// Certain constants are missing from the fs/crypto UAPI
+#define FS_KEY_DESC_PREFIX "fscrypt:"
+#define FS_KEY_DESC_PREFIX_SIZE 8
+#define FS_MAX_KEY_SIZE 64
+
+// The code generator produces -0x1 for (~0), but an unsigned value is necessary
+// for the tipc_subscr timeout __u32 field.
+#undef TIPC_WAIT_FOREVER
+#define TIPC_WAIT_FOREVER 0xffffffff
+
+// Copied from linux/netfilter/nf_nat.h
+// Including linux/netfilter/nf_nat.h here causes conflicts between linux/in.h
+// and netinet/in.h.
+#define NF_NAT_RANGE_MAP_IPS (1 << 0)
+#define NF_NAT_RANGE_PROTO_SPECIFIED (1 << 1)
+#define NF_NAT_RANGE_PROTO_RANDOM (1 << 2)
+#define NF_NAT_RANGE_PERSISTENT (1 << 3)
+#define NF_NAT_RANGE_PROTO_RANDOM_FULLY (1 << 4)
+#define NF_NAT_RANGE_PROTO_OFFSET (1 << 5)
+#define NF_NAT_RANGE_NETMAP (1 << 6)
+#define NF_NAT_RANGE_PROTO_RANDOM_ALL \
+ (NF_NAT_RANGE_PROTO_RANDOM | NF_NAT_RANGE_PROTO_RANDOM_FULLY)
+#define NF_NAT_RANGE_MASK \
+ (NF_NAT_RANGE_MAP_IPS | NF_NAT_RANGE_PROTO_SPECIFIED | \
+ NF_NAT_RANGE_PROTO_RANDOM | NF_NAT_RANGE_PERSISTENT | \
+ NF_NAT_RANGE_PROTO_RANDOM_FULLY | NF_NAT_RANGE_PROTO_OFFSET | \
+ NF_NAT_RANGE_NETMAP)
+
+// Copied from linux/hid.h.
+// Keep in sync with the size of the referenced fields.
+#define _HIDIOCGRAWNAME_LEN 128 // sizeof_field(struct hid_device, name)
+#define _HIDIOCGRAWPHYS_LEN 64 // sizeof_field(struct hid_device, phys)
+#define _HIDIOCGRAWUNIQ_LEN 64 // sizeof_field(struct hid_device, uniq)
+
+#define _HIDIOCGRAWNAME HIDIOCGRAWNAME(_HIDIOCGRAWNAME_LEN)
+#define _HIDIOCGRAWPHYS HIDIOCGRAWPHYS(_HIDIOCGRAWPHYS_LEN)
+#define _HIDIOCGRAWUNIQ HIDIOCGRAWUNIQ(_HIDIOCGRAWUNIQ_LEN)
+
+'
+
+includes_NetBSD='
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+// Needed since refers to it...
+#define schedppq 1
+'
+
+includes_OpenBSD='
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+// We keep some constants not supported in OpenBSD 5.5 and beyond for
+// the promise of compatibility.
+#define EMUL_ENABLED 0x1
+#define EMUL_NATIVE 0x2
+#define IPV6_FAITH 0x1d
+#define IPV6_OPTIONS 0x1
+#define IPV6_RTHDR_STRICT 0x1
+#define IPV6_SOCKOPT_RESERVED1 0x3
+#define SIOCGIFGENERIC 0xc020693a
+#define SIOCSIFGENERIC 0x80206939
+#define WALTSIG 0x4
+'
+
+includes_SunOS='
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include